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> 1831c24c1eSJean-Baptiste Maneyrol #include <linux/iio/iio.h> 1931c24c1eSJean-Baptiste Maneyrol 2031c24c1eSJean-Baptiste Maneyrol #include "inv_icm42600.h" 217f85e42aSJean-Baptiste Maneyrol #include "inv_icm42600_buffer.h" 22ec74ae9fSJean-Baptiste Maneyrol #include "inv_icm42600_timestamp.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 }; 4431c24c1eSJean-Baptiste Maneyrol EXPORT_SYMBOL_GPL(inv_icm42600_regmap_config); 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 }, 9031c24c1eSJean-Baptiste Maneyrol }; 9131c24c1eSJean-Baptiste Maneyrol 9231c24c1eSJean-Baptiste Maneyrol const struct iio_mount_matrix * 9331c24c1eSJean-Baptiste Maneyrol inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev, 9431c24c1eSJean-Baptiste Maneyrol const struct iio_chan_spec *chan) 9531c24c1eSJean-Baptiste Maneyrol { 9631c24c1eSJean-Baptiste Maneyrol const struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 9731c24c1eSJean-Baptiste Maneyrol 9831c24c1eSJean-Baptiste Maneyrol return &st->orientation; 9931c24c1eSJean-Baptiste Maneyrol } 10031c24c1eSJean-Baptiste Maneyrol 10131c24c1eSJean-Baptiste Maneyrol uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr) 10231c24c1eSJean-Baptiste Maneyrol { 10331c24c1eSJean-Baptiste Maneyrol static uint32_t odr_periods[INV_ICM42600_ODR_NB] = { 10431c24c1eSJean-Baptiste Maneyrol /* reserved values */ 10531c24c1eSJean-Baptiste Maneyrol 0, 0, 0, 10631c24c1eSJean-Baptiste Maneyrol /* 8kHz */ 10731c24c1eSJean-Baptiste Maneyrol 125000, 10831c24c1eSJean-Baptiste Maneyrol /* 4kHz */ 10931c24c1eSJean-Baptiste Maneyrol 250000, 11031c24c1eSJean-Baptiste Maneyrol /* 2kHz */ 11131c24c1eSJean-Baptiste Maneyrol 500000, 11231c24c1eSJean-Baptiste Maneyrol /* 1kHz */ 11331c24c1eSJean-Baptiste Maneyrol 1000000, 11431c24c1eSJean-Baptiste Maneyrol /* 200Hz */ 11531c24c1eSJean-Baptiste Maneyrol 5000000, 11631c24c1eSJean-Baptiste Maneyrol /* 100Hz */ 11731c24c1eSJean-Baptiste Maneyrol 10000000, 11831c24c1eSJean-Baptiste Maneyrol /* 50Hz */ 11931c24c1eSJean-Baptiste Maneyrol 20000000, 12031c24c1eSJean-Baptiste Maneyrol /* 25Hz */ 12131c24c1eSJean-Baptiste Maneyrol 40000000, 12231c24c1eSJean-Baptiste Maneyrol /* 12.5Hz */ 12331c24c1eSJean-Baptiste Maneyrol 80000000, 12431c24c1eSJean-Baptiste Maneyrol /* 6.25Hz */ 12531c24c1eSJean-Baptiste Maneyrol 160000000, 12631c24c1eSJean-Baptiste Maneyrol /* 3.125Hz */ 12731c24c1eSJean-Baptiste Maneyrol 320000000, 12831c24c1eSJean-Baptiste Maneyrol /* 1.5625Hz */ 12931c24c1eSJean-Baptiste Maneyrol 640000000, 13031c24c1eSJean-Baptiste Maneyrol /* 500Hz */ 13131c24c1eSJean-Baptiste Maneyrol 2000000, 13231c24c1eSJean-Baptiste Maneyrol }; 13331c24c1eSJean-Baptiste Maneyrol 13431c24c1eSJean-Baptiste Maneyrol return odr_periods[odr]; 13531c24c1eSJean-Baptiste Maneyrol } 13631c24c1eSJean-Baptiste Maneyrol 13731c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st, 13831c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode gyro, 13931c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode accel, 14031c24c1eSJean-Baptiste Maneyrol bool temp, unsigned int *sleep_ms) 14131c24c1eSJean-Baptiste Maneyrol { 14231c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode oldgyro = st->conf.gyro.mode; 14331c24c1eSJean-Baptiste Maneyrol enum inv_icm42600_sensor_mode oldaccel = st->conf.accel.mode; 14431c24c1eSJean-Baptiste Maneyrol bool oldtemp = st->conf.temp_en; 14531c24c1eSJean-Baptiste Maneyrol unsigned int sleepval; 14631c24c1eSJean-Baptiste Maneyrol unsigned int val; 14731c24c1eSJean-Baptiste Maneyrol int ret; 14831c24c1eSJean-Baptiste Maneyrol 14931c24c1eSJean-Baptiste Maneyrol /* if nothing changed, exit */ 15031c24c1eSJean-Baptiste Maneyrol if (gyro == oldgyro && accel == oldaccel && temp == oldtemp) 15131c24c1eSJean-Baptiste Maneyrol return 0; 15231c24c1eSJean-Baptiste Maneyrol 15331c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_PWR_MGMT0_GYRO(gyro) | 15431c24c1eSJean-Baptiste Maneyrol INV_ICM42600_PWR_MGMT0_ACCEL(accel); 15531c24c1eSJean-Baptiste Maneyrol if (!temp) 15631c24c1eSJean-Baptiste Maneyrol val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS; 15731c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val); 15831c24c1eSJean-Baptiste Maneyrol if (ret) 15931c24c1eSJean-Baptiste Maneyrol return ret; 16031c24c1eSJean-Baptiste Maneyrol 16131c24c1eSJean-Baptiste Maneyrol st->conf.gyro.mode = gyro; 16231c24c1eSJean-Baptiste Maneyrol st->conf.accel.mode = accel; 16331c24c1eSJean-Baptiste Maneyrol st->conf.temp_en = temp; 16431c24c1eSJean-Baptiste Maneyrol 16531c24c1eSJean-Baptiste Maneyrol /* compute required wait time for sensors to stabilize */ 16631c24c1eSJean-Baptiste Maneyrol sleepval = 0; 16731c24c1eSJean-Baptiste Maneyrol /* temperature stabilization time */ 16831c24c1eSJean-Baptiste Maneyrol if (temp && !oldtemp) { 16931c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_TEMP_STARTUP_TIME_MS) 17031c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_TEMP_STARTUP_TIME_MS; 17131c24c1eSJean-Baptiste Maneyrol } 17231c24c1eSJean-Baptiste Maneyrol /* accel startup time */ 17331c24c1eSJean-Baptiste Maneyrol if (accel != oldaccel && oldaccel == INV_ICM42600_SENSOR_MODE_OFF) { 17431c24c1eSJean-Baptiste Maneyrol /* block any register write for at least 200 µs */ 17531c24c1eSJean-Baptiste Maneyrol usleep_range(200, 300); 17631c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_ACCEL_STARTUP_TIME_MS) 17731c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_ACCEL_STARTUP_TIME_MS; 17831c24c1eSJean-Baptiste Maneyrol } 17931c24c1eSJean-Baptiste Maneyrol if (gyro != oldgyro) { 18031c24c1eSJean-Baptiste Maneyrol /* gyro startup time */ 18131c24c1eSJean-Baptiste Maneyrol if (oldgyro == INV_ICM42600_SENSOR_MODE_OFF) { 18231c24c1eSJean-Baptiste Maneyrol /* block any register write for at least 200 µs */ 18331c24c1eSJean-Baptiste Maneyrol usleep_range(200, 300); 18431c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_GYRO_STARTUP_TIME_MS) 18531c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_GYRO_STARTUP_TIME_MS; 18631c24c1eSJean-Baptiste Maneyrol /* gyro stop time */ 18731c24c1eSJean-Baptiste Maneyrol } else if (gyro == INV_ICM42600_SENSOR_MODE_OFF) { 18831c24c1eSJean-Baptiste Maneyrol if (sleepval < INV_ICM42600_GYRO_STOP_TIME_MS) 18931c24c1eSJean-Baptiste Maneyrol sleepval = INV_ICM42600_GYRO_STOP_TIME_MS; 19031c24c1eSJean-Baptiste Maneyrol } 19131c24c1eSJean-Baptiste Maneyrol } 19231c24c1eSJean-Baptiste Maneyrol 19331c24c1eSJean-Baptiste Maneyrol /* deferred sleep value if sleep pointer is provided or direct sleep */ 19431c24c1eSJean-Baptiste Maneyrol if (sleep_ms) 19531c24c1eSJean-Baptiste Maneyrol *sleep_ms = sleepval; 19631c24c1eSJean-Baptiste Maneyrol else if (sleepval) 19731c24c1eSJean-Baptiste Maneyrol msleep(sleepval); 19831c24c1eSJean-Baptiste Maneyrol 19931c24c1eSJean-Baptiste Maneyrol return 0; 20031c24c1eSJean-Baptiste Maneyrol } 20131c24c1eSJean-Baptiste Maneyrol 20231c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st, 20331c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *conf, 20431c24c1eSJean-Baptiste Maneyrol unsigned int *sleep_ms) 20531c24c1eSJean-Baptiste Maneyrol { 20631c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *oldconf = &st->conf.accel; 20731c24c1eSJean-Baptiste Maneyrol unsigned int val; 20831c24c1eSJean-Baptiste Maneyrol int ret; 20931c24c1eSJean-Baptiste Maneyrol 21031c24c1eSJean-Baptiste Maneyrol /* Sanitize missing values with current values */ 21131c24c1eSJean-Baptiste Maneyrol if (conf->mode < 0) 21231c24c1eSJean-Baptiste Maneyrol conf->mode = oldconf->mode; 21331c24c1eSJean-Baptiste Maneyrol if (conf->fs < 0) 21431c24c1eSJean-Baptiste Maneyrol conf->fs = oldconf->fs; 21531c24c1eSJean-Baptiste Maneyrol if (conf->odr < 0) 21631c24c1eSJean-Baptiste Maneyrol conf->odr = oldconf->odr; 21731c24c1eSJean-Baptiste Maneyrol if (conf->filter < 0) 21831c24c1eSJean-Baptiste Maneyrol conf->filter = oldconf->filter; 21931c24c1eSJean-Baptiste Maneyrol 22031c24c1eSJean-Baptiste Maneyrol /* set ACCEL_CONFIG0 register (accel fullscale & odr) */ 22131c24c1eSJean-Baptiste Maneyrol if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) { 22231c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) | 22331c24c1eSJean-Baptiste Maneyrol INV_ICM42600_ACCEL_CONFIG0_ODR(conf->odr); 22431c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val); 22531c24c1eSJean-Baptiste Maneyrol if (ret) 22631c24c1eSJean-Baptiste Maneyrol return ret; 22731c24c1eSJean-Baptiste Maneyrol oldconf->fs = conf->fs; 22831c24c1eSJean-Baptiste Maneyrol oldconf->odr = conf->odr; 22931c24c1eSJean-Baptiste Maneyrol } 23031c24c1eSJean-Baptiste Maneyrol 23131c24c1eSJean-Baptiste Maneyrol /* set GYRO_ACCEL_CONFIG0 register (accel filter) */ 23231c24c1eSJean-Baptiste Maneyrol if (conf->filter != oldconf->filter) { 23331c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->filter) | 23431c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(st->conf.gyro.filter); 23531c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val); 23631c24c1eSJean-Baptiste Maneyrol if (ret) 23731c24c1eSJean-Baptiste Maneyrol return ret; 23831c24c1eSJean-Baptiste Maneyrol oldconf->filter = conf->filter; 23931c24c1eSJean-Baptiste Maneyrol } 24031c24c1eSJean-Baptiste Maneyrol 24131c24c1eSJean-Baptiste Maneyrol /* set PWR_MGMT0 register (accel sensor mode) */ 24231c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode, 24331c24c1eSJean-Baptiste Maneyrol st->conf.temp_en, sleep_ms); 24431c24c1eSJean-Baptiste Maneyrol } 24531c24c1eSJean-Baptiste Maneyrol 24631c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st, 24731c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *conf, 24831c24c1eSJean-Baptiste Maneyrol unsigned int *sleep_ms) 24931c24c1eSJean-Baptiste Maneyrol { 25031c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_sensor_conf *oldconf = &st->conf.gyro; 25131c24c1eSJean-Baptiste Maneyrol unsigned int val; 25231c24c1eSJean-Baptiste Maneyrol int ret; 25331c24c1eSJean-Baptiste Maneyrol 25431c24c1eSJean-Baptiste Maneyrol /* sanitize missing values with current values */ 25531c24c1eSJean-Baptiste Maneyrol if (conf->mode < 0) 25631c24c1eSJean-Baptiste Maneyrol conf->mode = oldconf->mode; 25731c24c1eSJean-Baptiste Maneyrol if (conf->fs < 0) 25831c24c1eSJean-Baptiste Maneyrol conf->fs = oldconf->fs; 25931c24c1eSJean-Baptiste Maneyrol if (conf->odr < 0) 26031c24c1eSJean-Baptiste Maneyrol conf->odr = oldconf->odr; 26131c24c1eSJean-Baptiste Maneyrol if (conf->filter < 0) 26231c24c1eSJean-Baptiste Maneyrol conf->filter = oldconf->filter; 26331c24c1eSJean-Baptiste Maneyrol 26431c24c1eSJean-Baptiste Maneyrol /* set GYRO_CONFIG0 register (gyro fullscale & odr) */ 26531c24c1eSJean-Baptiste Maneyrol if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) { 26631c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_CONFIG0_FS(conf->fs) | 26731c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_CONFIG0_ODR(conf->odr); 26831c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val); 26931c24c1eSJean-Baptiste Maneyrol if (ret) 27031c24c1eSJean-Baptiste Maneyrol return ret; 27131c24c1eSJean-Baptiste Maneyrol oldconf->fs = conf->fs; 27231c24c1eSJean-Baptiste Maneyrol oldconf->odr = conf->odr; 27331c24c1eSJean-Baptiste Maneyrol } 27431c24c1eSJean-Baptiste Maneyrol 27531c24c1eSJean-Baptiste Maneyrol /* set GYRO_ACCEL_CONFIG0 register (gyro filter) */ 27631c24c1eSJean-Baptiste Maneyrol if (conf->filter != oldconf->filter) { 27731c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(st->conf.accel.filter) | 27831c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->filter); 27931c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val); 28031c24c1eSJean-Baptiste Maneyrol if (ret) 28131c24c1eSJean-Baptiste Maneyrol return ret; 28231c24c1eSJean-Baptiste Maneyrol oldconf->filter = conf->filter; 28331c24c1eSJean-Baptiste Maneyrol } 28431c24c1eSJean-Baptiste Maneyrol 28531c24c1eSJean-Baptiste Maneyrol /* set PWR_MGMT0 register (gyro sensor mode) */ 28631c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode, 28731c24c1eSJean-Baptiste Maneyrol st->conf.temp_en, sleep_ms); 28831c24c1eSJean-Baptiste Maneyrol 28931c24c1eSJean-Baptiste Maneyrol return 0; 29031c24c1eSJean-Baptiste Maneyrol } 29131c24c1eSJean-Baptiste Maneyrol 29231c24c1eSJean-Baptiste Maneyrol int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable, 29331c24c1eSJean-Baptiste Maneyrol unsigned int *sleep_ms) 29431c24c1eSJean-Baptiste Maneyrol { 29531c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode, 29631c24c1eSJean-Baptiste Maneyrol st->conf.accel.mode, enable, 29731c24c1eSJean-Baptiste Maneyrol sleep_ms); 29831c24c1eSJean-Baptiste Maneyrol } 29931c24c1eSJean-Baptiste Maneyrol 30031c24c1eSJean-Baptiste Maneyrol int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg, 30131c24c1eSJean-Baptiste Maneyrol unsigned int writeval, unsigned int *readval) 30231c24c1eSJean-Baptiste Maneyrol { 30331c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 30431c24c1eSJean-Baptiste Maneyrol int ret; 30531c24c1eSJean-Baptiste Maneyrol 30631c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock); 30731c24c1eSJean-Baptiste Maneyrol 30831c24c1eSJean-Baptiste Maneyrol if (readval) 30931c24c1eSJean-Baptiste Maneyrol ret = regmap_read(st->map, reg, readval); 31031c24c1eSJean-Baptiste Maneyrol else 31131c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, reg, writeval); 31231c24c1eSJean-Baptiste Maneyrol 31331c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock); 31431c24c1eSJean-Baptiste Maneyrol 31531c24c1eSJean-Baptiste Maneyrol return ret; 31631c24c1eSJean-Baptiste Maneyrol } 31731c24c1eSJean-Baptiste Maneyrol 31831c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_set_conf(struct inv_icm42600_state *st, 31931c24c1eSJean-Baptiste Maneyrol const struct inv_icm42600_conf *conf) 32031c24c1eSJean-Baptiste Maneyrol { 32131c24c1eSJean-Baptiste Maneyrol unsigned int val; 32231c24c1eSJean-Baptiste Maneyrol int ret; 32331c24c1eSJean-Baptiste Maneyrol 32431c24c1eSJean-Baptiste Maneyrol /* set PWR_MGMT0 register (gyro & accel sensor mode, temp enabled) */ 32531c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_PWR_MGMT0_GYRO(conf->gyro.mode) | 32631c24c1eSJean-Baptiste Maneyrol INV_ICM42600_PWR_MGMT0_ACCEL(conf->accel.mode); 32731c24c1eSJean-Baptiste Maneyrol if (!conf->temp_en) 32831c24c1eSJean-Baptiste Maneyrol val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS; 32931c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val); 33031c24c1eSJean-Baptiste Maneyrol if (ret) 33131c24c1eSJean-Baptiste Maneyrol return ret; 33231c24c1eSJean-Baptiste Maneyrol 33331c24c1eSJean-Baptiste Maneyrol /* set GYRO_CONFIG0 register (gyro fullscale & odr) */ 33431c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_CONFIG0_FS(conf->gyro.fs) | 33531c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_CONFIG0_ODR(conf->gyro.odr); 33631c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val); 33731c24c1eSJean-Baptiste Maneyrol if (ret) 33831c24c1eSJean-Baptiste Maneyrol return ret; 33931c24c1eSJean-Baptiste Maneyrol 34031c24c1eSJean-Baptiste Maneyrol /* set ACCEL_CONFIG0 register (accel fullscale & odr) */ 34131c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->accel.fs) | 34231c24c1eSJean-Baptiste Maneyrol INV_ICM42600_ACCEL_CONFIG0_ODR(conf->accel.odr); 34331c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val); 34431c24c1eSJean-Baptiste Maneyrol if (ret) 34531c24c1eSJean-Baptiste Maneyrol return ret; 34631c24c1eSJean-Baptiste Maneyrol 34731c24c1eSJean-Baptiste Maneyrol /* set GYRO_ACCEL_CONFIG0 register (gyro & accel filters) */ 34831c24c1eSJean-Baptiste Maneyrol val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->accel.filter) | 34931c24c1eSJean-Baptiste Maneyrol INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->gyro.filter); 35031c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val); 35131c24c1eSJean-Baptiste Maneyrol if (ret) 35231c24c1eSJean-Baptiste Maneyrol return ret; 35331c24c1eSJean-Baptiste Maneyrol 35431c24c1eSJean-Baptiste Maneyrol /* update internal conf */ 35531c24c1eSJean-Baptiste Maneyrol st->conf = *conf; 35631c24c1eSJean-Baptiste Maneyrol 35731c24c1eSJean-Baptiste Maneyrol return 0; 35831c24c1eSJean-Baptiste Maneyrol } 35931c24c1eSJean-Baptiste Maneyrol 36031c24c1eSJean-Baptiste Maneyrol /** 36131c24c1eSJean-Baptiste Maneyrol * inv_icm42600_setup() - check and setup chip 36231c24c1eSJean-Baptiste Maneyrol * @st: driver internal state 36331c24c1eSJean-Baptiste Maneyrol * @bus_setup: callback for setting up bus specific registers 36431c24c1eSJean-Baptiste Maneyrol * 36531c24c1eSJean-Baptiste Maneyrol * Returns 0 on success, a negative error code otherwise. 36631c24c1eSJean-Baptiste Maneyrol */ 36731c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_setup(struct inv_icm42600_state *st, 36831c24c1eSJean-Baptiste Maneyrol inv_icm42600_bus_setup bus_setup) 36931c24c1eSJean-Baptiste Maneyrol { 37031c24c1eSJean-Baptiste Maneyrol const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip]; 37131c24c1eSJean-Baptiste Maneyrol const struct device *dev = regmap_get_device(st->map); 37231c24c1eSJean-Baptiste Maneyrol unsigned int val; 37331c24c1eSJean-Baptiste Maneyrol int ret; 37431c24c1eSJean-Baptiste Maneyrol 37531c24c1eSJean-Baptiste Maneyrol /* check chip self-identification value */ 37631c24c1eSJean-Baptiste Maneyrol ret = regmap_read(st->map, INV_ICM42600_REG_WHOAMI, &val); 37731c24c1eSJean-Baptiste Maneyrol if (ret) 37831c24c1eSJean-Baptiste Maneyrol return ret; 37931c24c1eSJean-Baptiste Maneyrol if (val != hw->whoami) { 38031c24c1eSJean-Baptiste Maneyrol dev_err(dev, "invalid whoami %#02x expected %#02x (%s)\n", 38131c24c1eSJean-Baptiste Maneyrol val, hw->whoami, hw->name); 38231c24c1eSJean-Baptiste Maneyrol return -ENODEV; 38331c24c1eSJean-Baptiste Maneyrol } 38431c24c1eSJean-Baptiste Maneyrol st->name = hw->name; 38531c24c1eSJean-Baptiste Maneyrol 38631c24c1eSJean-Baptiste Maneyrol /* reset to make sure previous state are not there */ 38731c24c1eSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_DEVICE_CONFIG, 38831c24c1eSJean-Baptiste Maneyrol INV_ICM42600_DEVICE_CONFIG_SOFT_RESET); 38931c24c1eSJean-Baptiste Maneyrol if (ret) 39031c24c1eSJean-Baptiste Maneyrol return ret; 39131c24c1eSJean-Baptiste Maneyrol msleep(INV_ICM42600_RESET_TIME_MS); 39231c24c1eSJean-Baptiste Maneyrol 39331c24c1eSJean-Baptiste Maneyrol ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &val); 39431c24c1eSJean-Baptiste Maneyrol if (ret) 39531c24c1eSJean-Baptiste Maneyrol return ret; 39631c24c1eSJean-Baptiste Maneyrol if (!(val & INV_ICM42600_INT_STATUS_RESET_DONE)) { 39731c24c1eSJean-Baptiste Maneyrol dev_err(dev, "reset error, reset done bit not set\n"); 39831c24c1eSJean-Baptiste Maneyrol return -ENODEV; 39931c24c1eSJean-Baptiste Maneyrol } 40031c24c1eSJean-Baptiste Maneyrol 40131c24c1eSJean-Baptiste Maneyrol /* set chip bus configuration */ 40231c24c1eSJean-Baptiste Maneyrol ret = bus_setup(st); 40331c24c1eSJean-Baptiste Maneyrol if (ret) 40431c24c1eSJean-Baptiste Maneyrol return ret; 40531c24c1eSJean-Baptiste Maneyrol 40631c24c1eSJean-Baptiste Maneyrol /* sensor data in big-endian (default) */ 40731c24c1eSJean-Baptiste Maneyrol ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0, 40831c24c1eSJean-Baptiste Maneyrol INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN, 40931c24c1eSJean-Baptiste Maneyrol INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN); 41031c24c1eSJean-Baptiste Maneyrol if (ret) 41131c24c1eSJean-Baptiste Maneyrol return ret; 41231c24c1eSJean-Baptiste Maneyrol 41331c24c1eSJean-Baptiste Maneyrol return inv_icm42600_set_conf(st, hw->conf); 41431c24c1eSJean-Baptiste Maneyrol } 41531c24c1eSJean-Baptiste Maneyrol 416ec74ae9fSJean-Baptiste Maneyrol static irqreturn_t inv_icm42600_irq_timestamp(int irq, void *_data) 417ec74ae9fSJean-Baptiste Maneyrol { 418ec74ae9fSJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data; 419ec74ae9fSJean-Baptiste Maneyrol 420ec74ae9fSJean-Baptiste Maneyrol st->timestamp.gyro = iio_get_time_ns(st->indio_gyro); 421ec74ae9fSJean-Baptiste Maneyrol st->timestamp.accel = iio_get_time_ns(st->indio_accel); 422ec74ae9fSJean-Baptiste Maneyrol 423ec74ae9fSJean-Baptiste Maneyrol return IRQ_WAKE_THREAD; 424ec74ae9fSJean-Baptiste Maneyrol } 425ec74ae9fSJean-Baptiste Maneyrol 426e5efa104SJean-Baptiste Maneyrol static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data) 427e5efa104SJean-Baptiste Maneyrol { 428e5efa104SJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data; 429e5efa104SJean-Baptiste Maneyrol struct device *dev = regmap_get_device(st->map); 430e5efa104SJean-Baptiste Maneyrol unsigned int status; 431e5efa104SJean-Baptiste Maneyrol int ret; 432e5efa104SJean-Baptiste Maneyrol 433e5efa104SJean-Baptiste Maneyrol mutex_lock(&st->lock); 434e5efa104SJean-Baptiste Maneyrol 435e5efa104SJean-Baptiste Maneyrol ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &status); 436e5efa104SJean-Baptiste Maneyrol if (ret) 437e5efa104SJean-Baptiste Maneyrol goto out_unlock; 438e5efa104SJean-Baptiste Maneyrol 439e5efa104SJean-Baptiste Maneyrol /* FIFO full */ 440e5efa104SJean-Baptiste Maneyrol if (status & INV_ICM42600_INT_STATUS_FIFO_FULL) 441e5efa104SJean-Baptiste Maneyrol dev_warn(dev, "FIFO full data lost!\n"); 442e5efa104SJean-Baptiste Maneyrol 4437f85e42aSJean-Baptiste Maneyrol /* FIFO threshold reached */ 4447f85e42aSJean-Baptiste Maneyrol if (status & INV_ICM42600_INT_STATUS_FIFO_THS) { 4457f85e42aSJean-Baptiste Maneyrol ret = inv_icm42600_buffer_fifo_read(st, 0); 4467f85e42aSJean-Baptiste Maneyrol if (ret) { 4477f85e42aSJean-Baptiste Maneyrol dev_err(dev, "FIFO read error %d\n", ret); 4487f85e42aSJean-Baptiste Maneyrol goto out_unlock; 4497f85e42aSJean-Baptiste Maneyrol } 4507f85e42aSJean-Baptiste Maneyrol ret = inv_icm42600_buffer_fifo_parse(st); 4517f85e42aSJean-Baptiste Maneyrol if (ret) 4527f85e42aSJean-Baptiste Maneyrol dev_err(dev, "FIFO parsing error %d\n", ret); 4537f85e42aSJean-Baptiste Maneyrol } 4547f85e42aSJean-Baptiste Maneyrol 455e5efa104SJean-Baptiste Maneyrol out_unlock: 456e5efa104SJean-Baptiste Maneyrol mutex_unlock(&st->lock); 457e5efa104SJean-Baptiste Maneyrol return IRQ_HANDLED; 458e5efa104SJean-Baptiste Maneyrol } 459e5efa104SJean-Baptiste Maneyrol 460e5efa104SJean-Baptiste Maneyrol /** 461e5efa104SJean-Baptiste Maneyrol * inv_icm42600_irq_init() - initialize int pin and interrupt handler 462e5efa104SJean-Baptiste Maneyrol * @st: driver internal state 463e5efa104SJean-Baptiste Maneyrol * @irq: irq number 464e5efa104SJean-Baptiste Maneyrol * @irq_type: irq trigger type 465e5efa104SJean-Baptiste Maneyrol * @open_drain: true if irq is open drain, false for push-pull 466e5efa104SJean-Baptiste Maneyrol * 467e5efa104SJean-Baptiste Maneyrol * Returns 0 on success, a negative error code otherwise. 468e5efa104SJean-Baptiste Maneyrol */ 469e5efa104SJean-Baptiste Maneyrol static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq, 470e5efa104SJean-Baptiste Maneyrol int irq_type, bool open_drain) 471e5efa104SJean-Baptiste Maneyrol { 472e5efa104SJean-Baptiste Maneyrol struct device *dev = regmap_get_device(st->map); 473e5efa104SJean-Baptiste Maneyrol unsigned int val; 474e5efa104SJean-Baptiste Maneyrol int ret; 475e5efa104SJean-Baptiste Maneyrol 476e5efa104SJean-Baptiste Maneyrol /* configure INT1 interrupt: default is active low on edge */ 477e5efa104SJean-Baptiste Maneyrol switch (irq_type) { 478e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_RISING: 479e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_HIGH: 480e5efa104SJean-Baptiste Maneyrol val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGH; 481e5efa104SJean-Baptiste Maneyrol break; 482e5efa104SJean-Baptiste Maneyrol default: 483e5efa104SJean-Baptiste Maneyrol val = INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOW; 484e5efa104SJean-Baptiste Maneyrol break; 485e5efa104SJean-Baptiste Maneyrol } 486e5efa104SJean-Baptiste Maneyrol 487e5efa104SJean-Baptiste Maneyrol switch (irq_type) { 488e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_LOW: 489e5efa104SJean-Baptiste Maneyrol case IRQF_TRIGGER_HIGH: 490e5efa104SJean-Baptiste Maneyrol val |= INV_ICM42600_INT_CONFIG_INT1_LATCHED; 491e5efa104SJean-Baptiste Maneyrol break; 492e5efa104SJean-Baptiste Maneyrol default: 493e5efa104SJean-Baptiste Maneyrol break; 494e5efa104SJean-Baptiste Maneyrol } 495e5efa104SJean-Baptiste Maneyrol 496e5efa104SJean-Baptiste Maneyrol if (!open_drain) 497e5efa104SJean-Baptiste Maneyrol val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL; 498e5efa104SJean-Baptiste Maneyrol 499e5efa104SJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val); 500e5efa104SJean-Baptiste Maneyrol if (ret) 501e5efa104SJean-Baptiste Maneyrol return ret; 502e5efa104SJean-Baptiste Maneyrol 503e5efa104SJean-Baptiste Maneyrol /* Deassert async reset for proper INT pin operation (cf datasheet) */ 504e5efa104SJean-Baptiste Maneyrol ret = regmap_update_bits(st->map, INV_ICM42600_REG_INT_CONFIG1, 505e5efa104SJean-Baptiste Maneyrol INV_ICM42600_INT_CONFIG1_ASYNC_RESET, 0); 506e5efa104SJean-Baptiste Maneyrol if (ret) 507e5efa104SJean-Baptiste Maneyrol return ret; 508e5efa104SJean-Baptiste Maneyrol 509ec74ae9fSJean-Baptiste Maneyrol return devm_request_threaded_irq(dev, irq, inv_icm42600_irq_timestamp, 510e5efa104SJean-Baptiste Maneyrol inv_icm42600_irq_handler, irq_type, 511e5efa104SJean-Baptiste Maneyrol "inv_icm42600", st); 512e5efa104SJean-Baptiste Maneyrol } 513e5efa104SJean-Baptiste Maneyrol 51431c24c1eSJean-Baptiste Maneyrol static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st) 51531c24c1eSJean-Baptiste Maneyrol { 51631c24c1eSJean-Baptiste Maneyrol int ret; 51731c24c1eSJean-Baptiste Maneyrol 51831c24c1eSJean-Baptiste Maneyrol ret = regulator_enable(st->vddio_supply); 51931c24c1eSJean-Baptiste Maneyrol if (ret) 52031c24c1eSJean-Baptiste Maneyrol return ret; 52131c24c1eSJean-Baptiste Maneyrol 52231c24c1eSJean-Baptiste Maneyrol /* wait a little for supply ramp */ 52331c24c1eSJean-Baptiste Maneyrol usleep_range(3000, 4000); 52431c24c1eSJean-Baptiste Maneyrol 52531c24c1eSJean-Baptiste Maneyrol return 0; 52631c24c1eSJean-Baptiste Maneyrol } 52731c24c1eSJean-Baptiste Maneyrol 52831c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_vdd_reg(void *_data) 52931c24c1eSJean-Baptiste Maneyrol { 53031c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data; 53131c24c1eSJean-Baptiste Maneyrol const struct device *dev = regmap_get_device(st->map); 53231c24c1eSJean-Baptiste Maneyrol int ret; 53331c24c1eSJean-Baptiste Maneyrol 53431c24c1eSJean-Baptiste Maneyrol ret = regulator_disable(st->vdd_supply); 53531c24c1eSJean-Baptiste Maneyrol if (ret) 53631c24c1eSJean-Baptiste Maneyrol dev_err(dev, "failed to disable vdd error %d\n", ret); 53731c24c1eSJean-Baptiste Maneyrol } 53831c24c1eSJean-Baptiste Maneyrol 53931c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_vddio_reg(void *_data) 54031c24c1eSJean-Baptiste Maneyrol { 54131c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = _data; 54231c24c1eSJean-Baptiste Maneyrol const struct device *dev = regmap_get_device(st->map); 54331c24c1eSJean-Baptiste Maneyrol int ret; 54431c24c1eSJean-Baptiste Maneyrol 54531c24c1eSJean-Baptiste Maneyrol ret = regulator_disable(st->vddio_supply); 54631c24c1eSJean-Baptiste Maneyrol if (ret) 54731c24c1eSJean-Baptiste Maneyrol dev_err(dev, "failed to disable vddio error %d\n", ret); 54831c24c1eSJean-Baptiste Maneyrol } 54931c24c1eSJean-Baptiste Maneyrol 55031c24c1eSJean-Baptiste Maneyrol static void inv_icm42600_disable_pm(void *_data) 55131c24c1eSJean-Baptiste Maneyrol { 55231c24c1eSJean-Baptiste Maneyrol struct device *dev = _data; 55331c24c1eSJean-Baptiste Maneyrol 55431c24c1eSJean-Baptiste Maneyrol pm_runtime_put_sync(dev); 55531c24c1eSJean-Baptiste Maneyrol pm_runtime_disable(dev); 55631c24c1eSJean-Baptiste Maneyrol } 55731c24c1eSJean-Baptiste Maneyrol 558e5efa104SJean-Baptiste Maneyrol int inv_icm42600_core_probe(struct regmap *regmap, int chip, int irq, 55931c24c1eSJean-Baptiste Maneyrol inv_icm42600_bus_setup bus_setup) 56031c24c1eSJean-Baptiste Maneyrol { 56131c24c1eSJean-Baptiste Maneyrol struct device *dev = regmap_get_device(regmap); 56231c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st; 563e5efa104SJean-Baptiste Maneyrol struct irq_data *irq_desc; 564e5efa104SJean-Baptiste Maneyrol int irq_type; 565e5efa104SJean-Baptiste Maneyrol bool open_drain; 56631c24c1eSJean-Baptiste Maneyrol int ret; 56731c24c1eSJean-Baptiste Maneyrol 56831c24c1eSJean-Baptiste Maneyrol if (chip < 0 || chip >= INV_CHIP_NB) { 56931c24c1eSJean-Baptiste Maneyrol dev_err(dev, "invalid chip = %d\n", chip); 57031c24c1eSJean-Baptiste Maneyrol return -ENODEV; 57131c24c1eSJean-Baptiste Maneyrol } 57231c24c1eSJean-Baptiste Maneyrol 573e5efa104SJean-Baptiste Maneyrol /* get irq properties, set trigger falling by default */ 574e5efa104SJean-Baptiste Maneyrol irq_desc = irq_get_irq_data(irq); 575e5efa104SJean-Baptiste Maneyrol if (!irq_desc) { 576e5efa104SJean-Baptiste Maneyrol dev_err(dev, "could not find IRQ %d\n", irq); 577e5efa104SJean-Baptiste Maneyrol return -EINVAL; 578e5efa104SJean-Baptiste Maneyrol } 579e5efa104SJean-Baptiste Maneyrol 580e5efa104SJean-Baptiste Maneyrol irq_type = irqd_get_trigger_type(irq_desc); 581e5efa104SJean-Baptiste Maneyrol if (!irq_type) 582e5efa104SJean-Baptiste Maneyrol irq_type = IRQF_TRIGGER_FALLING; 583e5efa104SJean-Baptiste Maneyrol 584e5efa104SJean-Baptiste Maneyrol open_drain = device_property_read_bool(dev, "drive-open-drain"); 585e5efa104SJean-Baptiste Maneyrol 58631c24c1eSJean-Baptiste Maneyrol st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); 58731c24c1eSJean-Baptiste Maneyrol if (!st) 58831c24c1eSJean-Baptiste Maneyrol return -ENOMEM; 58931c24c1eSJean-Baptiste Maneyrol 59031c24c1eSJean-Baptiste Maneyrol dev_set_drvdata(dev, st); 59131c24c1eSJean-Baptiste Maneyrol mutex_init(&st->lock); 59231c24c1eSJean-Baptiste Maneyrol st->chip = chip; 59331c24c1eSJean-Baptiste Maneyrol st->map = regmap; 59431c24c1eSJean-Baptiste Maneyrol 59531c24c1eSJean-Baptiste Maneyrol ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation); 59631c24c1eSJean-Baptiste Maneyrol if (ret) { 59731c24c1eSJean-Baptiste Maneyrol dev_err(dev, "failed to retrieve mounting matrix %d\n", ret); 59831c24c1eSJean-Baptiste Maneyrol return ret; 59931c24c1eSJean-Baptiste Maneyrol } 60031c24c1eSJean-Baptiste Maneyrol 60131c24c1eSJean-Baptiste Maneyrol st->vdd_supply = devm_regulator_get(dev, "vdd"); 60231c24c1eSJean-Baptiste Maneyrol if (IS_ERR(st->vdd_supply)) 60331c24c1eSJean-Baptiste Maneyrol return PTR_ERR(st->vdd_supply); 60431c24c1eSJean-Baptiste Maneyrol 60531c24c1eSJean-Baptiste Maneyrol st->vddio_supply = devm_regulator_get(dev, "vddio"); 60631c24c1eSJean-Baptiste Maneyrol if (IS_ERR(st->vddio_supply)) 60731c24c1eSJean-Baptiste Maneyrol return PTR_ERR(st->vddio_supply); 60831c24c1eSJean-Baptiste Maneyrol 60931c24c1eSJean-Baptiste Maneyrol ret = regulator_enable(st->vdd_supply); 61031c24c1eSJean-Baptiste Maneyrol if (ret) 61131c24c1eSJean-Baptiste Maneyrol return ret; 61231c24c1eSJean-Baptiste Maneyrol msleep(INV_ICM42600_POWER_UP_TIME_MS); 61331c24c1eSJean-Baptiste Maneyrol 61431c24c1eSJean-Baptiste Maneyrol ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vdd_reg, st); 61531c24c1eSJean-Baptiste Maneyrol if (ret) 61631c24c1eSJean-Baptiste Maneyrol return ret; 61731c24c1eSJean-Baptiste Maneyrol 61831c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_enable_regulator_vddio(st); 61931c24c1eSJean-Baptiste Maneyrol if (ret) 62031c24c1eSJean-Baptiste Maneyrol return ret; 62131c24c1eSJean-Baptiste Maneyrol 62231c24c1eSJean-Baptiste Maneyrol ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vddio_reg, st); 62331c24c1eSJean-Baptiste Maneyrol if (ret) 62431c24c1eSJean-Baptiste Maneyrol return ret; 62531c24c1eSJean-Baptiste Maneyrol 62631c24c1eSJean-Baptiste Maneyrol /* setup chip registers */ 62731c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_setup(st, bus_setup); 62831c24c1eSJean-Baptiste Maneyrol if (ret) 62931c24c1eSJean-Baptiste Maneyrol return ret; 63031c24c1eSJean-Baptiste Maneyrol 631ec74ae9fSJean-Baptiste Maneyrol ret = inv_icm42600_timestamp_setup(st); 632ec74ae9fSJean-Baptiste Maneyrol if (ret) 633ec74ae9fSJean-Baptiste Maneyrol return ret; 634ec74ae9fSJean-Baptiste Maneyrol 6357f85e42aSJean-Baptiste Maneyrol ret = inv_icm42600_buffer_init(st); 6367f85e42aSJean-Baptiste Maneyrol if (ret) 6377f85e42aSJean-Baptiste Maneyrol return ret; 6387f85e42aSJean-Baptiste Maneyrol 639a095fadbSJean-Baptiste Maneyrol st->indio_gyro = inv_icm42600_gyro_init(st); 640a095fadbSJean-Baptiste Maneyrol if (IS_ERR(st->indio_gyro)) 641a095fadbSJean-Baptiste Maneyrol return PTR_ERR(st->indio_gyro); 642a095fadbSJean-Baptiste Maneyrol 643a47c1cdcSJean-Baptiste Maneyrol st->indio_accel = inv_icm42600_accel_init(st); 644a47c1cdcSJean-Baptiste Maneyrol if (IS_ERR(st->indio_accel)) 645a47c1cdcSJean-Baptiste Maneyrol return PTR_ERR(st->indio_accel); 646a47c1cdcSJean-Baptiste Maneyrol 647e5efa104SJean-Baptiste Maneyrol ret = inv_icm42600_irq_init(st, irq, irq_type, open_drain); 648e5efa104SJean-Baptiste Maneyrol if (ret) 649e5efa104SJean-Baptiste Maneyrol return ret; 650e5efa104SJean-Baptiste Maneyrol 65131c24c1eSJean-Baptiste Maneyrol /* setup runtime power management */ 65231c24c1eSJean-Baptiste Maneyrol ret = pm_runtime_set_active(dev); 65331c24c1eSJean-Baptiste Maneyrol if (ret) 65431c24c1eSJean-Baptiste Maneyrol return ret; 65531c24c1eSJean-Baptiste Maneyrol pm_runtime_get_noresume(dev); 65631c24c1eSJean-Baptiste Maneyrol pm_runtime_enable(dev); 65731c24c1eSJean-Baptiste Maneyrol pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS); 65831c24c1eSJean-Baptiste Maneyrol pm_runtime_use_autosuspend(dev); 65931c24c1eSJean-Baptiste Maneyrol pm_runtime_put(dev); 66031c24c1eSJean-Baptiste Maneyrol 66131c24c1eSJean-Baptiste Maneyrol return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev); 66231c24c1eSJean-Baptiste Maneyrol } 66331c24c1eSJean-Baptiste Maneyrol EXPORT_SYMBOL_GPL(inv_icm42600_core_probe); 66431c24c1eSJean-Baptiste Maneyrol 66531c24c1eSJean-Baptiste Maneyrol /* 66631c24c1eSJean-Baptiste Maneyrol * Suspend saves sensors state and turns everything off. 66731c24c1eSJean-Baptiste Maneyrol * Check first if runtime suspend has not already done the job. 66831c24c1eSJean-Baptiste Maneyrol */ 66931c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_suspend(struct device *dev) 67031c24c1eSJean-Baptiste Maneyrol { 67131c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev); 67231c24c1eSJean-Baptiste Maneyrol int ret; 67331c24c1eSJean-Baptiste Maneyrol 67431c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock); 67531c24c1eSJean-Baptiste Maneyrol 67631c24c1eSJean-Baptiste Maneyrol st->suspended.gyro = st->conf.gyro.mode; 67731c24c1eSJean-Baptiste Maneyrol st->suspended.accel = st->conf.accel.mode; 67831c24c1eSJean-Baptiste Maneyrol st->suspended.temp = st->conf.temp_en; 67931c24c1eSJean-Baptiste Maneyrol if (pm_runtime_suspended(dev)) { 68031c24c1eSJean-Baptiste Maneyrol ret = 0; 68131c24c1eSJean-Baptiste Maneyrol goto out_unlock; 68231c24c1eSJean-Baptiste Maneyrol } 68331c24c1eSJean-Baptiste Maneyrol 6847f85e42aSJean-Baptiste Maneyrol /* disable FIFO data streaming */ 6857f85e42aSJean-Baptiste Maneyrol if (st->fifo.on) { 6867f85e42aSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG, 6877f85e42aSJean-Baptiste Maneyrol INV_ICM42600_FIFO_CONFIG_BYPASS); 6887f85e42aSJean-Baptiste Maneyrol if (ret) 6897f85e42aSJean-Baptiste Maneyrol goto out_unlock; 6907f85e42aSJean-Baptiste Maneyrol } 6917f85e42aSJean-Baptiste Maneyrol 69231c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF, 69331c24c1eSJean-Baptiste Maneyrol INV_ICM42600_SENSOR_MODE_OFF, false, 69431c24c1eSJean-Baptiste Maneyrol NULL); 69531c24c1eSJean-Baptiste Maneyrol if (ret) 69631c24c1eSJean-Baptiste Maneyrol goto out_unlock; 69731c24c1eSJean-Baptiste Maneyrol 69831c24c1eSJean-Baptiste Maneyrol regulator_disable(st->vddio_supply); 69931c24c1eSJean-Baptiste Maneyrol 70031c24c1eSJean-Baptiste Maneyrol out_unlock: 70131c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock); 70231c24c1eSJean-Baptiste Maneyrol return ret; 70331c24c1eSJean-Baptiste Maneyrol } 70431c24c1eSJean-Baptiste Maneyrol 70531c24c1eSJean-Baptiste Maneyrol /* 70631c24c1eSJean-Baptiste Maneyrol * System resume gets the system back on and restores the sensors state. 70731c24c1eSJean-Baptiste Maneyrol * Manually put runtime power management in system active state. 70831c24c1eSJean-Baptiste Maneyrol */ 70931c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_resume(struct device *dev) 71031c24c1eSJean-Baptiste Maneyrol { 71131c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev); 71231c24c1eSJean-Baptiste Maneyrol int ret; 71331c24c1eSJean-Baptiste Maneyrol 71431c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock); 71531c24c1eSJean-Baptiste Maneyrol 71631c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_enable_regulator_vddio(st); 71731c24c1eSJean-Baptiste Maneyrol if (ret) 71831c24c1eSJean-Baptiste Maneyrol goto out_unlock; 71931c24c1eSJean-Baptiste Maneyrol 72031c24c1eSJean-Baptiste Maneyrol pm_runtime_disable(dev); 72131c24c1eSJean-Baptiste Maneyrol pm_runtime_set_active(dev); 72231c24c1eSJean-Baptiste Maneyrol pm_runtime_enable(dev); 72331c24c1eSJean-Baptiste Maneyrol 72431c24c1eSJean-Baptiste Maneyrol /* restore sensors state */ 72531c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_set_pwr_mgmt0(st, st->suspended.gyro, 72631c24c1eSJean-Baptiste Maneyrol st->suspended.accel, 72731c24c1eSJean-Baptiste Maneyrol st->suspended.temp, NULL); 72831c24c1eSJean-Baptiste Maneyrol if (ret) 72931c24c1eSJean-Baptiste Maneyrol goto out_unlock; 73031c24c1eSJean-Baptiste Maneyrol 7317f85e42aSJean-Baptiste Maneyrol /* restore FIFO data streaming */ 7327f85e42aSJean-Baptiste Maneyrol if (st->fifo.on) 7337f85e42aSJean-Baptiste Maneyrol ret = regmap_write(st->map, INV_ICM42600_REG_FIFO_CONFIG, 7347f85e42aSJean-Baptiste Maneyrol INV_ICM42600_FIFO_CONFIG_STREAM); 7357f85e42aSJean-Baptiste Maneyrol 73631c24c1eSJean-Baptiste Maneyrol out_unlock: 73731c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock); 73831c24c1eSJean-Baptiste Maneyrol return ret; 73931c24c1eSJean-Baptiste Maneyrol } 74031c24c1eSJean-Baptiste Maneyrol 74131c24c1eSJean-Baptiste Maneyrol /* Runtime suspend will turn off sensors that are enabled by iio devices. */ 74231c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_runtime_suspend(struct device *dev) 74331c24c1eSJean-Baptiste Maneyrol { 74431c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev); 74531c24c1eSJean-Baptiste Maneyrol int ret; 74631c24c1eSJean-Baptiste Maneyrol 74731c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock); 74831c24c1eSJean-Baptiste Maneyrol 74931c24c1eSJean-Baptiste Maneyrol /* disable all sensors */ 75031c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF, 75131c24c1eSJean-Baptiste Maneyrol INV_ICM42600_SENSOR_MODE_OFF, false, 75231c24c1eSJean-Baptiste Maneyrol NULL); 75331c24c1eSJean-Baptiste Maneyrol if (ret) 75431c24c1eSJean-Baptiste Maneyrol goto error_unlock; 75531c24c1eSJean-Baptiste Maneyrol 75631c24c1eSJean-Baptiste Maneyrol regulator_disable(st->vddio_supply); 75731c24c1eSJean-Baptiste Maneyrol 75831c24c1eSJean-Baptiste Maneyrol error_unlock: 75931c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock); 76031c24c1eSJean-Baptiste Maneyrol return ret; 76131c24c1eSJean-Baptiste Maneyrol } 76231c24c1eSJean-Baptiste Maneyrol 76331c24c1eSJean-Baptiste Maneyrol /* Sensors are enabled by iio devices, no need to turn them back on here. */ 76431c24c1eSJean-Baptiste Maneyrol static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev) 76531c24c1eSJean-Baptiste Maneyrol { 76631c24c1eSJean-Baptiste Maneyrol struct inv_icm42600_state *st = dev_get_drvdata(dev); 76731c24c1eSJean-Baptiste Maneyrol int ret; 76831c24c1eSJean-Baptiste Maneyrol 76931c24c1eSJean-Baptiste Maneyrol mutex_lock(&st->lock); 77031c24c1eSJean-Baptiste Maneyrol 77131c24c1eSJean-Baptiste Maneyrol ret = inv_icm42600_enable_regulator_vddio(st); 77231c24c1eSJean-Baptiste Maneyrol 77331c24c1eSJean-Baptiste Maneyrol mutex_unlock(&st->lock); 77431c24c1eSJean-Baptiste Maneyrol return ret; 77531c24c1eSJean-Baptiste Maneyrol } 77631c24c1eSJean-Baptiste Maneyrol 77731c24c1eSJean-Baptiste Maneyrol const struct dev_pm_ops inv_icm42600_pm_ops = { 77831c24c1eSJean-Baptiste Maneyrol SET_SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume) 77931c24c1eSJean-Baptiste Maneyrol SET_RUNTIME_PM_OPS(inv_icm42600_runtime_suspend, 78031c24c1eSJean-Baptiste Maneyrol inv_icm42600_runtime_resume, NULL) 78131c24c1eSJean-Baptiste Maneyrol }; 78231c24c1eSJean-Baptiste Maneyrol EXPORT_SYMBOL_GPL(inv_icm42600_pm_ops); 78331c24c1eSJean-Baptiste Maneyrol 78431c24c1eSJean-Baptiste Maneyrol MODULE_AUTHOR("InvenSense, Inc."); 78531c24c1eSJean-Baptiste Maneyrol MODULE_DESCRIPTION("InvenSense ICM-426xx device driver"); 78631c24c1eSJean-Baptiste Maneyrol MODULE_LICENSE("GPL"); 787