blob: 3302a3d1b4bff17fc2a73ed41e7c19c05fad03a8 [file] [log] [blame]
Tiberiu Breana884ca452015-05-18 14:49:50 +03001/**
2 * Sensortek STK8BA50 3-Axis Accelerometer
3 *
4 * Copyright (c) 2015, Intel Corporation.
5 *
6 * This file is subject to the terms and conditions of version 2 of
7 * the GNU General Public License. See the file COPYING in the main
8 * directory of this archive for more details.
9 *
10 * STK8BA50 7-bit I2C address: 0x18.
11 */
12
13#include <linux/acpi.h>
14#include <linux/i2c.h>
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/iio/iio.h>
18#include <linux/iio/sysfs.h>
19
20#define STK8BA50_REG_XOUT 0x02
21#define STK8BA50_REG_YOUT 0x04
22#define STK8BA50_REG_ZOUT 0x06
23#define STK8BA50_REG_RANGE 0x0F
24#define STK8BA50_REG_POWMODE 0x11
25#define STK8BA50_REG_SWRST 0x14
26
27#define STK8BA50_MODE_NORMAL 0
28#define STK8BA50_MODE_SUSPEND 1
29#define STK8BA50_MODE_POWERBIT BIT(7)
30#define STK8BA50_DATA_SHIFT 6
31#define STK8BA50_RESET_CMD 0xB6
32
33#define STK8BA50_DRIVER_NAME "stk8ba50"
34
35#define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069"
36
37/*
38 * The accelerometer has four measurement ranges:
39 * +/-2g; +/-4g; +/-8g; +/-16g
40 *
41 * Acceleration values are 10-bit, 2's complement.
42 * Scales are calculated as following:
43 *
44 * scale1 = (2 + 2) * 9.81 / (2^10 - 1) = 0.0384
45 * scale2 = (4 + 4) * 9.81 / (2^10 - 1) = 0.0767
46 * etc.
47 *
48 * Scales are stored in this format:
49 * { <register value>, <scale value> }
50 *
51 * Locally, the range is stored as a table index.
52 */
Tiberiu Breana003f4882015-06-10 18:07:29 +030053static const struct {
54 u8 reg_val;
55 u32 scale_val;
56} stk8ba50_scale_table[] = {
Tiberiu Breana884ca452015-05-18 14:49:50 +030057 {3, 38400}, {5, 76700}, {8, 153400}, {12, 306900}
58};
59
60struct stk8ba50_data {
61 struct i2c_client *client;
62 struct mutex lock;
63 int range;
64};
65
66#define STK8BA50_ACCEL_CHANNEL(reg, axis) { \
67 .type = IIO_ACCEL, \
68 .address = reg, \
69 .modified = 1, \
70 .channel2 = IIO_MOD_##axis, \
71 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
72 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
73}
74
75static const struct iio_chan_spec stk8ba50_channels[] = {
76 STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_XOUT, X),
77 STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_YOUT, Y),
78 STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_ZOUT, Z),
79};
80
81static IIO_CONST_ATTR(in_accel_scale_available, STK8BA50_SCALE_AVAIL);
82
83static struct attribute *stk8ba50_attributes[] = {
84 &iio_const_attr_in_accel_scale_available.dev_attr.attr,
85 NULL,
86};
87
88static const struct attribute_group stk8ba50_attribute_group = {
89 .attrs = stk8ba50_attributes
90};
91
92static int stk8ba50_read_accel(struct stk8ba50_data *data, u8 reg)
93{
94 int ret;
95 struct i2c_client *client = data->client;
96
97 ret = i2c_smbus_read_word_data(client, reg);
98 if (ret < 0) {
99 dev_err(&client->dev, "register read failed\n");
100 return ret;
101 }
102
103 return sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9);
104}
105
106static int stk8ba50_read_raw(struct iio_dev *indio_dev,
107 struct iio_chan_spec const *chan,
108 int *val, int *val2, long mask)
109{
110 struct stk8ba50_data *data = iio_priv(indio_dev);
111
112 switch (mask) {
113 case IIO_CHAN_INFO_RAW:
114 mutex_lock(&data->lock);
115 *val = stk8ba50_read_accel(data, chan->address);
116 mutex_unlock(&data->lock);
117 return IIO_VAL_INT;
118 case IIO_CHAN_INFO_SCALE:
119 *val = 0;
Tiberiu Breana003f4882015-06-10 18:07:29 +0300120 *val2 = stk8ba50_scale_table[data->range].scale_val;
Tiberiu Breana884ca452015-05-18 14:49:50 +0300121 return IIO_VAL_INT_PLUS_MICRO;
122 }
123
124 return -EINVAL;
125}
126
127static int stk8ba50_write_raw(struct iio_dev *indio_dev,
128 struct iio_chan_spec const *chan,
129 int val, int val2, long mask)
130{
131 int ret;
132 int i;
133 int index = -1;
134 struct stk8ba50_data *data = iio_priv(indio_dev);
135
136 switch (mask) {
137 case IIO_CHAN_INFO_SCALE:
138 if (val != 0)
139 return -EINVAL;
140
141 for (i = 0; i < ARRAY_SIZE(stk8ba50_scale_table); i++)
Tiberiu Breana003f4882015-06-10 18:07:29 +0300142 if (val2 == stk8ba50_scale_table[i].scale_val) {
Tiberiu Breana884ca452015-05-18 14:49:50 +0300143 index = i;
144 break;
145 }
146 if (index < 0)
147 return -EINVAL;
148
149 ret = i2c_smbus_write_byte_data(data->client,
150 STK8BA50_REG_RANGE,
Tiberiu Breana003f4882015-06-10 18:07:29 +0300151 stk8ba50_scale_table[index].reg_val);
Tiberiu Breana884ca452015-05-18 14:49:50 +0300152 if (ret < 0)
153 dev_err(&data->client->dev,
154 "failed to set measurement range\n");
155 else
156 data->range = index;
157
158 return ret;
159 }
160
161 return -EINVAL;
162}
163
164static const struct iio_info stk8ba50_info = {
165 .driver_module = THIS_MODULE,
166 .read_raw = stk8ba50_read_raw,
167 .write_raw = stk8ba50_write_raw,
168 .attrs = &stk8ba50_attribute_group,
169};
170
171static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode)
172{
173 int ret;
174 u8 masked_reg;
175 struct i2c_client *client = data->client;
176
177 ret = i2c_smbus_read_byte_data(client, STK8BA50_REG_POWMODE);
178 if (ret < 0)
179 goto exit_err;
180
181 if (mode)
182 masked_reg = ret | STK8BA50_MODE_POWERBIT;
183 else
184 masked_reg = ret & (~STK8BA50_MODE_POWERBIT);
185
186 ret = i2c_smbus_write_byte_data(client, STK8BA50_REG_POWMODE,
187 masked_reg);
188 if (ret < 0)
189 goto exit_err;
190
191 return ret;
192
193exit_err:
194 dev_err(&client->dev, "failed to change sensor mode\n");
195 return ret;
196}
197
198static int stk8ba50_probe(struct i2c_client *client,
199 const struct i2c_device_id *id)
200{
201 int ret;
202 struct iio_dev *indio_dev;
203 struct stk8ba50_data *data;
204
205 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
206 if (!indio_dev) {
207 dev_err(&client->dev, "iio allocation failed!\n");
208 return -ENOMEM;
209 }
210
211 data = iio_priv(indio_dev);
212 data->client = client;
213 i2c_set_clientdata(client, indio_dev);
214 mutex_init(&data->lock);
215
216 indio_dev->dev.parent = &client->dev;
217 indio_dev->info = &stk8ba50_info;
218 indio_dev->name = STK8BA50_DRIVER_NAME;
219 indio_dev->modes = INDIO_DIRECT_MODE;
220 indio_dev->channels = stk8ba50_channels;
221 indio_dev->num_channels = ARRAY_SIZE(stk8ba50_channels);
222
223 /* Reset all registers on startup */
224 ret = i2c_smbus_write_byte_data(client,
225 STK8BA50_REG_SWRST, STK8BA50_RESET_CMD);
226 if (ret < 0) {
227 dev_err(&client->dev, "failed to reset sensor\n");
228 return ret;
229 }
230
231 /* The default range is +/-2g */
232 data->range = 0;
233
234 ret = iio_device_register(indio_dev);
235 if (ret < 0) {
236 dev_err(&client->dev, "device_register failed\n");
237 stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
238 }
239
240 return ret;
241}
242
243static int stk8ba50_remove(struct i2c_client *client)
244{
245 struct iio_dev *indio_dev = i2c_get_clientdata(client);
246
247 iio_device_unregister(indio_dev);
248
249 return stk8ba50_set_power(iio_priv(indio_dev), STK8BA50_MODE_SUSPEND);
250}
251
252#ifdef CONFIG_PM_SLEEP
253static int stk8ba50_suspend(struct device *dev)
254{
255 struct stk8ba50_data *data;
256
257 data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
258
259 return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
260}
261
262static int stk8ba50_resume(struct device *dev)
263{
264 struct stk8ba50_data *data;
265
266 data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
267
268 return stk8ba50_set_power(data, STK8BA50_MODE_NORMAL);
269}
270
271static SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume);
272
273#define STK8BA50_PM_OPS (&stk8ba50_pm_ops)
274#else
275#define STK8BA50_PM_OPS NULL
276#endif
277
278static const struct i2c_device_id stk8ba50_i2c_id[] = {
279 {"stk8ba50", 0},
280 {}
281};
282
283static const struct acpi_device_id stk8ba50_acpi_id[] = {
284 {"STK8BA50", 0},
285 {}
286};
287
288MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id);
289
290static struct i2c_driver stk8ba50_driver = {
291 .driver = {
292 .name = "stk8ba50",
293 .pm = STK8BA50_PM_OPS,
294 .acpi_match_table = ACPI_PTR(stk8ba50_acpi_id),
295 },
296 .probe = stk8ba50_probe,
297 .remove = stk8ba50_remove,
298 .id_table = stk8ba50_i2c_id,
299};
300
301module_i2c_driver(stk8ba50_driver);
302
303MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
304MODULE_DESCRIPTION("STK8BA50 3-Axis Accelerometer driver");
305MODULE_LICENSE("GPL v2");