1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2020 Invensense, Inc. |
4 | */ |
5 | |
6 | #include <linux/kernel.h> |
7 | #include <linux/device.h> |
8 | #include <linux/module.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/delay.h> |
11 | #include <linux/mutex.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/irq.h> |
14 | #include <linux/regulator/consumer.h> |
15 | #include <linux/pm_runtime.h> |
16 | #include <linux/property.h> |
17 | #include <linux/regmap.h> |
18 | |
19 | #include <linux/iio/iio.h> |
20 | |
21 | #include "inv_icm42600.h" |
22 | #include "inv_icm42600_buffer.h" |
23 | |
24 | static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = { |
25 | { |
26 | .name = "user banks" , |
27 | .range_min = 0x0000, |
28 | .range_max = 0x4FFF, |
29 | .selector_reg = INV_ICM42600_REG_BANK_SEL, |
30 | .selector_mask = INV_ICM42600_BANK_SEL_MASK, |
31 | .selector_shift = 0, |
32 | .window_start = 0, |
33 | .window_len = 0x1000, |
34 | }, |
35 | }; |
36 | |
37 | const struct regmap_config inv_icm42600_regmap_config = { |
38 | .reg_bits = 8, |
39 | .val_bits = 8, |
40 | .max_register = 0x4FFF, |
41 | .ranges = inv_icm42600_regmap_ranges, |
42 | .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges), |
43 | }; |
44 | EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600); |
45 | |
46 | struct inv_icm42600_hw { |
47 | uint8_t whoami; |
48 | const char *name; |
49 | const struct inv_icm42600_conf *conf; |
50 | }; |
51 | |
52 | /* chip initial default configuration */ |
53 | static const struct inv_icm42600_conf inv_icm42600_default_conf = { |
54 | .gyro = { |
55 | .mode = INV_ICM42600_SENSOR_MODE_OFF, |
56 | .fs = INV_ICM42600_GYRO_FS_2000DPS, |
57 | .odr = INV_ICM42600_ODR_50HZ, |
58 | .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2, |
59 | }, |
60 | .accel = { |
61 | .mode = INV_ICM42600_SENSOR_MODE_OFF, |
62 | .fs = INV_ICM42600_ACCEL_FS_16G, |
63 | .odr = INV_ICM42600_ODR_50HZ, |
64 | .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2, |
65 | }, |
66 | .temp_en = false, |
67 | }; |
68 | |
69 | static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = { |
70 | [INV_CHIP_ICM42600] = { |
71 | .whoami = INV_ICM42600_WHOAMI_ICM42600, |
72 | .name = "icm42600" , |
73 | .conf = &inv_icm42600_default_conf, |
74 | }, |
75 | [INV_CHIP_ICM42602] = { |
76 | .whoami = INV_ICM42600_WHOAMI_ICM42602, |
77 | .name = "icm42602" , |
78 | .conf = &inv_icm42600_default_conf, |
79 | }, |
80 | [INV_CHIP_ICM42605] = { |
81 | .whoami = INV_ICM42600_WHOAMI_ICM42605, |
82 | .name = "icm42605" , |
83 | .conf = &inv_icm42600_default_conf, |
84 | }, |
85 | [INV_CHIP_ICM42622] = { |
86 | .whoami = INV_ICM42600_WHOAMI_ICM42622, |
87 | .name = "icm42622" , |
88 | .conf = &inv_icm42600_default_conf, |
89 | }, |
90 | [INV_CHIP_ICM42631] = { |
91 | .whoami = INV_ICM42600_WHOAMI_ICM42631, |
92 | .name = "icm42631" , |
93 | .conf = &inv_icm42600_default_conf, |
94 | }, |
95 | }; |
96 | |
97 | const struct iio_mount_matrix * |
98 | inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev, |
99 | const struct iio_chan_spec *chan) |
100 | { |
101 | const struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); |
102 | |
103 | return &st->orientation; |
104 | } |
105 | |
106 | uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr) |
107 | { |
108 | static uint32_t odr_periods[INV_ICM42600_ODR_NB] = { |
109 | /* reserved values */ |
110 | 0, 0, 0, |
111 | /* 8kHz */ |
112 | 125000, |
113 | /* 4kHz */ |
114 | 250000, |
115 | /* 2kHz */ |
116 | 500000, |
117 | /* 1kHz */ |
118 | 1000000, |
119 | /* 200Hz */ |
120 | 5000000, |
121 | /* 100Hz */ |
122 | 10000000, |
123 | /* 50Hz */ |
124 | 20000000, |
125 | /* 25Hz */ |
126 | 40000000, |
127 | /* 12.5Hz */ |
128 | 80000000, |
129 | /* 6.25Hz */ |
130 | 160000000, |
131 | /* 3.125Hz */ |
132 | 320000000, |
133 | /* 1.5625Hz */ |
134 | 640000000, |
135 | /* 500Hz */ |
136 | 2000000, |
137 | }; |
138 | |
139 | return odr_periods[odr]; |
140 | } |
141 | |
142 | static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st, |
143 | enum inv_icm42600_sensor_mode gyro, |
144 | enum inv_icm42600_sensor_mode accel, |
145 | bool temp, unsigned int *sleep_ms) |
146 | { |
147 | enum inv_icm42600_sensor_mode oldgyro = st->conf.gyro.mode; |
148 | enum inv_icm42600_sensor_mode oldaccel = st->conf.accel.mode; |
149 | bool oldtemp = st->conf.temp_en; |
150 | unsigned int sleepval; |
151 | unsigned int val; |
152 | int ret; |
153 | |
154 | /* if nothing changed, exit */ |
155 | if (gyro == oldgyro && accel == oldaccel && temp == oldtemp) |
156 | return 0; |
157 | |
158 | val = INV_ICM42600_PWR_MGMT0_GYRO(gyro) | |
159 | INV_ICM42600_PWR_MGMT0_ACCEL(accel); |
160 | if (!temp) |
161 | val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS; |
162 | ret = regmap_write(map: st->map, INV_ICM42600_REG_PWR_MGMT0, val); |
163 | if (ret) |
164 | return ret; |
165 | |
166 | st->conf.gyro.mode = gyro; |
167 | st->conf.accel.mode = accel; |
168 | st->conf.temp_en = temp; |
169 | |
170 | /* compute required wait time for sensors to stabilize */ |
171 | sleepval = 0; |
172 | /* temperature stabilization time */ |
173 | if (temp && !oldtemp) { |
174 | if (sleepval < INV_ICM42600_TEMP_STARTUP_TIME_MS) |
175 | sleepval = INV_ICM42600_TEMP_STARTUP_TIME_MS; |
176 | } |
177 | /* accel startup time */ |
178 | if (accel != oldaccel && oldaccel == INV_ICM42600_SENSOR_MODE_OFF) { |
179 | /* block any register write for at least 200 µs */ |
180 | usleep_range(min: 200, max: 300); |
181 | if (sleepval < INV_ICM42600_ACCEL_STARTUP_TIME_MS) |
182 | sleepval = INV_ICM42600_ACCEL_STARTUP_TIME_MS; |
183 | } |
184 | if (gyro != oldgyro) { |
185 | /* gyro startup time */ |
186 | if (oldgyro == INV_ICM42600_SENSOR_MODE_OFF) { |
187 | /* block any register write for at least 200 µs */ |
188 | usleep_range(min: 200, max: 300); |
189 | if (sleepval < INV_ICM42600_GYRO_STARTUP_TIME_MS) |
190 | sleepval = INV_ICM42600_GYRO_STARTUP_TIME_MS; |
191 | /* gyro stop time */ |
192 | } else if (gyro == INV_ICM42600_SENSOR_MODE_OFF) { |
193 | if (sleepval < INV_ICM42600_GYRO_STOP_TIME_MS) |
194 | sleepval = INV_ICM42600_GYRO_STOP_TIME_MS; |
195 | } |
196 | } |
197 | |
198 | /* deferred sleep value if sleep pointer is provided or direct sleep */ |
199 | if (sleep_ms) |
200 | *sleep_ms = sleepval; |
201 | else if (sleepval) |
202 | msleep(msecs: sleepval); |
203 | |
204 | return 0; |
205 | } |
206 | |
207 | int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st, |
208 | struct inv_icm42600_sensor_conf *conf, |
209 | unsigned int *sleep_ms) |
210 | { |
211 | struct inv_icm42600_sensor_conf *oldconf = &st->conf.accel; |
212 | unsigned int val; |
213 | int ret; |
214 | |
215 | /* Sanitize missing values with current values */ |
216 | if (conf->mode < 0) |
217 | conf->mode = oldconf->mode; |
218 | if (conf->fs < 0) |
219 | conf->fs = oldconf->fs; |
220 | if (conf->odr < 0) |
221 | conf->odr = oldconf->odr; |
222 | if (conf->filter < 0) |
223 | conf->filter = oldconf->filter; |
224 | |
225 | /* set ACCEL_CONFIG0 register (accel fullscale & odr) */ |
226 | if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) { |
227 | val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) | |
228 | INV_ICM42600_ACCEL_CONFIG0_ODR(conf->odr); |
229 | ret = regmap_write(map: st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val); |
230 | if (ret) |
231 | return ret; |
232 | oldconf->fs = conf->fs; |
233 | oldconf->odr = conf->odr; |
234 | } |
235 | |
236 | /* set GYRO_ACCEL_CONFIG0 register (accel filter) */ |
237 | if (conf->filter != oldconf->filter) { |
238 | val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->filter) | |
239 | INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(st->conf.gyro.filter); |
240 | ret = regmap_write(map: st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val); |
241 | if (ret) |
242 | return ret; |
243 | oldconf->filter = conf->filter; |
244 | } |
245 | |
246 | /* set PWR_MGMT0 register (accel sensor mode) */ |
247 | return inv_icm42600_set_pwr_mgmt0(st, gyro: st->conf.gyro.mode, accel: conf->mode, |
248 | temp: st->conf.temp_en, sleep_ms); |
249 | } |
250 | |
251 | int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st, |
252 | struct inv_icm42600_sensor_conf *conf, |
253 | unsigned int *sleep_ms) |
254 | { |
255 | struct inv_icm42600_sensor_conf *oldconf = &st->conf.gyro; |
256 | unsigned int val; |
257 | int ret; |
258 | |
259 | /* sanitize missing values with current values */ |
260 | if (conf->mode < 0) |
261 | conf->mode = oldconf->mode; |
262 | if (conf->fs < 0) |
263 | conf->fs = oldconf->fs; |
264 | if (conf->odr < 0) |
265 | conf->odr = oldconf->odr; |
266 | if (conf->filter < 0) |
267 | conf->filter = oldconf->filter; |
268 | |
269 | /* set GYRO_CONFIG0 register (gyro fullscale & odr) */ |
270 | if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) { |
271 | val = INV_ICM42600_GYRO_CONFIG0_FS(conf->fs) | |
272 | INV_ICM42600_GYRO_CONFIG0_ODR(conf->odr); |
273 | ret = regmap_write(map: st->map, INV_ICM42600_REG_GYRO_CONFIG0, val); |
274 | if (ret) |
275 | return ret; |
276 | oldconf->fs = conf->fs; |
277 | oldconf->odr = conf->odr; |
278 | } |
279 | |
280 | /* set GYRO_ACCEL_CONFIG0 register (gyro filter) */ |
281 | if (conf->filter != oldconf->filter) { |
282 | val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(st->conf.accel.filter) | |
283 | INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->filter); |
284 | ret = regmap_write(map: st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val); |
285 | if (ret) |
286 | return ret; |
287 | oldconf->filter = conf->filter; |
288 | } |
289 | |
290 | /* set PWR_MGMT0 register (gyro sensor mode) */ |
291 | return inv_icm42600_set_pwr_mgmt0(st, gyro: conf->mode, accel: st->conf.accel.mode, |
292 | temp: st->conf.temp_en, sleep_ms); |
293 | |
294 | return 0; |
295 | } |
296 | |
297 | int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, |
298 | unsigned int *sleep_ms) |
299 | { |
300 | return inv_icm42600_set_pwr_mgmt0(st, gyro: st->conf.gyro.mode, |
301 | accel: st->conf.accel.mode, temp: enable, |
302 | sleep_ms); |
303 | } |
304 | |
305 | int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, |
306 | unsigned int writeval, unsigned int *readval) |
307 | { |
308 | struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); |
309 | int ret; |
310 | |
311 | mutex_lock(&st->lock); |
312 | |
313 | if (readval) |
314 | ret = regmap_read(map: st->map, reg, val: readval); |
315 | else |
316 | ret = regmap_write(map: st->map, reg, val: writeval); |
317 | |
318 | mutex_unlock(lock: &st->lock); |
319 | |
320 | return ret; |
321 | } |
322 | |
323 | static int inv_icm42600_set_conf(struct inv_icm42600_state *st, |
324 | const struct inv_icm42600_conf *conf) |
325 | { |
326 | unsigned int val; |
327 | int ret; |
328 | |
329 | /* set PWR_MGMT0 register (gyro & accel sensor mode, temp enabled) */ |
330 | val = INV_ICM42600_PWR_MGMT0_GYRO(conf->gyro.mode) | |
331 | INV_ICM42600_PWR_MGMT0_ACCEL(conf->accel.mode); |
332 | if (!conf->temp_en) |
333 | val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS; |
334 | ret = regmap_write(map: st->map, INV_ICM42600_REG_PWR_MGMT0, val); |
335 | if (ret) |
336 | return ret; |
337 | |
338 | /* set GYRO_CONFIG0 register (gyro fullscale & odr) */ |
339 | val = INV_ICM42600_GYRO_CONFIG0_FS(conf->gyro.fs) | |
340 | INV_ICM42600_GYRO_CONFIG0_ODR(conf->gyro.odr); |
341 | ret = regmap_write(map: st->map, INV_ICM42600_REG_GYRO_CONFIG0, val); |
342 | if (ret) |
343 | return ret; |
344 | |
345 | /* set ACCEL_CONFIG0 register (accel fullscale & odr) */ |
346 | val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->accel.fs) | |
347 | INV_ICM42600_ACCEL_CONFIG0_ODR(conf->accel.odr); |
348 | ret = regmap_write(map: st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val); |
349 | if (ret) |
350 | return ret; |
351 | |
352 | /* set GYRO_ACCEL_CONFIG0 register (gyro & accel filters) */ |
353 | val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->accel.filter) | |
354 | INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->gyro.filter); |
355 | ret = regmap_write(map: st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val); |
356 | if (ret) |
357 | return ret; |
358 | |
359 | /* update internal conf */ |
360 | st->conf = *conf; |
361 | |
362 | return 0; |
363 | } |
364 | |
365 | /** |
366 | * inv_icm42600_setup() - check and setup chip |
367 | * @st: driver internal state |
368 | * @bus_setup: callback for setting up bus specific registers |
369 | * |
370 | * Returns 0 on success, a negative error code otherwise. |
371 | */ |
372 | static int inv_icm42600_setup(struct inv_icm42600_state *st, |
373 | inv_icm42600_bus_setup bus_setup) |
374 | { |
375 | const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip]; |
376 | const struct device *dev = regmap_get_device(map: st->map); |
377 | unsigned int val; |
378 | int ret; |
379 | |
380 | /* check chip self-identification value */ |
381 | ret = regmap_read(map: st->map, INV_ICM42600_REG_WHOAMI, val: &val); |
382 | if (ret) |
383 | return ret; |
384 | if (val != hw->whoami) { |
385 | dev_err(dev, "invalid whoami %#02x expected %#02x (%s)\n" , |
386 | val, hw->whoami, hw->name); |
387 | return -ENODEV; |
388 | } |
389 | st->name = hw->name; |
390 | |
391 | /* reset to make sure previous state are not there */ |
392 | ret = regmap_write(map: st->map, INV_ICM42600_REG_DEVICE_CONFIG, |
393 | INV_ICM42600_DEVICE_CONFIG_SOFT_RESET); |
394 | if (ret) |
395 | return ret; |
396 | msleep(INV_ICM42600_RESET_TIME_MS); |
397 | |
398 | ret = regmap_read(map: st->map, INV_ICM42600_REG_INT_STATUS, val: &val); |
399 | if (ret) |
400 | return ret; |
401 | if (!(val & INV_ICM42600_INT_STATUS_RESET_DONE)) { |
402 | dev_err(dev, "reset error, reset done bit not set\n" ); |
403 | return -ENODEV; |
404 | } |
405 | |
406 | /* set chip bus configuration */ |
407 | ret = bus_setup(st); |
408 | if (ret) |
409 | return ret; |
410 | |
411 | /* sensor data in big-endian (default) */ |
412 | ret = regmap_update_bits(map: st->map, INV_ICM42600_REG_INTF_CONFIG0, |
413 | INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN, |
414 | INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN); |
415 | if (ret) |
416 | return ret; |
417 | |
418 | return inv_icm42600_set_conf(st, conf: hw->conf); |
419 | } |
420 | |
421 | static irqreturn_t inv_icm42600_irq_timestamp(int irq, void *_data) |
422 | { |
423 | struct inv_icm42600_state *st = _data; |
424 | |
425 | st->timestamp.gyro = iio_get_time_ns(indio_dev: st->indio_gyro); |
426 | st->timestamp.accel = iio_get_time_ns(indio_dev: st->indio_accel); |
427 | |
428 | return IRQ_WAKE_THREAD; |
429 | } |
430 | |
431 | static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data) |
432 | { |
433 | struct inv_icm42600_state *st = _data; |
434 | struct device *dev = regmap_get_device(map: st->map); |
435 | unsigned int status; |
436 | int ret; |
437 | |
438 | mutex_lock(&st->lock); |
439 | |
440 | ret = regmap_read(map: st->map, INV_ICM42600_REG_INT_STATUS, val: &status); |
441 | if (ret) |
442 | goto out_unlock; |
443 | |
444 | /* FIFO full */ |
445 | if (status & INV_ICM42600_INT_STATUS_FIFO_FULL) |
446 | dev_warn(dev, "FIFO full data lost!\n" ); |
447 | |
448 | /* FIFO threshold reached */ |
449 | if (status & INV_ICM42600_INT_STATUS_FIFO_THS) { |
450 | ret = inv_icm42600_buffer_fifo_read(st, max: 0); |
451 | if (ret) { |
452 | dev_err(dev, "FIFO read error %d\n" , ret); |
453 | goto out_unlock; |
454 | } |
455 | ret = inv_icm42600_buffer_fifo_parse(st); |
456 | if (ret) |
457 | dev_err(dev, "FIFO parsing error %d\n" , ret); |
458 | } |
459 | |
460 | out_unlock: |
461 | mutex_unlock(lock: &st->lock); |
462 | return IRQ_HANDLED; |
463 | } |
464 | |
465 | /** |
466 | * inv_icm42600_irq_init() - initialize int pin and interrupt handler |
467 | * @st: driver internal state |
468 | * @irq: irq number |
469 | * @irq_type: irq trigger type |
470 | * @open_drain: true if irq is open drain, false for push-pull |
471 | * |
472 | * Returns 0 on success, a negative error code otherwise. |
473 | */ |
474 | static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq, |
475 | int irq_type, bool open_drain) |
476 | { |
477 | struct device *dev = regmap_get_device(map: st->map); |
478 | unsigned int val; |
479 | int ret; |
480 | |
481 | /* configure INT1 interrupt: default is active low on edge */ |
482 | switch (irq_type) { |
483 | case IRQF_TRIGGER_RISING: |
484 | case IRQF_TRIGGER_HIGH: |
485 | val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH; |
486 | break; |
487 | default: |
488 | val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW; |
489 | break; |
490 | } |
491 | |
492 | switch (irq_type) { |
493 | case IRQF_TRIGGER_LOW: |
494 | case IRQF_TRIGGER_HIGH: |
495 | val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED; |
496 | break; |
497 | default: |
498 | break; |
499 | } |
500 | |
501 | if (!open_drain) |
502 | val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL; |
503 | |
504 | ret = regmap_write(map: st->map, INV_ICM42600_REG_INT_CONFIG, val); |
505 | if (ret) |
506 | return ret; |
507 | |
508 | /* Deassert async reset for proper INT pin operation (cf datasheet) */ |
509 | ret = regmap_update_bits(map: st->map, INV_ICM42600_REG_INT_CONFIG1, |
510 | INV_ICM42600_INT_CONFIG1_ASYNC_RESET, val: 0); |
511 | if (ret) |
512 | return ret; |
513 | |
514 | return devm_request_threaded_irq(dev, irq, handler: inv_icm42600_irq_timestamp, |
515 | thread_fn: inv_icm42600_irq_handler, irqflags: irq_type, |
516 | devname: "inv_icm42600" , dev_id: st); |
517 | } |
518 | |
519 | static int inv_icm42600_timestamp_setup(struct inv_icm42600_state *st) |
520 | { |
521 | unsigned int val; |
522 | |
523 | /* enable timestamp register */ |
524 | val = INV_ICM42600_TMST_CONFIG_TMST_TO_REGS_EN | |
525 | INV_ICM42600_TMST_CONFIG_TMST_EN; |
526 | return regmap_update_bits(map: st->map, INV_ICM42600_REG_TMST_CONFIG, |
527 | INV_ICM42600_TMST_CONFIG_MASK, val); |
528 | } |
529 | |
530 | static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st) |
531 | { |
532 | int ret; |
533 | |
534 | ret = regulator_enable(regulator: st->vddio_supply); |
535 | if (ret) |
536 | return ret; |
537 | |
538 | /* wait a little for supply ramp */ |
539 | usleep_range(min: 3000, max: 4000); |
540 | |
541 | return 0; |
542 | } |
543 | |
544 | static void inv_icm42600_disable_vdd_reg(void *_data) |
545 | { |
546 | struct inv_icm42600_state *st = _data; |
547 | const struct device *dev = regmap_get_device(map: st->map); |
548 | int ret; |
549 | |
550 | ret = regulator_disable(regulator: st->vdd_supply); |
551 | if (ret) |
552 | dev_err(dev, "failed to disable vdd error %d\n" , ret); |
553 | } |
554 | |
555 | static void inv_icm42600_disable_vddio_reg(void *_data) |
556 | { |
557 | struct inv_icm42600_state *st = _data; |
558 | const struct device *dev = regmap_get_device(map: st->map); |
559 | int ret; |
560 | |
561 | ret = regulator_disable(regulator: st->vddio_supply); |
562 | if (ret) |
563 | dev_err(dev, "failed to disable vddio error %d\n" , ret); |
564 | } |
565 | |
566 | static void inv_icm42600_disable_pm(void *_data) |
567 | { |
568 | struct device *dev = _data; |
569 | |
570 | pm_runtime_put_sync(dev); |
571 | pm_runtime_disable(dev); |
572 | } |
573 | |
574 | int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, |
575 | inv_icm42600_bus_setup bus_setup) |
576 | { |
577 | struct device *dev = regmap_get_device(map: regmap); |
578 | struct inv_icm42600_state *st; |
579 | struct irq_data *irq_desc; |
580 | int irq_type; |
581 | bool open_drain; |
582 | int ret; |
583 | |
584 | if (chip <= INV_CHIP_INVALID || chip >= INV_CHIP_NB) { |
585 | dev_err(dev, "invalid chip = %d\n" , chip); |
586 | return -ENODEV; |
587 | } |
588 | |
589 | /* get irq properties, set trigger falling by default */ |
590 | irq_desc = irq_get_irq_data(irq); |
591 | if (!irq_desc) { |
592 | dev_err(dev, "could not find IRQ %d\n" , irq); |
593 | return -EINVAL; |
594 | } |
595 | |
596 | irq_type = irqd_get_trigger_type(d: irq_desc); |
597 | if (!irq_type) |
598 | irq_type = IRQF_TRIGGER_FALLING; |
599 | |
600 | open_drain = device_property_read_bool(dev, propname: "drive-open-drain" ); |
601 | |
602 | st = devm_kzalloc(dev, size: sizeof(*st), GFP_KERNEL); |
603 | if (!st) |
604 | return -ENOMEM; |
605 | |
606 | dev_set_drvdata(dev, data: st); |
607 | mutex_init(&st->lock); |
608 | st->chip = chip; |
609 | st->map = regmap; |
610 | |
611 | ret = iio_read_mount_matrix(dev, matrix: &st->orientation); |
612 | if (ret) { |
613 | dev_err(dev, "failed to retrieve mounting matrix %d\n" , ret); |
614 | return ret; |
615 | } |
616 | |
617 | st->vdd_supply = devm_regulator_get(dev, id: "vdd" ); |
618 | if (IS_ERR(ptr: st->vdd_supply)) |
619 | return PTR_ERR(ptr: st->vdd_supply); |
620 | |
621 | st->vddio_supply = devm_regulator_get(dev, id: "vddio" ); |
622 | if (IS_ERR(ptr: st->vddio_supply)) |
623 | return PTR_ERR(ptr: st->vddio_supply); |
624 | |
625 | ret = regulator_enable(regulator: st->vdd_supply); |
626 | if (ret) |
627 | return ret; |
628 | msleep(INV_ICM42600_POWER_UP_TIME_MS); |
629 | |
630 | ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vdd_reg, st); |
631 | if (ret) |
632 | return ret; |
633 | |
634 | ret = inv_icm42600_enable_regulator_vddio(st); |
635 | if (ret) |
636 | return ret; |
637 | |
638 | ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vddio_reg, st); |
639 | if (ret) |
640 | return ret; |
641 | |
642 | /* setup chip registers */ |
643 | ret = inv_icm42600_setup(st, bus_setup); |
644 | if (ret) |
645 | return ret; |
646 | |
647 | ret = inv_icm42600_timestamp_setup(st); |
648 | if (ret) |
649 | return ret; |
650 | |
651 | ret = inv_icm42600_buffer_init(st); |
652 | if (ret) |
653 | return ret; |
654 | |
655 | st->indio_gyro = inv_icm42600_gyro_init(st); |
656 | if (IS_ERR(ptr: st->indio_gyro)) |
657 | return PTR_ERR(ptr: st->indio_gyro); |
658 | |
659 | st->indio_accel = inv_icm42600_accel_init(st); |
660 | if (IS_ERR(ptr: st->indio_accel)) |
661 | return PTR_ERR(ptr: st->indio_accel); |
662 | |
663 | ret = inv_icm42600_irq_init(st, irq, irq_type, open_drain); |
664 | if (ret) |
665 | return ret; |
666 | |
667 | /* setup runtime power management */ |
668 | ret = pm_runtime_set_active(dev); |
669 | if (ret) |
670 | return ret; |
671 | pm_runtime_get_noresume(dev); |
672 | pm_runtime_enable(dev); |
673 | pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS); |
674 | pm_runtime_use_autosuspend(dev); |
675 | pm_runtime_put(dev); |
676 | |
677 | return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev); |
678 | } |
679 | EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, IIO_ICM42600); |
680 | |
681 | /* |
682 | * Suspend saves sensors state and turns everything off. |
683 | * Check first if runtime suspend has not already done the job. |
684 | */ |
685 | static int inv_icm42600_suspend(struct device *dev) |
686 | { |
687 | struct inv_icm42600_state *st = dev_get_drvdata(dev); |
688 | int ret; |
689 | |
690 | mutex_lock(&st->lock); |
691 | |
692 | st->suspended.gyro = st->conf.gyro.mode; |
693 | st->suspended.accel = st->conf.accel.mode; |
694 | st->suspended.temp = st->conf.temp_en; |
695 | if (pm_runtime_suspended(dev)) { |
696 | ret = 0; |
697 | goto out_unlock; |
698 | } |
699 | |
700 | /* disable FIFO data streaming */ |
701 | if (st->fifo.on) { |
702 | ret = regmap_write(map: st->map, INV_ICM42600_REG_FIFO_CONFIG, |
703 | INV_ICM42600_FIFO_CONFIG_BYPASS); |
704 | if (ret) |
705 | goto out_unlock; |
706 | } |
707 | |
708 | ret = inv_icm42600_set_pwr_mgmt0(st, gyro: INV_ICM42600_SENSOR_MODE_OFF, |
709 | accel: INV_ICM42600_SENSOR_MODE_OFF, temp: false, |
710 | NULL); |
711 | if (ret) |
712 | goto out_unlock; |
713 | |
714 | regulator_disable(regulator: st->vddio_supply); |
715 | |
716 | out_unlock: |
717 | mutex_unlock(lock: &st->lock); |
718 | return ret; |
719 | } |
720 | |
721 | /* |
722 | * System resume gets the system back on and restores the sensors state. |
723 | * Manually put runtime power management in system active state. |
724 | */ |
725 | static int inv_icm42600_resume(struct device *dev) |
726 | { |
727 | struct inv_icm42600_state *st = dev_get_drvdata(dev); |
728 | int ret; |
729 | |
730 | mutex_lock(&st->lock); |
731 | |
732 | ret = inv_icm42600_enable_regulator_vddio(st); |
733 | if (ret) |
734 | goto out_unlock; |
735 | |
736 | pm_runtime_disable(dev); |
737 | pm_runtime_set_active(dev); |
738 | pm_runtime_enable(dev); |
739 | |
740 | /* restore sensors state */ |
741 | ret = inv_icm42600_set_pwr_mgmt0(st, gyro: st->suspended.gyro, |
742 | accel: st->suspended.accel, |
743 | temp: st->suspended.temp, NULL); |
744 | if (ret) |
745 | goto out_unlock; |
746 | |
747 | /* restore FIFO data streaming */ |
748 | if (st->fifo.on) |
749 | ret = regmap_write(map: st->map, INV_ICM42600_REG_FIFO_CONFIG, |
750 | INV_ICM42600_FIFO_CONFIG_STREAM); |
751 | |
752 | out_unlock: |
753 | mutex_unlock(lock: &st->lock); |
754 | return ret; |
755 | } |
756 | |
757 | /* Runtime suspend will turn off sensors that are enabled by iio devices. */ |
758 | static int inv_icm42600_runtime_suspend(struct device *dev) |
759 | { |
760 | struct inv_icm42600_state *st = dev_get_drvdata(dev); |
761 | int ret; |
762 | |
763 | mutex_lock(&st->lock); |
764 | |
765 | /* disable all sensors */ |
766 | ret = inv_icm42600_set_pwr_mgmt0(st, gyro: INV_ICM42600_SENSOR_MODE_OFF, |
767 | accel: INV_ICM42600_SENSOR_MODE_OFF, temp: false, |
768 | NULL); |
769 | if (ret) |
770 | goto error_unlock; |
771 | |
772 | regulator_disable(regulator: st->vddio_supply); |
773 | |
774 | error_unlock: |
775 | mutex_unlock(lock: &st->lock); |
776 | return ret; |
777 | } |
778 | |
779 | /* Sensors are enabled by iio devices, no need to turn them back on here. */ |
780 | static int inv_icm42600_runtime_resume(struct device *dev) |
781 | { |
782 | struct inv_icm42600_state *st = dev_get_drvdata(dev); |
783 | int ret; |
784 | |
785 | mutex_lock(&st->lock); |
786 | |
787 | ret = inv_icm42600_enable_regulator_vddio(st); |
788 | |
789 | mutex_unlock(lock: &st->lock); |
790 | return ret; |
791 | } |
792 | |
793 | EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42600_pm_ops, IIO_ICM42600) = { |
794 | SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume) |
795 | RUNTIME_PM_OPS(inv_icm42600_runtime_suspend, |
796 | inv_icm42600_runtime_resume, NULL) |
797 | }; |
798 | |
799 | MODULE_AUTHOR("InvenSense, Inc." ); |
800 | MODULE_DESCRIPTION("InvenSense ICM-426xx device driver" ); |
801 | MODULE_LICENSE("GPL" ); |
802 | MODULE_IMPORT_NS(IIO_INV_SENSORS_TIMESTAMP); |
803 | |