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