diff options
-rw-r--r-- | drivers/iio/imu/Kconfig | 9 | ||||
-rw-r--r-- | drivers/iio/imu/Makefile | 2 | ||||
-rw-r--r-- | drivers/iio/imu/kmx61.c | 691 |
3 files changed, 702 insertions, 0 deletions
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 2b0e45133e9d..db4221db10f2 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig | |||
@@ -25,6 +25,15 @@ config ADIS16480 | |||
25 | Say yes here to build support for Analog Devices ADIS16375, ADIS16480, | 25 | Say yes here to build support for Analog Devices ADIS16375, ADIS16480, |
26 | ADIS16485, ADIS16488 inertial sensors. | 26 | ADIS16485, ADIS16488 inertial sensors. |
27 | 27 | ||
28 | config KMX61 | ||
29 | tristate "Kionix KMX61 6-axis accelerometer and magnetometer" | ||
30 | depends on I2C | ||
31 | help | ||
32 | Say Y here if you want to build a driver for Kionix KMX61 6-axis | ||
33 | accelerometer and magnetometer. | ||
34 | To compile this driver as module, choose M here: the module will | ||
35 | be called kmx61. | ||
36 | |||
28 | source "drivers/iio/imu/inv_mpu6050/Kconfig" | 37 | source "drivers/iio/imu/inv_mpu6050/Kconfig" |
29 | 38 | ||
30 | endmenu | 39 | endmenu |
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 114d2c17cbe2..e1e6e3d70e26 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile | |||
@@ -14,3 +14,5 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o | |||
14 | obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o | 14 | obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o |
15 | 15 | ||
16 | obj-y += inv_mpu6050/ | 16 | obj-y += inv_mpu6050/ |
17 | |||
18 | obj-$(CONFIG_KMX61) += kmx61.o | ||
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c new file mode 100644 index 000000000000..5231d8f3b167 --- /dev/null +++ b/drivers/iio/imu/kmx61.c | |||
@@ -0,0 +1,691 @@ | |||
1 | /* | ||
2 | * KMX61 - Kionix 6-axis Accelerometer/Magnetometer | ||
3 | * | ||
4 | * Copyright (c) 2014, 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 | * IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F). | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/iio/iio.h> | ||
17 | #include <linux/iio/sysfs.h> | ||
18 | |||
19 | #define KMX61_DRV_NAME "kmx61" | ||
20 | |||
21 | #define KMX61_REG_WHO_AM_I 0x00 | ||
22 | |||
23 | /* | ||
24 | * three 16-bit accelerometer output registers for X/Y/Z axis | ||
25 | * we use only XOUT_L as a base register, all other addresses | ||
26 | * can be obtained by applying an offset and are provided here | ||
27 | * only for clarity. | ||
28 | */ | ||
29 | #define KMX61_ACC_XOUT_L 0x0A | ||
30 | #define KMX61_ACC_XOUT_H 0x0B | ||
31 | #define KMX61_ACC_YOUT_L 0x0C | ||
32 | #define KMX61_ACC_YOUT_H 0x0D | ||
33 | #define KMX61_ACC_ZOUT_L 0x0E | ||
34 | #define KMX61_ACC_ZOUT_H 0x0F | ||
35 | |||
36 | /* | ||
37 | * one 16-bit temperature output register | ||
38 | */ | ||
39 | #define KMX61_TEMP_L 0x10 | ||
40 | #define KMX61_TEMP_H 0x11 | ||
41 | |||
42 | /* | ||
43 | * three 16-bit magnetometer output registers for X/Y/Z axis | ||
44 | */ | ||
45 | #define KMX61_MAG_XOUT_L 0x12 | ||
46 | #define KMX61_MAG_XOUT_H 0x13 | ||
47 | #define KMX61_MAG_YOUT_L 0x14 | ||
48 | #define KMX61_MAG_YOUT_H 0x15 | ||
49 | #define KMX61_MAG_ZOUT_L 0x16 | ||
50 | #define KMX61_MAG_ZOUT_H 0x17 | ||
51 | |||
52 | #define KMX61_REG_STBY 0x29 | ||
53 | #define KMX61_REG_CTRL1 0x2A | ||
54 | #define KMX61_REG_ODCNTL 0x2C | ||
55 | |||
56 | #define KMX61_ACC_STBY_BIT BIT(0) | ||
57 | #define KMX61_MAG_STBY_BIT BIT(1) | ||
58 | #define KMX61_ACT_STBY_BIT BIT(7) | ||
59 | |||
60 | #define KMX61_ALL_STBY (KMX61_ACC_STBY_BIT | KMX61_MAG_STBY_BIT) | ||
61 | |||
62 | #define KMX61_REG_CTRL1_GSEL_MASK 0x03 | ||
63 | |||
64 | #define KMX61_ACC_ODR_SHIFT 0 | ||
65 | #define KMX61_MAG_ODR_SHIFT 4 | ||
66 | #define KMX61_ACC_ODR_MASK 0x0F | ||
67 | #define KMX61_MAG_ODR_MASK 0xF0 | ||
68 | |||
69 | #define KMX61_CHIP_ID 0x12 | ||
70 | |||
71 | /* KMX61 devices */ | ||
72 | #define KMX61_ACC 0x01 | ||
73 | #define KMX61_MAG 0x02 | ||
74 | |||
75 | struct kmx61_data { | ||
76 | struct i2c_client *client; | ||
77 | |||
78 | /* serialize access to non-atomic ops, e.g set_mode */ | ||
79 | struct mutex lock; | ||
80 | |||
81 | /* standby state */ | ||
82 | bool acc_stby; | ||
83 | bool mag_stby; | ||
84 | |||
85 | /* config bits */ | ||
86 | u8 range; | ||
87 | u8 odr_bits; | ||
88 | |||
89 | /* accelerometer specific data */ | ||
90 | struct iio_dev *acc_indio_dev; | ||
91 | |||
92 | /* magnetometer specific data */ | ||
93 | struct iio_dev *mag_indio_dev; | ||
94 | }; | ||
95 | |||
96 | enum kmx61_range { | ||
97 | KMX61_RANGE_2G, | ||
98 | KMX61_RANGE_4G, | ||
99 | KMX61_RANGE_8G, | ||
100 | }; | ||
101 | |||
102 | enum kmx61_axis { | ||
103 | KMX61_AXIS_X, | ||
104 | KMX61_AXIS_Y, | ||
105 | KMX61_AXIS_Z, | ||
106 | }; | ||
107 | |||
108 | static const u16 kmx61_uscale_table[] = {9582, 19163, 38326}; | ||
109 | |||
110 | static const struct { | ||
111 | int val; | ||
112 | int val2; | ||
113 | u8 odr_bits; | ||
114 | } kmx61_samp_freq_table[] = { {12, 500000, 0x00}, | ||
115 | {25, 0, 0x01}, | ||
116 | {50, 0, 0x02}, | ||
117 | {100, 0, 0x03}, | ||
118 | {200, 0, 0x04}, | ||
119 | {400, 0, 0x05}, | ||
120 | {800, 0, 0x06}, | ||
121 | {1600, 0, 0x07}, | ||
122 | {0, 781000, 0x08}, | ||
123 | {1, 563000, 0x09}, | ||
124 | {3, 125000, 0x0A}, | ||
125 | {6, 250000, 0x0B} }; | ||
126 | |||
127 | static IIO_CONST_ATTR(accel_scale_available, "0.009582 0.019163 0.038326"); | ||
128 | static IIO_CONST_ATTR(magn_scale_available, "0.001465"); | ||
129 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( | ||
130 | "0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800"); | ||
131 | |||
132 | static struct attribute *kmx61_acc_attributes[] = { | ||
133 | &iio_const_attr_accel_scale_available.dev_attr.attr, | ||
134 | &iio_const_attr_sampling_frequency_available.dev_attr.attr, | ||
135 | NULL, | ||
136 | }; | ||
137 | |||
138 | static struct attribute *kmx61_mag_attributes[] = { | ||
139 | &iio_const_attr_magn_scale_available.dev_attr.attr, | ||
140 | &iio_const_attr_sampling_frequency_available.dev_attr.attr, | ||
141 | NULL, | ||
142 | }; | ||
143 | |||
144 | static const struct attribute_group kmx61_acc_attribute_group = { | ||
145 | .attrs = kmx61_acc_attributes, | ||
146 | }; | ||
147 | |||
148 | static const struct attribute_group kmx61_mag_attribute_group = { | ||
149 | .attrs = kmx61_mag_attributes, | ||
150 | }; | ||
151 | |||
152 | #define KMX61_ACC_CHAN(_axis) { \ | ||
153 | .type = IIO_ACCEL, \ | ||
154 | .modified = 1, \ | ||
155 | .channel2 = IIO_MOD_ ## _axis, \ | ||
156 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
157 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | ||
158 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
159 | .address = KMX61_ACC, \ | ||
160 | .scan_index = KMX61_AXIS_ ## _axis, \ | ||
161 | .scan_type = { \ | ||
162 | .sign = 's', \ | ||
163 | .realbits = 12, \ | ||
164 | .storagebits = 16, \ | ||
165 | .shift = 4, \ | ||
166 | .endianness = IIO_LE, \ | ||
167 | }, \ | ||
168 | } | ||
169 | |||
170 | #define KMX61_MAG_CHAN(_axis) { \ | ||
171 | .type = IIO_MAGN, \ | ||
172 | .modified = 1, \ | ||
173 | .channel2 = IIO_MOD_ ## _axis, \ | ||
174 | .address = KMX61_MAG, \ | ||
175 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
176 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | ||
177 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | ||
178 | .scan_index = KMX61_AXIS_ ## _axis, \ | ||
179 | .scan_type = { \ | ||
180 | .sign = 's', \ | ||
181 | .realbits = 14, \ | ||
182 | .storagebits = 16, \ | ||
183 | .shift = 2, \ | ||
184 | .endianness = IIO_LE, \ | ||
185 | }, \ | ||
186 | } | ||
187 | |||
188 | static const struct iio_chan_spec kmx61_acc_channels[] = { | ||
189 | KMX61_ACC_CHAN(X), | ||
190 | KMX61_ACC_CHAN(Y), | ||
191 | KMX61_ACC_CHAN(Z), | ||
192 | }; | ||
193 | |||
194 | static const struct iio_chan_spec kmx61_mag_channels[] = { | ||
195 | KMX61_MAG_CHAN(X), | ||
196 | KMX61_MAG_CHAN(Y), | ||
197 | KMX61_MAG_CHAN(Z), | ||
198 | }; | ||
199 | |||
200 | static void kmx61_set_data(struct iio_dev *indio_dev, struct kmx61_data *data) | ||
201 | { | ||
202 | struct kmx61_data **priv = iio_priv(indio_dev); | ||
203 | |||
204 | *priv = data; | ||
205 | } | ||
206 | |||
207 | static struct kmx61_data *kmx61_get_data(struct iio_dev *indio_dev) | ||
208 | { | ||
209 | return *(struct kmx61_data **)iio_priv(indio_dev); | ||
210 | } | ||
211 | |||
212 | static int kmx61_convert_freq_to_bit(int val, int val2) | ||
213 | { | ||
214 | int i; | ||
215 | |||
216 | for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++) | ||
217 | if (val == kmx61_samp_freq_table[i].val && | ||
218 | val2 == kmx61_samp_freq_table[i].val2) | ||
219 | return kmx61_samp_freq_table[i].odr_bits; | ||
220 | return -EINVAL; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * kmx61_set_mode() - set KMX61 device operating mode | ||
225 | * @data - kmx61 device private data pointer | ||
226 | * @mode - bitmask, indicating operating mode for @device | ||
227 | * @device - bitmask, indicating device for which @mode needs to be set | ||
228 | * @update - update stby bits stored in device's private @data | ||
229 | * | ||
230 | * For each sensor (accelerometer/magnetometer) there are two operating modes | ||
231 | * STANDBY and OPERATION. Neither accel nor magn can be disabled independently | ||
232 | * if they are both enabled. Internal sensors state is saved in acc_stby and | ||
233 | * mag_stby members of driver's private @data. | ||
234 | */ | ||
235 | static int kmx61_set_mode(struct kmx61_data *data, u8 mode, u8 device, | ||
236 | bool update) | ||
237 | { | ||
238 | int ret; | ||
239 | int acc_stby = -1, mag_stby = -1; | ||
240 | |||
241 | ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY); | ||
242 | if (ret < 0) { | ||
243 | dev_err(&data->client->dev, "Error reading reg_stby\n"); | ||
244 | return ret; | ||
245 | } | ||
246 | if (device & KMX61_ACC) { | ||
247 | if (mode & KMX61_ACC_STBY_BIT) { | ||
248 | ret |= KMX61_ACC_STBY_BIT; | ||
249 | acc_stby = 1; | ||
250 | } else { | ||
251 | ret &= ~KMX61_ACC_STBY_BIT; | ||
252 | acc_stby = 0; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | if (device & KMX61_MAG) { | ||
257 | if (mode & KMX61_MAG_STBY_BIT) { | ||
258 | ret |= KMX61_MAG_STBY_BIT; | ||
259 | mag_stby = 1; | ||
260 | } else { | ||
261 | ret &= ~KMX61_MAG_STBY_BIT; | ||
262 | mag_stby = 0; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | if (mode & KMX61_ACT_STBY_BIT) | ||
267 | ret |= KMX61_ACT_STBY_BIT; | ||
268 | |||
269 | ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_STBY, ret); | ||
270 | if (ret < 0) { | ||
271 | dev_err(&data->client->dev, "Error writing reg_stby\n"); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | if (acc_stby != -1 && update) | ||
276 | data->acc_stby = acc_stby; | ||
277 | if (mag_stby != -1 && update) | ||
278 | data->mag_stby = mag_stby; | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int kmx61_get_mode(struct kmx61_data *data, u8 *mode, u8 device) | ||
284 | { | ||
285 | int ret; | ||
286 | |||
287 | ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY); | ||
288 | if (ret < 0) { | ||
289 | dev_err(&data->client->dev, "Error reading reg_stby\n"); | ||
290 | return ret; | ||
291 | } | ||
292 | *mode = 0; | ||
293 | |||
294 | if (device & KMX61_ACC) { | ||
295 | if (ret & KMX61_ACC_STBY_BIT) | ||
296 | *mode |= KMX61_ACC_STBY_BIT; | ||
297 | else | ||
298 | *mode &= ~KMX61_ACC_STBY_BIT; | ||
299 | } | ||
300 | |||
301 | if (device & KMX61_MAG) { | ||
302 | if (ret & KMX61_MAG_STBY_BIT) | ||
303 | *mode |= KMX61_MAG_STBY_BIT; | ||
304 | else | ||
305 | *mode &= ~KMX61_MAG_STBY_BIT; | ||
306 | } | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static int kmx61_set_odr(struct kmx61_data *data, int val, int val2, u8 device) | ||
312 | { | ||
313 | int ret; | ||
314 | u8 mode; | ||
315 | int lodr_bits, odr_bits; | ||
316 | |||
317 | ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG); | ||
318 | if (ret < 0) | ||
319 | return ret; | ||
320 | |||
321 | lodr_bits = kmx61_convert_freq_to_bit(val, val2); | ||
322 | if (lodr_bits < 0) | ||
323 | return lodr_bits; | ||
324 | |||
325 | /* To change ODR, accel and magn must be in STDBY */ | ||
326 | ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, | ||
327 | true); | ||
328 | if (ret < 0) | ||
329 | return ret; | ||
330 | |||
331 | odr_bits = 0; | ||
332 | if (device & KMX61_ACC) | ||
333 | odr_bits |= lodr_bits << KMX61_ACC_ODR_SHIFT; | ||
334 | if (device & KMX61_MAG) | ||
335 | odr_bits |= lodr_bits << KMX61_MAG_ODR_SHIFT; | ||
336 | |||
337 | ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_ODCNTL, | ||
338 | odr_bits); | ||
339 | if (ret < 0) | ||
340 | return ret; | ||
341 | |||
342 | return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true); | ||
343 | } | ||
344 | |||
345 | static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2, | ||
346 | u8 device) | ||
347 | { int i; | ||
348 | u8 lodr_bits; | ||
349 | |||
350 | if (device & KMX61_ACC) | ||
351 | lodr_bits = (data->odr_bits >> KMX61_ACC_ODR_SHIFT) & | ||
352 | KMX61_ACC_ODR_MASK; | ||
353 | else if (device & KMX61_MAG) | ||
354 | lodr_bits = (data->odr_bits >> KMX61_MAG_ODR_SHIFT) & | ||
355 | KMX61_MAG_ODR_MASK; | ||
356 | else | ||
357 | return -EINVAL; | ||
358 | |||
359 | for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++) | ||
360 | if (lodr_bits == kmx61_samp_freq_table[i].odr_bits) { | ||
361 | *val = kmx61_samp_freq_table[i].val; | ||
362 | *val2 = kmx61_samp_freq_table[i].val2; | ||
363 | return 0; | ||
364 | } | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | |||
368 | static int kmx61_set_range(struct kmx61_data *data, u8 range) | ||
369 | { | ||
370 | int ret; | ||
371 | |||
372 | ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1); | ||
373 | if (ret < 0) { | ||
374 | dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | ret &= ~KMX61_REG_CTRL1_GSEL_MASK; | ||
379 | ret |= range & KMX61_REG_CTRL1_GSEL_MASK; | ||
380 | |||
381 | ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret); | ||
382 | if (ret < 0) { | ||
383 | dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); | ||
384 | return ret; | ||
385 | } | ||
386 | |||
387 | data->range = range; | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | static int kmx61_set_scale(struct kmx61_data *data, u16 uscale) | ||
393 | { | ||
394 | int ret, i; | ||
395 | u8 mode; | ||
396 | |||
397 | for (i = 0; i < ARRAY_SIZE(kmx61_uscale_table); i++) { | ||
398 | if (kmx61_uscale_table[i] == uscale) { | ||
399 | ret = kmx61_get_mode(data, &mode, | ||
400 | KMX61_ACC | KMX61_MAG); | ||
401 | if (ret < 0) | ||
402 | return ret; | ||
403 | |||
404 | ret = kmx61_set_mode(data, KMX61_ALL_STBY, | ||
405 | KMX61_ACC | KMX61_MAG, true); | ||
406 | if (ret < 0) | ||
407 | return ret; | ||
408 | |||
409 | ret = kmx61_set_range(data, i); | ||
410 | if (ret < 0) | ||
411 | return ret; | ||
412 | |||
413 | return kmx61_set_mode(data, mode, | ||
414 | KMX61_ACC | KMX61_MAG, true); | ||
415 | } | ||
416 | } | ||
417 | return -EINVAL; | ||
418 | } | ||
419 | |||
420 | static int kmx61_chip_init(struct kmx61_data *data) | ||
421 | { | ||
422 | int ret; | ||
423 | |||
424 | ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_WHO_AM_I); | ||
425 | if (ret < 0) { | ||
426 | dev_err(&data->client->dev, "Error reading who_am_i\n"); | ||
427 | return ret; | ||
428 | } | ||
429 | |||
430 | if (ret != KMX61_CHIP_ID) { | ||
431 | dev_err(&data->client->dev, | ||
432 | "Wrong chip id, got %x expected %x\n", | ||
433 | ret, KMX61_CHIP_ID); | ||
434 | return -EINVAL; | ||
435 | } | ||
436 | |||
437 | /* set accel 12bit, 4g range */ | ||
438 | ret = kmx61_set_range(data, KMX61_RANGE_4G); | ||
439 | if (ret < 0) | ||
440 | return ret; | ||
441 | |||
442 | ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_ODCNTL); | ||
443 | if (ret < 0) { | ||
444 | dev_err(&data->client->dev, "Error reading reg_odcntl\n"); | ||
445 | return ret; | ||
446 | } | ||
447 | data->odr_bits = ret; | ||
448 | |||
449 | /* set acc/magn to OPERATION mode */ | ||
450 | ret = kmx61_set_mode(data, 0, KMX61_ACC | KMX61_MAG, true); | ||
451 | if (ret < 0) | ||
452 | return ret; | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static int kmx61_read_measurement(struct kmx61_data *data, u8 base, u8 offset) | ||
458 | { | ||
459 | int ret; | ||
460 | u8 reg = base + offset * 2; | ||
461 | |||
462 | ret = i2c_smbus_read_word_data(data->client, reg); | ||
463 | if (ret < 0) | ||
464 | dev_err(&data->client->dev, "failed to read reg at %x\n", reg); | ||
465 | |||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | static int kmx61_read_raw(struct iio_dev *indio_dev, | ||
470 | struct iio_chan_spec const *chan, int *val, | ||
471 | int *val2, long mask) | ||
472 | { | ||
473 | int ret; | ||
474 | u8 base_reg; | ||
475 | struct kmx61_data *data = kmx61_get_data(indio_dev); | ||
476 | |||
477 | switch (mask) { | ||
478 | case IIO_CHAN_INFO_RAW: | ||
479 | switch (chan->type) { | ||
480 | case IIO_ACCEL: | ||
481 | base_reg = KMX61_ACC_XOUT_L; | ||
482 | break; | ||
483 | case IIO_MAGN: | ||
484 | base_reg = KMX61_MAG_XOUT_L; | ||
485 | break; | ||
486 | default: | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | mutex_lock(&data->lock); | ||
490 | |||
491 | ret = kmx61_read_measurement(data, base_reg, chan->scan_index); | ||
492 | if (ret < 0) { | ||
493 | mutex_unlock(&data->lock); | ||
494 | return ret; | ||
495 | } | ||
496 | *val = sign_extend32(ret >> chan->scan_type.shift, | ||
497 | chan->scan_type.realbits - 1); | ||
498 | |||
499 | mutex_unlock(&data->lock); | ||
500 | return IIO_VAL_INT; | ||
501 | case IIO_CHAN_INFO_SCALE: | ||
502 | switch (chan->type) { | ||
503 | case IIO_ACCEL: | ||
504 | *val = 0; | ||
505 | *val2 = kmx61_uscale_table[data->range]; | ||
506 | return IIO_VAL_INT_PLUS_MICRO; | ||
507 | case IIO_MAGN: | ||
508 | /* 14 bits res, 1465 microGauss per magn count */ | ||
509 | *val = 0; | ||
510 | *val2 = 1465; | ||
511 | return IIO_VAL_INT_PLUS_MICRO; | ||
512 | default: | ||
513 | return -EINVAL; | ||
514 | } | ||
515 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
516 | if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN) | ||
517 | return -EINVAL; | ||
518 | |||
519 | mutex_lock(&data->lock); | ||
520 | ret = kmx61_get_odr(data, val, val2, chan->address); | ||
521 | mutex_unlock(&data->lock); | ||
522 | if (ret) | ||
523 | return -EINVAL; | ||
524 | return IIO_VAL_INT_PLUS_MICRO; | ||
525 | } | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | static int kmx61_write_raw(struct iio_dev *indio_dev, | ||
530 | struct iio_chan_spec const *chan, int val, | ||
531 | int val2, long mask) | ||
532 | { | ||
533 | int ret; | ||
534 | struct kmx61_data *data = kmx61_get_data(indio_dev); | ||
535 | |||
536 | switch (mask) { | ||
537 | case IIO_CHAN_INFO_SAMP_FREQ: | ||
538 | if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN) | ||
539 | return -EINVAL; | ||
540 | |||
541 | mutex_lock(&data->lock); | ||
542 | ret = kmx61_set_odr(data, val, val2, chan->address); | ||
543 | mutex_unlock(&data->lock); | ||
544 | return ret; | ||
545 | case IIO_CHAN_INFO_SCALE: | ||
546 | switch (chan->type) { | ||
547 | case IIO_ACCEL: | ||
548 | if (val != 0) | ||
549 | return -EINVAL; | ||
550 | mutex_lock(&data->lock); | ||
551 | ret = kmx61_set_scale(data, val2); | ||
552 | mutex_unlock(&data->lock); | ||
553 | return ret; | ||
554 | default: | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | default: | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | } | ||
561 | |||
562 | static const struct iio_info kmx61_acc_info = { | ||
563 | .driver_module = THIS_MODULE, | ||
564 | .read_raw = kmx61_read_raw, | ||
565 | .write_raw = kmx61_write_raw, | ||
566 | .attrs = &kmx61_acc_attribute_group, | ||
567 | }; | ||
568 | |||
569 | static const struct iio_info kmx61_mag_info = { | ||
570 | .driver_module = THIS_MODULE, | ||
571 | .read_raw = kmx61_read_raw, | ||
572 | .write_raw = kmx61_write_raw, | ||
573 | .attrs = &kmx61_mag_attribute_group, | ||
574 | }; | ||
575 | |||
576 | static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data, | ||
577 | const struct iio_info *info, | ||
578 | const struct iio_chan_spec *chan, | ||
579 | int num_channels, | ||
580 | const char *name) | ||
581 | { | ||
582 | struct iio_dev *indio_dev; | ||
583 | |||
584 | indio_dev = devm_iio_device_alloc(&data->client->dev, sizeof(data)); | ||
585 | if (!indio_dev) | ||
586 | return ERR_PTR(-ENOMEM); | ||
587 | |||
588 | kmx61_set_data(indio_dev, data); | ||
589 | |||
590 | indio_dev->dev.parent = &data->client->dev; | ||
591 | indio_dev->channels = chan; | ||
592 | indio_dev->num_channels = num_channels; | ||
593 | indio_dev->name = name; | ||
594 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
595 | indio_dev->info = info; | ||
596 | |||
597 | return indio_dev; | ||
598 | } | ||
599 | |||
600 | static int kmx61_probe(struct i2c_client *client, | ||
601 | const struct i2c_device_id *id) | ||
602 | { | ||
603 | int ret; | ||
604 | struct kmx61_data *data; | ||
605 | const char *name = NULL; | ||
606 | |||
607 | data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); | ||
608 | if (!data) | ||
609 | return -ENOMEM; | ||
610 | |||
611 | i2c_set_clientdata(client, data); | ||
612 | data->client = client; | ||
613 | |||
614 | mutex_init(&data->lock); | ||
615 | |||
616 | data->acc_indio_dev = | ||
617 | kmx61_indiodev_setup(data, &kmx61_acc_info, | ||
618 | kmx61_acc_channels, | ||
619 | ARRAY_SIZE(kmx61_acc_channels), | ||
620 | name); | ||
621 | if (IS_ERR(data->acc_indio_dev)) | ||
622 | return PTR_ERR(data->acc_indio_dev); | ||
623 | |||
624 | data->mag_indio_dev = | ||
625 | kmx61_indiodev_setup(data, &kmx61_mag_info, | ||
626 | kmx61_mag_channels, | ||
627 | ARRAY_SIZE(kmx61_mag_channels), | ||
628 | name); | ||
629 | if (IS_ERR(data->mag_indio_dev)) | ||
630 | return PTR_ERR(data->mag_indio_dev); | ||
631 | |||
632 | ret = kmx61_chip_init(data); | ||
633 | if (ret < 0) | ||
634 | return ret; | ||
635 | |||
636 | ret = iio_device_register(data->acc_indio_dev); | ||
637 | if (ret < 0) { | ||
638 | dev_err(&client->dev, "Failed to register acc iio device\n"); | ||
639 | goto err_chip_uninit; | ||
640 | } | ||
641 | |||
642 | ret = iio_device_register(data->mag_indio_dev); | ||
643 | if (ret < 0) { | ||
644 | dev_err(&client->dev, "Failed to register mag iio device\n"); | ||
645 | goto err_iio_unregister; | ||
646 | } | ||
647 | |||
648 | return 0; | ||
649 | |||
650 | err_iio_unregister: | ||
651 | iio_device_unregister(data->acc_indio_dev); | ||
652 | err_chip_uninit: | ||
653 | kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); | ||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | static int kmx61_remove(struct i2c_client *client) | ||
658 | { | ||
659 | struct kmx61_data *data = i2c_get_clientdata(client); | ||
660 | |||
661 | iio_device_unregister(data->acc_indio_dev); | ||
662 | iio_device_unregister(data->mag_indio_dev); | ||
663 | |||
664 | mutex_lock(&data->lock); | ||
665 | kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true); | ||
666 | mutex_unlock(&data->lock); | ||
667 | |||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static const struct i2c_device_id kmx61_id[] = { | ||
672 | {"kmx611021", 0}, | ||
673 | {} | ||
674 | }; | ||
675 | |||
676 | MODULE_DEVICE_TABLE(i2c, kmx61_id); | ||
677 | |||
678 | static struct i2c_driver kmx61_driver = { | ||
679 | .driver = { | ||
680 | .name = KMX61_DRV_NAME, | ||
681 | }, | ||
682 | .probe = kmx61_probe, | ||
683 | .remove = kmx61_remove, | ||
684 | .id_table = kmx61_id, | ||
685 | }; | ||
686 | |||
687 | module_i2c_driver(kmx61_driver); | ||
688 | |||
689 | MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>"); | ||
690 | MODULE_DESCRIPTION("KMX61 accelerometer/magnetometer driver"); | ||
691 | MODULE_LICENSE("GPL v2"); | ||