131c24c1eSJean-Baptiste Maneyrol // SPDX-License-Identifier: GPL-2.0-or-later
231c24c1eSJean-Baptiste Maneyrol /*
331c24c1eSJean-Baptiste Maneyrol * Copyright (C) 2020 Invensense, Inc.
431c24c1eSJean-Baptiste Maneyrol */
531c24c1eSJean-Baptiste Maneyrol
631c24c1eSJean-Baptiste Maneyrol #include <linux/kernel.h>
731c24c1eSJean-Baptiste Maneyrol #include <linux/device.h>
831c24c1eSJean-Baptiste Maneyrol #include <linux/module.h>
931c24c1eSJean-Baptiste Maneyrol #include <linux/slab.h>
1031c24c1eSJean-Baptiste Maneyrol #include <linux/delay.h>
1131c24c1eSJean-Baptiste Maneyrol #include <linux/mutex.h>
12e5efa104SJean-Baptiste Maneyrol #include <linux/interrupt.h>
13e5efa104SJean-Baptiste Maneyrol #include <linux/irq.h>
1431c24c1eSJean-Baptiste Maneyrol #include <linux/regulator/consumer.h>
1531c24c1eSJean-Baptiste Maneyrol #include <linux/pm_runtime.h>
16e5efa104SJean-Baptiste Maneyrol #include <linux/property.h>
1731c24c1eSJean-Baptiste Maneyrol #include <linux/regmap.h>
18*d99ff463SJean-Baptiste Maneyrol
1931c24c1eSJean-Baptiste Maneyrol #include <linux/iio/iio.h>
2031c24c1eSJean-Baptiste Maneyrol
2131c24c1eSJean-Baptiste Maneyrol #include "inv_icm42600.h"
227f85e42aSJean-Baptiste Maneyrol #include "inv_icm42600_buffer.h"
2331c24c1eSJean-Baptiste Maneyrol
2431c24c1eSJean-Baptiste Maneyrol static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
2531c24c1eSJean-Baptiste Maneyrol {
2631c24c1eSJean-Baptiste Maneyrol .name = "user banks",
2731c24c1eSJean-Baptiste Maneyrol .range_min = 0x0000,
2831c24c1eSJean-Baptiste Maneyrol .range_max = 0x4FFF,
2931c24c1eSJean-Baptiste Maneyrol .selector_reg = INV_ICM42600_REG_BANK_SEL,
3031c24c1eSJean-Baptiste Maneyrol .selector_mask = INV_ICM42600_BANK_SEL_MASK,
3131c24c1eSJean-Baptiste Maneyrol .selector_shift = 0,
3231c24c1eSJean-Baptiste Maneyrol .window_start = 0,
3331c24c1eSJean-Baptiste Maneyrol .window_len = 0x1000,
3431c24c1eSJean-Baptiste Maneyrol },
3531c24c1eSJean-Baptiste Maneyrol };
3631c24c1eSJean-Baptiste Maneyrol
3731c24c1eSJean-Baptiste Maneyrol const struct regmap_config inv_icm42600_regmap_config = {
3831c24c1eSJean-Baptiste Maneyrol .reg_bits = 8,
3931c24c1eSJean-Baptiste Maneyrol .val_bits = 8,
4031c24c1eSJean-Baptiste Maneyrol .max_register = 0x4FFF,
4131c24c1eSJean-Baptiste Maneyrol .ranges = inv_icm42600_regmap_ranges,
4231c24c1eSJean-Baptiste Maneyrol .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
4331c24c1eSJean-Baptiste Maneyrol };
44ef5a5ef2SJonathan Cameron EXPORT_SYMBOL_NS_GPL(inv_icm42600_regmap_config, IIO_ICM42600);
4531c24c1eSJean-Baptiste Maneyrol
4631c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_hw {
4731c24c1eSJean-Baptiste Maneyrol uint8_t whoami;
4831c24c1eSJean-Baptiste Maneyrol const char *name;
4931c24c1eSJean-Baptiste Maneyrol const struct inv_icm42600_conf *conf;
5031c24c1eSJean-Baptiste Maneyrol };
5131c24c1eSJean-Baptiste Maneyrol
5231c24c1eSJean-Baptiste Maneyrol /* chip initial default configuration */
5331c24c1eSJean-Baptiste Maneyrol static const struct inv_icm42600_conf inv_icm42600_default_conf = {
5431c24c1eSJean-Baptiste Maneyrol .gyro = {
5531c24c1eSJean-Baptiste Maneyrol .mode = INV_ICM42600_SENSOR_MODE_OFF,
5631c24c1eSJean-Baptiste Maneyrol .fs = INV_ICM42600_GYRO_FS_2000DPS,
5731c24c1eSJean-Baptiste Maneyrol .odr = INV_ICM42600_ODR_50HZ,
5831c24c1eSJean-Baptiste Maneyrol .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
5931c24c1eSJean-Baptiste Maneyrol },
6031c24c1eSJean-Baptiste Maneyrol .accel = {
6131c24c1eSJean-Baptiste Maneyrol .mode = INV_ICM42600_SENSOR_MODE_OFF,
6231c24c1eSJean-Baptiste Maneyrol .fs = INV_ICM42600_ACCEL_FS_16G,
6331c24c1eSJean-Baptiste Maneyrol .odr = INV_ICM42600_ODR_50HZ,
6431c24c1eSJean-Baptiste Maneyrol .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
6531c24c1eSJean-Baptiste Maneyrol },
6631c24c1eSJean-Baptiste Maneyrol .temp_en = false,
6731c24c1eSJean-Baptiste Maneyrol };
6831c24c1eSJean-Baptiste Maneyrol
6931c24c1eSJean-Baptiste Maneyrol static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
7031c24c1eSJean-Baptiste Maneyrol [INV_CHIP_ICM42600] = {
7131c24c1eSJean-Baptiste Maneyrol .whoami = INV_ICM42600_WHOAMI_ICM42600,
7231c24c1eSJean-Baptiste Maneyrol .name = "icm42600",
7331c24c1eSJean-Baptiste Maneyrol .conf = &inv_icm42600_default_conf,
7431c24c1eSJean-Baptiste Maneyrol },
7531c24c1eSJean-Baptiste Maneyrol [INV_CHIP_ICM42602] = {
7631c24c1eSJean-Baptiste Maneyrol .whoami = INV_ICM42600_WHOAMI_ICM42602,
7731c24c1eSJean-Baptiste Maneyrol .name = "icm42602",
7831c24c1eSJean-Baptiste Maneyrol .conf = &inv_icm42600_default_conf,
7931c24c1eSJean-Baptiste Maneyrol },
8031c24c1eSJean-Baptiste Maneyrol [INV_CHIP_ICM42605] = {
8131c24c1eSJean-Baptiste Maneyrol .whoami = INV_ICM42600_WHOAMI_ICM42605,
8231c24c1eSJean-Baptiste Maneyrol .name = "icm42605",
8331c24c1eSJean-Baptiste Maneyrol .conf = &inv_icm42600_default_conf,
8431c24c1eSJean-Baptiste Maneyrol },
8531c24c1eSJean-Baptiste Maneyrol [INV_CHIP_ICM42622] = {
8631c24c1eSJean-Baptiste Maneyrol .whoami = INV_ICM42600_WHOAMI_ICM42622,
8731c24c1eSJean-Baptiste Maneyrol .name = "icm42622",
8831c24c1eSJean-Baptiste Maneyrol .conf = &inv_icm42600_default_conf,
8931c24c1eSJean-Baptiste Maneyrol },
90c896b9f0SJay Greco [INV_CHIP_ICM42631] = {
91c896b9f0SJay Greco .whoami = INV_ICM42600_WHOAMI_ICM42631,
92c896b9f0SJay Greco .name = "icm42631",
93c896b9f0SJay Greco .conf = &inv_icm42600_default_conf,
94c896b9f0SJay Greco },
9531c24c1eSJean-Baptiste Maneyrol };
9631c24c1eSJean-Baptiste Maneyrol
9731c24c1eSJean-Baptiste Maneyrol const struct iio_mount_matrix *
inv_icm42600_get_mount_matrix(const struct iio_dev * indio_dev,const struct iio_chan_spec * chan)9831c24c1eSJean-Baptiste Maneyrol inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev,
9931c24c1eSJean-Baptiste Maneyrol const struct iio_chan_spec *chan)
10031c24c1eSJean-Baptiste Maneyrol {
10131c24c1eSJean-Baptiste Maneyrol const struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
10231c24c1eSJean-Baptiste Maneyrol
10331c24c1eSJean-Baptiste Maneyrol return &st->orientation;
10431c24c1eSJean-Baptiste Maneyrol }
10531c24c1eSJean-Baptiste Maneyrol
inv_icm42600_odr_to_period(enum inv_icm42600_odr odr)10631c24c1eSJean-Baptiste Maneyrol uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr)
10731c24c1eSJean-Baptiste Maneyrol {
10831c24c1eSJean-Baptiste Maneyrol static uint32_t odr_periods[INV_ICM42600_ODR_NB] = {
10931c24c1eSJean-Baptiste Maneyrol /* reserved values */
11031c24c1eSJean-Baptiste Maneyrol 0, 0, 0,
11131c24c1eSJean-Baptiste Maneyrol /* 8kHz */
11231c24c1eSJean-Baptiste Maneyrol 125000,
11331c24c1eSJean-Baptiste Maneyrol /* 4kHz */
11431c24c1eSJean-Baptiste Maneyrol 250000,
11531c24c1eSJean-Baptiste Maneyrol /* 2kHz */
11631c24c1eSJean-Baptiste Maneyrol 500000,
11731c24c1eSJean-Baptiste Maneyrol /* 1kHz */
11831c24c1eSJean-Baptiste Maneyrol 1000000,
11931c24c1eSJean-Baptiste Maneyrol /* 200Hz */
12031c24c1eSJean-Baptiste Maneyrol 5000000,
12131c24c1eSJean-Baptiste Maneyrol /* 100Hz */
12231c24c1eSJean-Baptiste Maneyrol 10000000,
12331c24c1eSJean-Baptiste Maneyrol /* 50Hz */
12431c24c1eSJean-Baptiste Maneyrol 20000000,
12531c24c1eSJean-Baptiste Maneyrol /* 25Hz */
12631c24c1eSJean-Baptiste Maneyrol 40000000,
12731c24c1eSJean-Baptiste Maneyrol /* 12.5Hz */
12831c24c1eSJean-Baptiste Maneyrol 80000000,
12931c24c1eSJean-Baptiste Maneyrol /* 6.25Hz */
13031c24c1eSJean-Baptiste Maneyrol 160000000,
13131c24c1eSJean-Baptiste Maneyrol /* 3.125Hz */
13231c24c1eSJean-Baptiste Maneyrol 320000000,
13331c24c1eSJean-Baptiste Maneyrol /* 1.5625Hz */
13431c24c1eSJean-Baptiste Maneyrol 640000000,
13531c24c1eSJean-Baptiste Maneyrol /* 500Hz */
13631c24c1eSJean-Baptiste Maneyrol 2000000,
13731c24c1eSJean-Baptiste Maneyrol };
13831c24c1eSJean-Baptiste Maneyrol
13931c24c1eSJean-Baptiste Maneyrol return odr_periods[odr];
14031c24c1eSJean-Baptiste Maneyrol }
14131c24c1eSJean-Baptiste Maneyrol
inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state * st,enum inv_icm42600_sensor_mode gyro,enum inv_icm42600_sensor_mode accel,bool temp,unsigned int * sleep_ms)14231c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st,
14331c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode gyro,
14431c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode accel,
14531c24c1eSJean-Baptiste Maneyrol bool temp, unsigned int *sleep_ms)
14631c24c1eSJean-Baptiste Maneyrol {
14731c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode oldgyro = st->conf.gyro.mode;
14831c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode oldaccel = st->conf.accel.mode;
14931c24c1eSJean-Baptiste Maneyrol bool oldtemp = st->conf.temp_en;
15031c24c1eSJean-Baptiste Maneyrol unsigned int sleepval;
15131c24c1eSJean-Baptiste Maneyrol unsigned int val;
15231c24c1eSJean-Baptiste Maneyrol int ret;
15331c24c1eSJean-Baptiste Maneyrol
15431c24c1eSJean-Baptiste Maneyrol /* if nothing changed, exit */
15531c24c1eSJean-Baptiste Maneyrol if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
15631c24c1eSJean-Baptiste Maneyrol return 0;
15731c24c1eSJean-Baptiste Maneyrol
15831c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_PWR_MGMT0_GYRO(gyro) |
15931c24c1eSJean-Baptiste Maneyrol INV_ICM42600_PWR_MGMT0_ACCEL(accel);
16031c24c1eSJean-Baptiste Maneyrol if (!temp)
16131c24c1eSJean-Baptiste Maneyrol val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
16231c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
16331c24c1eSJean-Baptiste Maneyrol if (ret)
16431c24c1eSJean-Baptiste Maneyrol return ret;
16531c24c1eSJean-Baptiste Maneyrol
16631c24c1eSJean-Baptiste Maneyrol st->conf.gyro.mode = gyro;
16731c24c1eSJean-Baptiste Maneyrol st->conf.accel.mode = accel;
16831c24c1eSJean-Baptiste Maneyrol st->conf.temp_en = temp;
16931c24c1eSJean-Baptiste Maneyrol
17031c24c1eSJean-Baptiste Maneyrol /* compute required wait time for sensors to stabilize */
17131c24c1eSJean-Baptiste Maneyrol sleepval = 0;
17231c24c1eSJean-Baptiste Maneyrol /* temperature stabilization time */
17331c24c1eSJean-Baptiste Maneyrol if (temp && !oldtemp) {
17431c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_TEMP_STARTUP_TIME_MS)
17531c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_TEMP_STARTUP_TIME_MS;
17631c24c1eSJean-Baptiste Maneyrol }
17731c24c1eSJean-Baptiste Maneyrol /* accel startup time */
17831c24c1eSJean-Baptiste Maneyrol if (accel != oldaccel && oldaccel == INV_ICM42600_SENSOR_MODE_OFF) {
17931c24c1eSJean-Baptiste Maneyrol /* block any register write for at least 200 µs */
18031c24c1eSJean-Baptiste Maneyrol usleep_range(200, 300);
18131c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_ACCEL_STARTUP_TIME_MS)
18231c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_ACCEL_STARTUP_TIME_MS;
18331c24c1eSJean-Baptiste Maneyrol }
18431c24c1eSJean-Baptiste Maneyrol if (gyro != oldgyro) {
18531c24c1eSJean-Baptiste Maneyrol /* gyro startup time */
18631c24c1eSJean-Baptiste Maneyrol if (oldgyro == INV_ICM42600_SENSOR_MODE_OFF) {
18731c24c1eSJean-Baptiste Maneyrol /* block any register write for at least 200 µs */
18831c24c1eSJean-Baptiste Maneyrol usleep_range(200, 300);
18931c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_GYRO_STARTUP_TIME_MS)
19031c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_GYRO_STARTUP_TIME_MS;
19131c24c1eSJean-Baptiste Maneyrol /* gyro stop time */
19231c24c1eSJean-Baptiste Maneyrol } else if (gyro == INV_ICM42600_SENSOR_MODE_OFF) {
19331c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_GYRO_STOP_TIME_MS)
19431c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_GYRO_STOP_TIME_MS;
19531c24c1eSJean-Baptiste Maneyrol }
19631c24c1eSJean-Baptiste Maneyrol }
19731c24c1eSJean-Baptiste Maneyrol
19831c24c1eSJean-Baptiste Maneyrol /* deferred sleep value if sleep pointer is provided or direct sleep */
19931c24c1eSJean-Baptiste Maneyrol if (sleep_ms)
20031c24c1eSJean-Baptiste Maneyrol *sleep_ms = sleepval;
20131c24c1eSJean-Baptiste Maneyrol else if (sleepval)
20231c24c1eSJean-Baptiste Maneyrol msleep(sleepval);
20331c24c1eSJean-Baptiste Maneyrol
20431c24c1eSJean-Baptiste Maneyrol return 0;
20531c24c1eSJean-Baptiste Maneyrol }
20631c24c1eSJean-Baptiste Maneyrol
inv_icm42600_set_accel_conf(struct inv_icm42600_state * st,struct inv_icm42600_sensor_conf * conf,unsigned int * sleep_ms)20731c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
20831c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *conf,
20931c24c1eSJean-Baptiste Maneyrol unsigned int *sleep_ms)
21031c24c1eSJean-Baptiste Maneyrol {
21131c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *oldconf = &st->conf.accel;
21231c24c1eSJean-Baptiste Maneyrol unsigned int val;
21331c24c1eSJean-Baptiste Maneyrol int ret;
21431c24c1eSJean-Baptiste Maneyrol
21531c24c1eSJean-Baptiste Maneyrol /* Sanitize missing values with current values */
21631c24c1eSJean-Baptiste Maneyrol if (conf->mode < 0)
21731c24c1eSJean-Baptiste Maneyrol conf->mode = oldconf->mode;
21831c24c1eSJean-Baptiste Maneyrol if (conf->fs < 0)
21931c24c1eSJean-Baptiste Maneyrol conf->fs = oldconf->fs;
22031c24c1eSJean-Baptiste Maneyrol if (conf->odr < 0)
22131c24c1eSJean-Baptiste Maneyrol conf->odr = oldconf->odr;
22231c24c1eSJean-Baptiste Maneyrol if (conf->filter < 0)
22331c24c1eSJean-Baptiste Maneyrol conf->filter = oldconf->filter;
22431c24c1eSJean-Baptiste Maneyrol
22531c24c1eSJean-Baptiste Maneyrol /* set ACCEL_CONFIG0 register (accel fullscale & odr) */
22631c24c1eSJean-Baptiste Maneyrol if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
22731c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) |
22831c24c1eSJean-Baptiste Maneyrol INV_ICM42600_ACCEL_CONFIG0_ODR(conf->odr);
22931c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
23031c24c1eSJean-Baptiste Maneyrol if (ret)
23131c24c1eSJean-Baptiste Maneyrol return ret;
23231c24c1eSJean-Baptiste Maneyrol oldconf->fs = conf->fs;
23331c24c1eSJean-Baptiste Maneyrol oldconf->odr = conf->odr;
23431c24c1eSJean-Baptiste Maneyrol }
23531c24c1eSJean-Baptiste Maneyrol
23631c24c1eSJean-Baptiste Maneyrol /* set GYRO_ACCEL_CONFIG0 register (accel filter) */
23731c24c1eSJean-Baptiste Maneyrol if (conf->filter != oldconf->filter) {
23831c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->filter) |
23931c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(st->conf.gyro.filter);
24031c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
24131c24c1eSJean-Baptiste Maneyrol if (ret)
24231c24c1eSJean-Baptiste Maneyrol return ret;
24331c24c1eSJean-Baptiste Maneyrol oldconf->filter = conf->filter;
24431c24c1eSJean-Baptiste Maneyrol }
24531c24c1eSJean-Baptiste Maneyrol
24631c24c1eSJean-Baptiste Maneyrol /* set PWR_MGMT0 register (accel sensor mode) */
24731c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
24831c24c1eSJean-Baptiste Maneyrol st->conf.temp_en, sleep_ms);
24931c24c1eSJean-Baptiste Maneyrol }
25031c24c1eSJean-Baptiste Maneyrol
inv_icm42600_set_gyro_conf(struct inv_icm42600_state * st,struct inv_icm42600_sensor_conf * conf,unsigned int * sleep_ms)25131c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
25231c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *conf,
25331c24c1eSJean-Baptiste Maneyrol unsigned int *sleep_ms)
25431c24c1eSJean-Baptiste Maneyrol {
25531c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *oldconf = &st->conf.gyro;
25631c24c1eSJean-Baptiste Maneyrol unsigned int val;
25731c24c1eSJean-Baptiste Maneyrol int ret;
25831c24c1eSJean-Baptiste Maneyrol
25931c24c1eSJean-Baptiste Maneyrol /* sanitize missing values with current values */
26031c24c1eSJean-Baptiste Maneyrol if (conf->mode < 0)
26131c24c1eSJean-Baptiste Maneyrol conf->mode = oldconf->mode;
26231c24c1eSJean-Baptiste Maneyrol if (conf->fs < 0)
26331c24c1eSJean-Baptiste Maneyrol conf->fs = oldconf->fs;
26431c24c1eSJean-Baptiste Maneyrol if (conf->odr < 0)
26531c24c1eSJean-Baptiste Maneyrol conf->odr = oldconf->odr;
26631c24c1eSJean-Baptiste Maneyrol if (conf->filter < 0)
26731c24c1eSJean-Baptiste Maneyrol conf->filter = oldconf->filter;
26831c24c1eSJean-Baptiste Maneyrol
26931c24c1eSJean-Baptiste Maneyrol /* set GYRO_CONFIG0 register (gyro fullscale & odr) */
27031c24c1eSJean-Baptiste Maneyrol if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
27131c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_CONFIG0_FS(conf->fs) |
27231c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_CONFIG0_ODR(conf->odr);
27331c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
27431c24c1eSJean-Baptiste Maneyrol if (ret)
27531c24c1eSJean-Baptiste Maneyrol return ret;
27631c24c1eSJean-Baptiste Maneyrol oldconf->fs = conf->fs;
27731c24c1eSJean-Baptiste Maneyrol oldconf->odr = conf->odr;
27831c24c1eSJean-Baptiste Maneyrol }
27931c24c1eSJean-Baptiste Maneyrol
28031c24c1eSJean-Baptiste Maneyrol /* set GYRO_ACCEL_CONFIG0 register (gyro filter) */
28131c24c1eSJean-Baptiste Maneyrol if (conf->filter != oldconf->filter) {
28231c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(st->conf.accel.filter) |
28331c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->filter);
28431c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
28531c24c1eSJean-Baptiste Maneyrol if (ret)
28631c24c1eSJean-Baptiste Maneyrol return ret;
28731c24c1eSJean-Baptiste Maneyrol oldconf->filter = conf->filter;
28831c24c1eSJean-Baptiste Maneyrol }
28931c24c1eSJean-Baptiste Maneyrol
29031c24c1eSJean-Baptiste Maneyrol /* set PWR_MGMT0 register (gyro sensor mode) */
29131c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
29231c24c1eSJean-Baptiste Maneyrol st->conf.temp_en, sleep_ms);
29331c24c1eSJean-Baptiste Maneyrol
29431c24c1eSJean-Baptiste Maneyrol return 0;
29531c24c1eSJean-Baptiste Maneyrol }
29631c24c1eSJean-Baptiste Maneyrol
inv_icm42600_set_temp_conf(struct inv_icm42600_state * st,bool enable,unsigned int * sleep_ms)29731c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
29831c24c1eSJean-Baptiste Maneyrol unsigned int *sleep_ms)
29931c24c1eSJean-Baptiste Maneyrol {
30031c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode,
30131c24c1eSJean-Baptiste Maneyrol st->conf.accel.mode, enable,
30231c24c1eSJean-Baptiste Maneyrol sleep_ms);
30331c24c1eSJean-Baptiste Maneyrol }
30431c24c1eSJean-Baptiste Maneyrol
inv_icm42600_debugfs_reg(struct iio_dev * indio_dev,unsigned int reg,unsigned int writeval,unsigned int * readval)30531c24c1eSJean-Baptiste Maneyrol int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
30631c24c1eSJean-Baptiste Maneyrol unsigned int writeval, unsigned int *readval)
30731c24c1eSJean-Baptiste Maneyrol {
30831c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
30931c24c1eSJean-Baptiste Maneyrol int ret;
31031c24c1eSJean-Baptiste Maneyrol
31131c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock);
31231c24c1eSJean-Baptiste Maneyrol
31331c24c1eSJean-Baptiste Maneyrol if (readval)
31431c24c1eSJean-Baptiste Maneyrol ret = regmap_read(st->map, reg, readval);
31531c24c1eSJean-Baptiste Maneyrol else
31631c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, reg, writeval);
31731c24c1eSJean-Baptiste Maneyrol
31831c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock);
31931c24c1eSJean-Baptiste Maneyrol
32031c24c1eSJean-Baptiste Maneyrol return ret;
32131c24c1eSJean-Baptiste Maneyrol }
32231c24c1eSJean-Baptiste Maneyrol
inv_icm42600_set_conf(struct inv_icm42600_state * st,const struct inv_icm42600_conf * conf)32331c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_set_conf(struct inv_icm42600_state *st,
32431c24c1eSJean-Baptiste Maneyrol const struct inv_icm42600_conf *conf)
32531c24c1eSJean-Baptiste Maneyrol {
32631c24c1eSJean-Baptiste Maneyrol unsigned int val;
32731c24c1eSJean-Baptiste Maneyrol int ret;
32831c24c1eSJean-Baptiste Maneyrol
32931c24c1eSJean-Baptiste Maneyrol /* set PWR_MGMT0 register (gyro & accel sensor mode, temp enabled) */
33031c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_PWR_MGMT0_GYRO(conf->gyro.mode) |
33131c24c1eSJean-Baptiste Maneyrol INV_ICM42600_PWR_MGMT0_ACCEL(conf->accel.mode);
33231c24c1eSJean-Baptiste Maneyrol if (!conf->temp_en)
33331c24c1eSJean-Baptiste Maneyrol val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
33431c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
33531c24c1eSJean-Baptiste Maneyrol if (ret)
33631c24c1eSJean-Baptiste Maneyrol return ret;
33731c24c1eSJean-Baptiste Maneyrol
33831c24c1eSJean-Baptiste Maneyrol /* set GYRO_CONFIG0 register (gyro fullscale & odr) */
33931c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_CONFIG0_FS(conf->gyro.fs) |
34031c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_CONFIG0_ODR(conf->gyro.odr);
34131c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
34231c24c1eSJean-Baptiste Maneyrol if (ret)
34331c24c1eSJean-Baptiste Maneyrol return ret;
34431c24c1eSJean-Baptiste Maneyrol
34531c24c1eSJean-Baptiste Maneyrol /* set ACCEL_CONFIG0 register (accel fullscale & odr) */
34631c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->accel.fs) |
34731c24c1eSJean-Baptiste Maneyrol INV_ICM42600_ACCEL_CONFIG0_ODR(conf->accel.odr);
34831c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
34931c24c1eSJean-Baptiste Maneyrol if (ret)
35031c24c1eSJean-Baptiste Maneyrol return ret;
35131c24c1eSJean-Baptiste Maneyrol
35231c24c1eSJean-Baptiste Maneyrol /* set GYRO_ACCEL_CONFIG0 register (gyro & accel filters) */
35331c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->accel.filter) |
35431c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->gyro.filter);
35531c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
35631c24c1eSJean-Baptiste Maneyrol if (ret)
35731c24c1eSJean-Baptiste Maneyrol return ret;
35831c24c1eSJean-Baptiste Maneyrol
35931c24c1eSJean-Baptiste Maneyrol /* update internal conf */
36031c24c1eSJean-Baptiste Maneyrol st->conf = *conf;
36131c24c1eSJean-Baptiste Maneyrol
36231c24c1eSJean-Baptiste Maneyrol return 0;
36331c24c1eSJean-Baptiste Maneyrol }
36431c24c1eSJean-Baptiste Maneyrol
36531c24c1eSJean-Baptiste Maneyrol /**
36631c24c1eSJean-Baptiste Maneyrol * inv_icm42600_setup() - check and setup chip
36731c24c1eSJean-Baptiste Maneyrol * @st: driver internal state
36831c24c1eSJean-Baptiste Maneyrol * @bus_setup: callback for setting up bus specific registers
36931c24c1eSJean-Baptiste Maneyrol *
37031c24c1eSJean-Baptiste Maneyrol * Returns 0 on success, a negative error code otherwise.
37131c24c1eSJean-Baptiste Maneyrol */
inv_icm42600_setup(struct inv_icm42600_state * st,inv_icm42600_bus_setup bus_setup)37231c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_setup(struct inv_icm42600_state *st,
37331c24c1eSJean-Baptiste Maneyrol inv_icm42600_bus_setup bus_setup)
37431c24c1eSJean-Baptiste Maneyrol {
37531c24c1eSJean-Baptiste Maneyrol const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip];
37631c24c1eSJean-Baptiste Maneyrol const struct device *dev = regmap_get_device(st->map);
37731c24c1eSJean-Baptiste Maneyrol unsigned int val;
37831c24c1eSJean-Baptiste Maneyrol int ret;
37931c24c1eSJean-Baptiste Maneyrol
38031c24c1eSJean-Baptiste Maneyrol /* check chip self-identification value */
38131c24c1eSJean-Baptiste Maneyrol ret = regmap_read(st->map, INV_ICM42600_REG_WHOAMI, &val);
38231c24c1eSJean-Baptiste Maneyrol if (ret)
38331c24c1eSJean-Baptiste Maneyrol return ret;
38431c24c1eSJean-Baptiste Maneyrol if (val != hw->whoami) {
38531c24c1eSJean-Baptiste Maneyrol dev_err(dev, "invalid whoami %#02x expected %#02x (%s)\n",
38631c24c1eSJean-Baptiste Maneyrol val, hw->whoami, hw->name);
38731c24c1eSJean-Baptiste Maneyrol return -ENODEV;
38831c24c1eSJean-Baptiste Maneyrol }
38931c24c1eSJean-Baptiste Maneyrol st->name = hw->name;
39031c24c1eSJean-Baptiste Maneyrol
39131c24c1eSJean-Baptiste Maneyrol /* reset to make sure previous state are not there */
39231c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_DEVICE_CONFIG,
39331c24c1eSJean-Baptiste Maneyrol INV_ICM42600_DEVICE_CONFIG_SOFT_RESET);
39431c24c1eSJean-Baptiste Maneyrol if (ret)
39531c24c1eSJean-Baptiste Maneyrol return ret;
39631c24c1eSJean-Baptiste Maneyrol msleep(INV_ICM42600_RESET_TIME_MS);
39731c24c1eSJean-Baptiste Maneyrol
39831c24c1eSJean-Baptiste Maneyrol ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &val);
39931c24c1eSJean-Baptiste Maneyrol if (ret)
40031c24c1eSJean-Baptiste Maneyrol return ret;
40131c24c1eSJean-Baptiste Maneyrol if (!(val & INV_ICM42600_INT_STATUS_RESET_DONE)) {
40231c24c1eSJean-Baptiste Maneyrol dev_err(dev, "reset error, reset done bit not set\n");
40331c24c1eSJean-Baptiste Maneyrol return -ENODEV;
40431c24c1eSJean-Baptiste Maneyrol }
40531c24c1eSJean-Baptiste Maneyrol
40631c24c1eSJean-Baptiste Maneyrol /* set chip bus configuration */
40731c24c1eSJean-Baptiste Maneyrol ret = bus_setup(st);
40831c24c1eSJean-Baptiste Maneyrol if (ret)
40931c24c1eSJean-Baptiste Maneyrol return ret;
41031c24c1eSJean-Baptiste Maneyrol
41131c24c1eSJean-Baptiste Maneyrol /* sensor data in big-endian (default) */
41231c24c1eSJean-Baptiste Maneyrol ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
41331c24c1eSJean-Baptiste Maneyrol INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN,
41431c24c1eSJean-Baptiste Maneyrol INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
41531c24c1eSJean-Baptiste Maneyrol if (ret)
41631c24c1eSJean-Baptiste Maneyrol return ret;
41731c24c1eSJean-Baptiste Maneyrol
41831c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_conf(st, hw->conf);
41931c24c1eSJean-Baptiste Maneyrol }
42031c24c1eSJean-Baptiste Maneyrol
inv_icm42600_irq_timestamp(int irq,void * _data)421ec74ae9fSJean-Baptiste Maneyrol static irqreturn_t inv_icm42600_irq_timestamp(int irq, void *_data)
422ec74ae9fSJean-Baptiste Maneyrol {
423ec74ae9fSJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data;
424ec74ae9fSJean-Baptiste Maneyrol
425ec74ae9fSJean-Baptiste Maneyrol st->timestamp.gyro = iio_get_time_ns(st->indio_gyro);
426ec74ae9fSJean-Baptiste Maneyrol st->timestamp.accel = iio_get_time_ns(st->indio_accel);
427ec74ae9fSJean-Baptiste Maneyrol
428ec74ae9fSJean-Baptiste Maneyrol return IRQ_WAKE_THREAD;
429ec74ae9fSJean-Baptiste Maneyrol }
430ec74ae9fSJean-Baptiste Maneyrol
inv_icm42600_irq_handler(int irq,void * _data)431e5efa104SJean-Baptiste Maneyrol static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
432e5efa104SJean-Baptiste Maneyrol {
433e5efa104SJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data;
434e5efa104SJean-Baptiste Maneyrol struct device *dev = regmap_get_device(st->map);
435e5efa104SJean-Baptiste Maneyrol unsigned int status;
436e5efa104SJean-Baptiste Maneyrol int ret;
437e5efa104SJean-Baptiste Maneyrol
438e5efa104SJean-Baptiste Maneyrol mutex_lock(&st->lock);
439e5efa104SJean-Baptiste Maneyrol
440e5efa104SJean-Baptiste Maneyrol ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &status);
441e5efa104SJean-Baptiste Maneyrol if (ret)
442e5efa104SJean-Baptiste Maneyrol goto out_unlock;
443e5efa104SJean-Baptiste Maneyrol
444e5efa104SJean-Baptiste Maneyrol /* FIFO full */
445e5efa104SJean-Baptiste Maneyrol if (status & INV_ICM42600_INT_STATUS_FIFO_FULL)
446e5efa104SJean-Baptiste Maneyrol dev_warn(dev, "FIFO full data lost!\n");
447e5efa104SJean-Baptiste Maneyrol
4487f85e42aSJean-Baptiste Maneyrol /* FIFO threshold reached */
4497f85e42aSJean-Baptiste Maneyrol if (status & INV_ICM42600_INT_STATUS_FIFO_THS) {
4507f85e42aSJean-Baptiste Maneyrol ret = inv_icm42600_buffer_fifo_read(st, 0);
4517f85e42aSJean-Baptiste Maneyrol if (ret) {
4527f85e42aSJean-Baptiste Maneyrol dev_err(dev, "FIFO read error %d\n", ret);
4537f85e42aSJean-Baptiste Maneyrol goto out_unlock;
4547f85e42aSJean-Baptiste Maneyrol }
4557f85e42aSJean-Baptiste Maneyrol ret = inv_icm42600_buffer_fifo_parse(st);
4567f85e42aSJean-Baptiste Maneyrol if (ret)
4577f85e42aSJean-Baptiste Maneyrol dev_err(dev, "FIFO parsing error %d\n", ret);
4587f85e42aSJean-Baptiste Maneyrol }
4597f85e42aSJean-Baptiste Maneyrol
460e5efa104SJean-Baptiste Maneyrol out_unlock:
461e5efa104SJean-Baptiste Maneyrol mutex_unlock(&st->lock);
462e5efa104SJean-Baptiste Maneyrol return IRQ_HANDLED;
463e5efa104SJean-Baptiste Maneyrol }
464e5efa104SJean-Baptiste Maneyrol
465e5efa104SJean-Baptiste Maneyrol /**
466e5efa104SJean-Baptiste Maneyrol * inv_icm42600_irq_init() - initialize int pin and interrupt handler
467e5efa104SJean-Baptiste Maneyrol * @st: driver internal state
468e5efa104SJean-Baptiste Maneyrol * @irq: irq number
469e5efa104SJean-Baptiste Maneyrol * @irq_type: irq trigger type
470e5efa104SJean-Baptiste Maneyrol * @open_drain: true if irq is open drain, false for push-pull
471e5efa104SJean-Baptiste Maneyrol *
472e5efa104SJean-Baptiste Maneyrol * Returns 0 on success, a negative error code otherwise.
473e5efa104SJean-Baptiste Maneyrol */
inv_icm42600_irq_init(struct inv_icm42600_state * st,int irq,int irq_type,bool open_drain)474e5efa104SJean-Baptiste Maneyrol static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
475e5efa104SJean-Baptiste Maneyrol int irq_type, bool open_drain)
476e5efa104SJean-Baptiste Maneyrol {
477e5efa104SJean-Baptiste Maneyrol struct device *dev = regmap_get_device(st->map);
478e5efa104SJean-Baptiste Maneyrol unsigned int val;
479e5efa104SJean-Baptiste Maneyrol int ret;
480e5efa104SJean-Baptiste Maneyrol
481e5efa104SJean-Baptiste Maneyrol /* configure INT1 interrupt: default is active low on edge */
482e5efa104SJean-Baptiste Maneyrol switch (irq_type) {
483e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_RISING:
484e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_HIGH:
485e5efa104SJean-Baptiste Maneyrol val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH;
486e5efa104SJean-Baptiste Maneyrol break;
487e5efa104SJean-Baptiste Maneyrol default:
488e5efa104SJean-Baptiste Maneyrol val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW;
489e5efa104SJean-Baptiste Maneyrol break;
490e5efa104SJean-Baptiste Maneyrol }
491e5efa104SJean-Baptiste Maneyrol
492e5efa104SJean-Baptiste Maneyrol switch (irq_type) {
493e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_LOW:
494e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_HIGH:
495e5efa104SJean-Baptiste Maneyrol val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED;
496e5efa104SJean-Baptiste Maneyrol break;
497e5efa104SJean-Baptiste Maneyrol default:
498e5efa104SJean-Baptiste Maneyrol break;
499e5efa104SJean-Baptiste Maneyrol }
500e5efa104SJean-Baptiste Maneyrol
501e5efa104SJean-Baptiste Maneyrol if (!open_drain)
502e5efa104SJean-Baptiste Maneyrol val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL;
503e5efa104SJean-Baptiste Maneyrol
504e5efa104SJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val);
505e5efa104SJean-Baptiste Maneyrol if (ret)
506e5efa104SJean-Baptiste Maneyrol return ret;
507e5efa104SJean-Baptiste Maneyrol
508e5efa104SJean-Baptiste Maneyrol /* Deassert async reset for proper INT pin operation (cf datasheet) */
509e5efa104SJean-Baptiste Maneyrol ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
510e5efa104SJean-Baptiste Maneyrol INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0);
511e5efa104SJean-Baptiste Maneyrol if (ret)
512e5efa104SJean-Baptiste Maneyrol return ret;
513e5efa104SJean-Baptiste Maneyrol
514ec74ae9fSJean-Baptiste Maneyrol return devm_request_threaded_irq(dev, irq, inv_icm42600_irq_timestamp,
515e5efa104SJean-Baptiste Maneyrol inv_icm42600_irq_handler, irq_type,
516e5efa104SJean-Baptiste Maneyrol "inv_icm42600", st);
517e5efa104SJean-Baptiste Maneyrol }
518e5efa104SJean-Baptiste Maneyrol
inv_icm42600_timestamp_setup(struct inv_icm42600_state * st)5196e9f2d83SJean-Baptiste Maneyrol static int inv_icm42600_timestamp_setup(struct inv_icm42600_state *st)
5206e9f2d83SJean-Baptiste Maneyrol {
5216e9f2d83SJean-Baptiste Maneyrol unsigned int val;
5226e9f2d83SJean-Baptiste Maneyrol
5236e9f2d83SJean-Baptiste Maneyrol /* enable timestamp register */
5246e9f2d83SJean-Baptiste Maneyrol val = INV_ICM42600_TMST_CONFIG_TMST_TO_REGS_EN |
5256e9f2d83SJean-Baptiste Maneyrol INV_ICM42600_TMST_CONFIG_TMST_EN;
5266e9f2d83SJean-Baptiste Maneyrol return regmap_update_bits(st->map, INV_ICM42600_REG_TMST_CONFIG,
5276e9f2d83SJean-Baptiste Maneyrol INV_ICM42600_TMST_CONFIG_MASK, val);
5286e9f2d83SJean-Baptiste Maneyrol }
5296e9f2d83SJean-Baptiste Maneyrol
inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state * st)53031c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st)
53131c24c1eSJean-Baptiste Maneyrol {
53231c24c1eSJean-Baptiste Maneyrol int ret;
53331c24c1eSJean-Baptiste Maneyrol
53431c24c1eSJean-Baptiste Maneyrol ret = regulator_enable(st->vddio_supply);
53531c24c1eSJean-Baptiste Maneyrol if (ret)
53631c24c1eSJean-Baptiste Maneyrol return ret;
53731c24c1eSJean-Baptiste Maneyrol
53831c24c1eSJean-Baptiste Maneyrol /* wait a little for supply ramp */
53931c24c1eSJean-Baptiste Maneyrol usleep_range(3000, 4000);
54031c24c1eSJean-Baptiste Maneyrol
54131c24c1eSJean-Baptiste Maneyrol return 0;
54231c24c1eSJean-Baptiste Maneyrol }
54331c24c1eSJean-Baptiste Maneyrol
inv_icm42600_disable_vdd_reg(void * _data)54431c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_vdd_reg(void *_data)
54531c24c1eSJean-Baptiste Maneyrol {
54631c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data;
54731c24c1eSJean-Baptiste Maneyrol const struct device *dev = regmap_get_device(st->map);
54831c24c1eSJean-Baptiste Maneyrol int ret;
54931c24c1eSJean-Baptiste Maneyrol
55031c24c1eSJean-Baptiste Maneyrol ret = regulator_disable(st->vdd_supply);
55131c24c1eSJean-Baptiste Maneyrol if (ret)
55231c24c1eSJean-Baptiste Maneyrol dev_err(dev, "failed to disable vdd error %d\n", ret);
55331c24c1eSJean-Baptiste Maneyrol }
55431c24c1eSJean-Baptiste Maneyrol
inv_icm42600_disable_vddio_reg(void * _data)55531c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_vddio_reg(void *_data)
55631c24c1eSJean-Baptiste Maneyrol {
55731c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data;
55831c24c1eSJean-Baptiste Maneyrol const struct device *dev = regmap_get_device(st->map);
55931c24c1eSJean-Baptiste Maneyrol int ret;
56031c24c1eSJean-Baptiste Maneyrol
56131c24c1eSJean-Baptiste Maneyrol ret = regulator_disable(st->vddio_supply);
56231c24c1eSJean-Baptiste Maneyrol if (ret)
56331c24c1eSJean-Baptiste Maneyrol dev_err(dev, "failed to disable vddio error %d\n", ret);
56431c24c1eSJean-Baptiste Maneyrol }
56531c24c1eSJean-Baptiste Maneyrol
inv_icm42600_disable_pm(void * _data)56631c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_pm(void *_data)
56731c24c1eSJean-Baptiste Maneyrol {
56831c24c1eSJean-Baptiste Maneyrol struct device *dev = _data;
56931c24c1eSJean-Baptiste Maneyrol
57031c24c1eSJean-Baptiste Maneyrol pm_runtime_put_sync(dev);
57131c24c1eSJean-Baptiste Maneyrol pm_runtime_disable(dev);
57231c24c1eSJean-Baptiste Maneyrol }
57331c24c1eSJean-Baptiste Maneyrol
inv_icm42600_core_probe(struct regmap * regmap,int chip,int irq,inv_icm42600_bus_setup bus_setup)574e5efa104SJean-Baptiste Maneyrol int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq,
57531c24c1eSJean-Baptiste Maneyrol inv_icm42600_bus_setup bus_setup)
57631c24c1eSJean-Baptiste Maneyrol {
57731c24c1eSJean-Baptiste Maneyrol struct device *dev = regmap_get_device(regmap);
57831c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st;
579e5efa104SJean-Baptiste Maneyrol struct irq_data *irq_desc;
580e5efa104SJean-Baptiste Maneyrol int irq_type;
581e5efa104SJean-Baptiste Maneyrol bool open_drain;
58231c24c1eSJean-Baptiste Maneyrol int ret;
58331c24c1eSJean-Baptiste Maneyrol
584106b391eSJean-Baptiste Maneyrol if (chip <= INV_CHIP_INVALID || chip >= INV_CHIP_NB) {
58531c24c1eSJean-Baptiste Maneyrol dev_err(dev, "invalid chip = %d\n", chip);
58631c24c1eSJean-Baptiste Maneyrol return -ENODEV;
58731c24c1eSJean-Baptiste Maneyrol }
58831c24c1eSJean-Baptiste Maneyrol
589e5efa104SJean-Baptiste Maneyrol /* get irq properties, set trigger falling by default */
590e5efa104SJean-Baptiste Maneyrol irq_desc = irq_get_irq_data(irq);
591e5efa104SJean-Baptiste Maneyrol if (!irq_desc) {
592e5efa104SJean-Baptiste Maneyrol dev_err(dev, "could not find IRQ %d\n", irq);
593e5efa104SJean-Baptiste Maneyrol return -EINVAL;
594e5efa104SJean-Baptiste Maneyrol }
595e5efa104SJean-Baptiste Maneyrol
596e5efa104SJean-Baptiste Maneyrol irq_type = irqd_get_trigger_type(irq_desc);
597e5efa104SJean-Baptiste Maneyrol if (!irq_type)
598e5efa104SJean-Baptiste Maneyrol irq_type = IRQF_TRIGGER_FALLING;
599e5efa104SJean-Baptiste Maneyrol
600e5efa104SJean-Baptiste Maneyrol open_drain = device_property_read_bool(dev, "drive-open-drain");
601e5efa104SJean-Baptiste Maneyrol
60231c24c1eSJean-Baptiste Maneyrol st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
60331c24c1eSJean-Baptiste Maneyrol if (!st)
60431c24c1eSJean-Baptiste Maneyrol return -ENOMEM;
60531c24c1eSJean-Baptiste Maneyrol
60631c24c1eSJean-Baptiste Maneyrol dev_set_drvdata(dev, st);
60731c24c1eSJean-Baptiste Maneyrol mutex_init(&st->lock);
60831c24c1eSJean-Baptiste Maneyrol st->chip = chip;
60931c24c1eSJean-Baptiste Maneyrol st->map = regmap;
61031c24c1eSJean-Baptiste Maneyrol
611b892770aSAndy Shevchenko ret = iio_read_mount_matrix(dev, &st->orientation);
61231c24c1eSJean-Baptiste Maneyrol if (ret) {
61331c24c1eSJean-Baptiste Maneyrol dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
61431c24c1eSJean-Baptiste Maneyrol return ret;
61531c24c1eSJean-Baptiste Maneyrol }
61631c24c1eSJean-Baptiste Maneyrol
61731c24c1eSJean-Baptiste Maneyrol st->vdd_supply = devm_regulator_get(dev, "vdd");
61831c24c1eSJean-Baptiste Maneyrol if (IS_ERR(st->vdd_supply))
61931c24c1eSJean-Baptiste Maneyrol return PTR_ERR(st->vdd_supply);
62031c24c1eSJean-Baptiste Maneyrol
62131c24c1eSJean-Baptiste Maneyrol st->vddio_supply = devm_regulator_get(dev, "vddio");
62231c24c1eSJean-Baptiste Maneyrol if (IS_ERR(st->vddio_supply))
62331c24c1eSJean-Baptiste Maneyrol return PTR_ERR(st->vddio_supply);
62431c24c1eSJean-Baptiste Maneyrol
62531c24c1eSJean-Baptiste Maneyrol ret = regulator_enable(st->vdd_supply);
62631c24c1eSJean-Baptiste Maneyrol if (ret)
62731c24c1eSJean-Baptiste Maneyrol return ret;
62831c24c1eSJean-Baptiste Maneyrol msleep(INV_ICM42600_POWER_UP_TIME_MS);
62931c24c1eSJean-Baptiste Maneyrol
63031c24c1eSJean-Baptiste Maneyrol ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vdd_reg, st);
63131c24c1eSJean-Baptiste Maneyrol if (ret)
63231c24c1eSJean-Baptiste Maneyrol return ret;
63331c24c1eSJean-Baptiste Maneyrol
63431c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_enable_regulator_vddio(st);
63531c24c1eSJean-Baptiste Maneyrol if (ret)
63631c24c1eSJean-Baptiste Maneyrol return ret;
63731c24c1eSJean-Baptiste Maneyrol
63831c24c1eSJean-Baptiste Maneyrol ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vddio_reg, st);
63931c24c1eSJean-Baptiste Maneyrol if (ret)
64031c24c1eSJean-Baptiste Maneyrol return ret;
64131c24c1eSJean-Baptiste Maneyrol
64231c24c1eSJean-Baptiste Maneyrol /* setup chip registers */
64331c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_setup(st, bus_setup);
64431c24c1eSJean-Baptiste Maneyrol if (ret)
64531c24c1eSJean-Baptiste Maneyrol return ret;
64631c24c1eSJean-Baptiste Maneyrol
647ec74ae9fSJean-Baptiste Maneyrol ret = inv_icm42600_timestamp_setup(st);
648ec74ae9fSJean-Baptiste Maneyrol if (ret)
649ec74ae9fSJean-Baptiste Maneyrol return ret;
650ec74ae9fSJean-Baptiste Maneyrol
6517f85e42aSJean-Baptiste Maneyrol ret = inv_icm42600_buffer_init(st);
6527f85e42aSJean-Baptiste Maneyrol if (ret)
6537f85e42aSJean-Baptiste Maneyrol return ret;
6547f85e42aSJean-Baptiste Maneyrol
655a095fadbSJean-Baptiste Maneyrol st->indio_gyro = inv_icm42600_gyro_init(st);
656a095fadbSJean-Baptiste Maneyrol if (IS_ERR(st->indio_gyro))
657a095fadbSJean-Baptiste Maneyrol return PTR_ERR(st->indio_gyro);
658a095fadbSJean-Baptiste Maneyrol
659a47c1cdcSJean-Baptiste Maneyrol st->indio_accel = inv_icm42600_accel_init(st);
660a47c1cdcSJean-Baptiste Maneyrol if (IS_ERR(st->indio_accel))
661a47c1cdcSJean-Baptiste Maneyrol return PTR_ERR(st->indio_accel);
662a47c1cdcSJean-Baptiste Maneyrol
663e5efa104SJean-Baptiste Maneyrol ret = inv_icm42600_irq_init(st, irq, irq_type, open_drain);
664e5efa104SJean-Baptiste Maneyrol if (ret)
665e5efa104SJean-Baptiste Maneyrol return ret;
666e5efa104SJean-Baptiste Maneyrol
66731c24c1eSJean-Baptiste Maneyrol /* setup runtime power management */
66831c24c1eSJean-Baptiste Maneyrol ret = pm_runtime_set_active(dev);
66931c24c1eSJean-Baptiste Maneyrol if (ret)
67031c24c1eSJean-Baptiste Maneyrol return ret;
67131c24c1eSJean-Baptiste Maneyrol pm_runtime_get_noresume(dev);
67231c24c1eSJean-Baptiste Maneyrol pm_runtime_enable(dev);
67331c24c1eSJean-Baptiste Maneyrol pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS);
67431c24c1eSJean-Baptiste Maneyrol pm_runtime_use_autosuspend(dev);
67531c24c1eSJean-Baptiste Maneyrol pm_runtime_put(dev);
67631c24c1eSJean-Baptiste Maneyrol
67731c24c1eSJean-Baptiste Maneyrol return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev);
67831c24c1eSJean-Baptiste Maneyrol }
679ef5a5ef2SJonathan Cameron EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, IIO_ICM42600);
68031c24c1eSJean-Baptiste Maneyrol
68131c24c1eSJean-Baptiste Maneyrol /*
68231c24c1eSJean-Baptiste Maneyrol * Suspend saves sensors state and turns everything off.
68331c24c1eSJean-Baptiste Maneyrol * Check first if runtime suspend has not already done the job.
68431c24c1eSJean-Baptiste Maneyrol */
inv_icm42600_suspend(struct device * dev)685ef5a5ef2SJonathan Cameron static int inv_icm42600_suspend(struct device *dev)
68631c24c1eSJean-Baptiste Maneyrol {
68731c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev);
68831c24c1eSJean-Baptiste Maneyrol int ret;
68931c24c1eSJean-Baptiste Maneyrol
69031c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock);
69131c24c1eSJean-Baptiste Maneyrol
69231c24c1eSJean-Baptiste Maneyrol st->suspended.gyro = st->conf.gyro.mode;
69331c24c1eSJean-Baptiste Maneyrol st->suspended.accel = st->conf.accel.mode;
69431c24c1eSJean-Baptiste Maneyrol st->suspended.temp = st->conf.temp_en;
69531c24c1eSJean-Baptiste Maneyrol if (pm_runtime_suspended(dev)) {
69631c24c1eSJean-Baptiste Maneyrol ret = 0;
69731c24c1eSJean-Baptiste Maneyrol goto out_unlock;
69831c24c1eSJean-Baptiste Maneyrol }
69931c24c1eSJean-Baptiste Maneyrol
7007f85e42aSJean-Baptiste Maneyrol /* disable FIFO data streaming */
7017f85e42aSJean-Baptiste Maneyrol if (st->fifo.on) {
7027f85e42aSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
7037f85e42aSJean-Baptiste Maneyrol INV_ICM42600_FIFO_CONFIG_BYPASS);
7047f85e42aSJean-Baptiste Maneyrol if (ret)
7057f85e42aSJean-Baptiste Maneyrol goto out_unlock;
7067f85e42aSJean-Baptiste Maneyrol }
7077f85e42aSJean-Baptiste Maneyrol
70831c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
70931c24c1eSJean-Baptiste Maneyrol INV_ICM42600_SENSOR_MODE_OFF, false,
71031c24c1eSJean-Baptiste Maneyrol NULL);
71131c24c1eSJean-Baptiste Maneyrol if (ret)
71231c24c1eSJean-Baptiste Maneyrol goto out_unlock;
71331c24c1eSJean-Baptiste Maneyrol
71431c24c1eSJean-Baptiste Maneyrol regulator_disable(st->vddio_supply);
71531c24c1eSJean-Baptiste Maneyrol
71631c24c1eSJean-Baptiste Maneyrol out_unlock:
71731c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock);
71831c24c1eSJean-Baptiste Maneyrol return ret;
71931c24c1eSJean-Baptiste Maneyrol }
72031c24c1eSJean-Baptiste Maneyrol
72131c24c1eSJean-Baptiste Maneyrol /*
72231c24c1eSJean-Baptiste Maneyrol * System resume gets the system back on and restores the sensors state.
72331c24c1eSJean-Baptiste Maneyrol * Manually put runtime power management in system active state.
72431c24c1eSJean-Baptiste Maneyrol */
inv_icm42600_resume(struct device * dev)725ef5a5ef2SJonathan Cameron static int inv_icm42600_resume(struct device *dev)
72631c24c1eSJean-Baptiste Maneyrol {
72731c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev);
72831c24c1eSJean-Baptiste Maneyrol int ret;
72931c24c1eSJean-Baptiste Maneyrol
73031c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock);
73131c24c1eSJean-Baptiste Maneyrol
73231c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_enable_regulator_vddio(st);
73331c24c1eSJean-Baptiste Maneyrol if (ret)
73431c24c1eSJean-Baptiste Maneyrol goto out_unlock;
73531c24c1eSJean-Baptiste Maneyrol
73631c24c1eSJean-Baptiste Maneyrol pm_runtime_disable(dev);
73731c24c1eSJean-Baptiste Maneyrol pm_runtime_set_active(dev);
73831c24c1eSJean-Baptiste Maneyrol pm_runtime_enable(dev);
73931c24c1eSJean-Baptiste Maneyrol
74031c24c1eSJean-Baptiste Maneyrol /* restore sensors state */
74131c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_set_pwr_mgmt0(st, st->suspended.gyro,
74231c24c1eSJean-Baptiste Maneyrol st->suspended.accel,
74331c24c1eSJean-Baptiste Maneyrol st->suspended.temp, NULL);
74431c24c1eSJean-Baptiste Maneyrol if (ret)
74531c24c1eSJean-Baptiste Maneyrol goto out_unlock;
74631c24c1eSJean-Baptiste Maneyrol
7477f85e42aSJean-Baptiste Maneyrol /* restore FIFO data streaming */
7487f85e42aSJean-Baptiste Maneyrol if (st->fifo.on)
7497f85e42aSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG,
7507f85e42aSJean-Baptiste Maneyrol INV_ICM42600_FIFO_CONFIG_STREAM);
7517f85e42aSJean-Baptiste Maneyrol
75231c24c1eSJean-Baptiste Maneyrol out_unlock:
75331c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock);
75431c24c1eSJean-Baptiste Maneyrol return ret;
75531c24c1eSJean-Baptiste Maneyrol }
75631c24c1eSJean-Baptiste Maneyrol
75731c24c1eSJean-Baptiste Maneyrol /* Runtime suspend will turn off sensors that are enabled by iio devices. */
inv_icm42600_runtime_suspend(struct device * dev)758ef5a5ef2SJonathan Cameron static int inv_icm42600_runtime_suspend(struct device *dev)
75931c24c1eSJean-Baptiste Maneyrol {
76031c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev);
76131c24c1eSJean-Baptiste Maneyrol int ret;
76231c24c1eSJean-Baptiste Maneyrol
76331c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock);
76431c24c1eSJean-Baptiste Maneyrol
76531c24c1eSJean-Baptiste Maneyrol /* disable all sensors */
76631c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
76731c24c1eSJean-Baptiste Maneyrol INV_ICM42600_SENSOR_MODE_OFF, false,
76831c24c1eSJean-Baptiste Maneyrol NULL);
76931c24c1eSJean-Baptiste Maneyrol if (ret)
77031c24c1eSJean-Baptiste Maneyrol goto error_unlock;
77131c24c1eSJean-Baptiste Maneyrol
77231c24c1eSJean-Baptiste Maneyrol regulator_disable(st->vddio_supply);
77331c24c1eSJean-Baptiste Maneyrol
77431c24c1eSJean-Baptiste Maneyrol error_unlock:
77531c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock);
77631c24c1eSJean-Baptiste Maneyrol return ret;
77731c24c1eSJean-Baptiste Maneyrol }
77831c24c1eSJean-Baptiste Maneyrol
77931c24c1eSJean-Baptiste Maneyrol /* Sensors are enabled by iio devices, no need to turn them back on here. */
inv_icm42600_runtime_resume(struct device * dev)780ef5a5ef2SJonathan Cameron static int inv_icm42600_runtime_resume(struct device *dev)
78131c24c1eSJean-Baptiste Maneyrol {
78231c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev);
78331c24c1eSJean-Baptiste Maneyrol int ret;
78431c24c1eSJean-Baptiste Maneyrol
78531c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock);
78631c24c1eSJean-Baptiste Maneyrol
78731c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_enable_regulator_vddio(st);
78831c24c1eSJean-Baptiste Maneyrol
78931c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock);
79031c24c1eSJean-Baptiste Maneyrol return ret;
79131c24c1eSJean-Baptiste Maneyrol }
79231c24c1eSJean-Baptiste Maneyrol
793ef5a5ef2SJonathan Cameron EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42600_pm_ops, IIO_ICM42600) = {
794ef5a5ef2SJonathan Cameron SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
795ef5a5ef2SJonathan Cameron RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
79631c24c1eSJean-Baptiste Maneyrol inv_icm42600_runtime_resume, NULL)
79731c24c1eSJean-Baptiste Maneyrol };
79831c24c1eSJean-Baptiste Maneyrol
79931c24c1eSJean-Baptiste Maneyrol MODULE_AUTHOR("InvenSense, Inc.");
80031c24c1eSJean-Baptiste Maneyrol MODULE_DESCRIPTION("InvenSense ICM-426xx device driver");
80131c24c1eSJean-Baptiste Maneyrol MODULE_LICENSE("GPL");
802*d99ff463SJean-Baptiste Maneyrol MODULE_IMPORT_NS(IIO_INV_SENSORS_TIMESTAMP);
803