#include <linux/regulator/consumer.h>
 #include <linux/pm.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/common/inv_sensors_timestamp.h>
 
 #include "inv_icm42600_buffer.h"
 
        INV_CHIP_ICM42600,
        INV_CHIP_ICM42602,
        INV_CHIP_ICM42605,
+       INV_CHIP_ICM42686,
        INV_CHIP_ICM42622,
        INV_CHIP_ICM42688,
        INV_CHIP_ICM42631,
        INV_ICM42600_GYRO_FS_15_625DPS,
        INV_ICM42600_GYRO_FS_NB,
 };
+enum inv_icm42686_gyro_fs {
+       INV_ICM42686_GYRO_FS_4000DPS,
+       INV_ICM42686_GYRO_FS_2000DPS,
+       INV_ICM42686_GYRO_FS_1000DPS,
+       INV_ICM42686_GYRO_FS_500DPS,
+       INV_ICM42686_GYRO_FS_250DPS,
+       INV_ICM42686_GYRO_FS_125DPS,
+       INV_ICM42686_GYRO_FS_62_5DPS,
+       INV_ICM42686_GYRO_FS_31_25DPS,
+       INV_ICM42686_GYRO_FS_NB,
+};
 
 /* accelerometer fullscale values */
 enum inv_icm42600_accel_fs {
        INV_ICM42600_ACCEL_FS_2G,
        INV_ICM42600_ACCEL_FS_NB,
 };
+enum inv_icm42686_accel_fs {
+       INV_ICM42686_ACCEL_FS_32G,
+       INV_ICM42686_ACCEL_FS_16G,
+       INV_ICM42686_ACCEL_FS_8G,
+       INV_ICM42686_ACCEL_FS_4G,
+       INV_ICM42686_ACCEL_FS_2G,
+       INV_ICM42686_ACCEL_FS_NB,
+};
 
 /* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */
 enum inv_icm42600_odr {
        } timestamp;
 };
 
+
+/**
+ * struct inv_icm42600_sensor_state - sensor state variables
+ * @scales:            table of scales.
+ * @scales_len:                length (nb of items) of the scales table.
+ * @ts:                        timestamp module states.
+ */
+struct inv_icm42600_sensor_state {
+       const int *scales;
+       size_t scales_len;
+       struct inv_sensors_timestamp ts;
+};
+
 /* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
 
 /* Bank selection register, available in all banks */
 #define INV_ICM42600_WHOAMI_ICM42600                   0x40
 #define INV_ICM42600_WHOAMI_ICM42602                   0x41
 #define INV_ICM42600_WHOAMI_ICM42605                   0x42
+#define INV_ICM42600_WHOAMI_ICM42686                   0x44
 #define INV_ICM42600_WHOAMI_ICM42622                   0x46
 #define INV_ICM42600_WHOAMI_ICM42688                   0x47
 #define INV_ICM42600_WHOAMI_ICM42631                   0x5C
 
                                               const unsigned long *scan_mask)
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
-       struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+       struct inv_sensors_timestamp *ts = &accel_st->ts;
        struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
        unsigned int fifo_en = 0;
        unsigned int sleep_temp = 0;
        [2 * INV_ICM42600_ACCEL_FS_2G] = 0,
        [2 * INV_ICM42600_ACCEL_FS_2G + 1] = 598550,
 };
+static const int inv_icm42686_accel_scale[] = {
+       /* +/- 32G => 0.009576807 m/s-2 */
+       [2 * INV_ICM42686_ACCEL_FS_32G] = 0,
+       [2 * INV_ICM42686_ACCEL_FS_32G + 1] = 9576807,
+       /* +/- 16G => 0.004788403 m/s-2 */
+       [2 * INV_ICM42686_ACCEL_FS_16G] = 0,
+       [2 * INV_ICM42686_ACCEL_FS_16G + 1] = 4788403,
+       /* +/- 8G => 0.002394202 m/s-2 */
+       [2 * INV_ICM42686_ACCEL_FS_8G] = 0,
+       [2 * INV_ICM42686_ACCEL_FS_8G + 1] = 2394202,
+       /* +/- 4G => 0.001197101 m/s-2 */
+       [2 * INV_ICM42686_ACCEL_FS_4G] = 0,
+       [2 * INV_ICM42686_ACCEL_FS_4G + 1] = 1197101,
+       /* +/- 2G => 0.000598550 m/s-2 */
+       [2 * INV_ICM42686_ACCEL_FS_2G] = 0,
+       [2 * INV_ICM42686_ACCEL_FS_2G + 1] = 598550,
+};
 
-static int inv_icm42600_accel_read_scale(struct inv_icm42600_state *st,
+static int inv_icm42600_accel_read_scale(struct iio_dev *indio_dev,
                                         int *val, int *val2)
 {
+       struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
        unsigned int idx;
 
        idx = st->conf.accel.fs;
 
-       *val = inv_icm42600_accel_scale[2 * idx];
-       *val2 = inv_icm42600_accel_scale[2 * idx + 1];
+       *val = accel_st->scales[2 * idx];
+       *val2 = accel_st->scales[2 * idx + 1];
        return IIO_VAL_INT_PLUS_NANO;
 }
 
-static int inv_icm42600_accel_write_scale(struct inv_icm42600_state *st,
+static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev,
                                          int val, int val2)
 {
+       struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
        struct device *dev = regmap_get_device(st->map);
        unsigned int idx;
        struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
        int ret;
 
-       for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_scale); idx += 2) {
-               if (val == inv_icm42600_accel_scale[idx] &&
-                   val2 == inv_icm42600_accel_scale[idx + 1])
+       for (idx = 0; idx < accel_st->scales_len; idx += 2) {
+               if (val == accel_st->scales[idx] &&
+                   val2 == accel_st->scales[idx + 1])
                        break;
        }
-       if (idx >= ARRAY_SIZE(inv_icm42600_accel_scale))
+       if (idx >= accel_st->scales_len)
                return -EINVAL;
 
        conf.fs = idx / 2;
                                        int val, int val2)
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
-       struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+       struct inv_sensors_timestamp *ts = &accel_st->ts;
        struct device *dev = regmap_get_device(st->map);
        unsigned int idx;
        struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
                *val = data;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_SCALE:
-               return inv_icm42600_accel_read_scale(st, val, val2);
+               return inv_icm42600_accel_read_scale(indio_dev, val, val2);
        case IIO_CHAN_INFO_SAMP_FREQ:
                return inv_icm42600_accel_read_odr(st, val, val2);
        case IIO_CHAN_INFO_CALIBBIAS:
                                         const int **vals,
                                         int *type, int *length, long mask)
 {
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+
        if (chan->type != IIO_ACCEL)
                return -EINVAL;
 
        switch (mask) {
        case IIO_CHAN_INFO_SCALE:
-               *vals = inv_icm42600_accel_scale;
+               *vals = accel_st->scales;
                *type = IIO_VAL_INT_PLUS_NANO;
-               *length = ARRAY_SIZE(inv_icm42600_accel_scale);
+               *length = accel_st->scales_len;
                return IIO_AVAIL_LIST;
        case IIO_CHAN_INFO_SAMP_FREQ:
                *vals = inv_icm42600_accel_odr;
                ret = iio_device_claim_direct_mode(indio_dev);
                if (ret)
                        return ret;
-               ret = inv_icm42600_accel_write_scale(st, val, val2);
+               ret = inv_icm42600_accel_write_scale(indio_dev, val, val2);
                iio_device_release_direct_mode(indio_dev);
                return ret;
        case IIO_CHAN_INFO_SAMP_FREQ:
 {
        struct device *dev = regmap_get_device(st->map);
        const char *name;
+       struct inv_icm42600_sensor_state *accel_st;
        struct inv_sensors_timestamp_chip ts_chip;
-       struct inv_sensors_timestamp *ts;
        struct iio_dev *indio_dev;
        int ret;
 
        if (!name)
                return ERR_PTR(-ENOMEM);
 
-       indio_dev = devm_iio_device_alloc(dev, sizeof(*ts));
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
        if (!indio_dev)
                return ERR_PTR(-ENOMEM);
+       accel_st = iio_priv(indio_dev);
+
+       switch (st->chip) {
+       case INV_CHIP_ICM42686:
+               accel_st->scales = inv_icm42686_accel_scale;
+               accel_st->scales_len = ARRAY_SIZE(inv_icm42686_accel_scale);
+               break;
+       default:
+               accel_st->scales = inv_icm42600_accel_scale;
+               accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale);
+               break;
+       }
 
        /*
         * clock period is 32kHz (31250ns)
        ts_chip.clock_period = 31250;
        ts_chip.jitter = 20;
        ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
-       ts = iio_priv(indio_dev);
-       inv_sensors_timestamp_init(ts, &ts_chip);
+       inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);
 
        iio_device_set_drvdata(indio_dev, st);
        indio_dev->name = name;
 int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev)
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
-       struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+       struct inv_sensors_timestamp *ts = &accel_st->ts;
        ssize_t i, size;
        unsigned int no;
        const void *accel, *gyro, *timestamp;
 
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
        struct device *dev = regmap_get_device(st->map);
-       struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
+       struct inv_icm42600_sensor_state *sensor_st = iio_priv(indio_dev);
+       struct inv_sensors_timestamp *ts = &sensor_st->ts;
 
        pm_runtime_get_sync(dev);
 
 
 int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st)
 {
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro);
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel);
        struct inv_sensors_timestamp *ts;
        int ret;
 
                return 0;
 
        /* handle gyroscope timestamp and FIFO data parsing */
-       ts = iio_priv(st->indio_gyro);
+       ts = &gyro_st->ts;
        inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total,
                                        st->fifo.nb.gyro, st->timestamp.gyro);
        if (st->fifo.nb.gyro > 0) {
        }
 
        /* handle accelerometer timestamp and FIFO data parsing */
-       ts = iio_priv(st->indio_accel);
+       ts = &accel_st->ts;
        inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total,
                                        st->fifo.nb.accel, st->timestamp.accel);
        if (st->fifo.nb.accel > 0) {
 int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
                                     unsigned int count)
 {
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro);
+       struct inv_icm42600_sensor_state *accel_st = iio_priv(st->indio_accel);
        struct inv_sensors_timestamp *ts;
        int64_t gyro_ts, accel_ts;
        int ret;
                return 0;
 
        if (st->fifo.nb.gyro > 0) {
-               ts = iio_priv(st->indio_gyro);
+               ts = &gyro_st->ts;
                inv_sensors_timestamp_interrupt(ts, st->fifo.period,
                                                st->fifo.nb.total, st->fifo.nb.gyro,
                                                gyro_ts);
        }
 
        if (st->fifo.nb.accel > 0) {
-               ts = iio_priv(st->indio_accel);
+               ts = &accel_st->ts;
                inv_sensors_timestamp_interrupt(ts, st->fifo.period,
                                                st->fifo.nb.total, st->fifo.nb.accel,
                                                accel_ts);
 
        .temp_en = false,
 };
 
+static const struct inv_icm42600_conf inv_icm42686_default_conf = {
+       .gyro = {
+               .mode = INV_ICM42600_SENSOR_MODE_OFF,
+               .fs = INV_ICM42686_GYRO_FS_4000DPS,
+               .odr = INV_ICM42600_ODR_50HZ,
+               .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
+       },
+       .accel = {
+               .mode = INV_ICM42600_SENSOR_MODE_OFF,
+               .fs = INV_ICM42686_ACCEL_FS_32G,
+               .odr = INV_ICM42600_ODR_50HZ,
+               .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
+       },
+       .temp_en = false,
+};
+
 static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
        [INV_CHIP_ICM42600] = {
                .whoami = INV_ICM42600_WHOAMI_ICM42600,
                .name = "icm42605",
                .conf = &inv_icm42600_default_conf,
        },
+       [INV_CHIP_ICM42686] = {
+               .whoami = INV_ICM42600_WHOAMI_ICM42686,
+               .name = "icm42686",
+               .conf = &inv_icm42686_default_conf,
+       },
        [INV_CHIP_ICM42622] = {
                .whoami = INV_ICM42600_WHOAMI_ICM42622,
                .name = "icm42622",
 
                                              const unsigned long *scan_mask)
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
-       struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
+       struct inv_sensors_timestamp *ts = &gyro_st->ts;
        struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
        unsigned int fifo_en = 0;
        unsigned int sleep_gyro = 0;
        [2 * INV_ICM42600_GYRO_FS_15_625DPS] = 0,
        [2 * INV_ICM42600_GYRO_FS_15_625DPS + 1] = 8322,
 };
+static const int inv_icm42686_gyro_scale[] = {
+       /* +/- 4000dps => 0.002130529 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_4000DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_4000DPS + 1] = 2130529,
+       /* +/- 2000dps => 0.001065264 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_2000DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_2000DPS + 1] = 1065264,
+       /* +/- 1000dps => 0.000532632 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_1000DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_1000DPS + 1] = 532632,
+       /* +/- 500dps => 0.000266316 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_500DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_500DPS + 1] = 266316,
+       /* +/- 250dps => 0.000133158 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_250DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_250DPS + 1] = 133158,
+       /* +/- 125dps => 0.000066579 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_125DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_125DPS + 1] = 66579,
+       /* +/- 62.5dps => 0.000033290 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_62_5DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_62_5DPS + 1] = 33290,
+       /* +/- 31.25dps => 0.000016645 rad/s */
+       [2 * INV_ICM42686_GYRO_FS_31_25DPS] = 0,
+       [2 * INV_ICM42686_GYRO_FS_31_25DPS + 1] = 16645,
+};
 
-static int inv_icm42600_gyro_read_scale(struct inv_icm42600_state *st,
+static int inv_icm42600_gyro_read_scale(struct iio_dev *indio_dev,
                                        int *val, int *val2)
 {
+       struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
        unsigned int idx;
 
        idx = st->conf.gyro.fs;
 
-       *val = inv_icm42600_gyro_scale[2 * idx];
-       *val2 = inv_icm42600_gyro_scale[2 * idx + 1];
+       *val = gyro_st->scales[2 * idx];
+       *val2 = gyro_st->scales[2 * idx + 1];
        return IIO_VAL_INT_PLUS_NANO;
 }
 
-static int inv_icm42600_gyro_write_scale(struct inv_icm42600_state *st,
+static int inv_icm42600_gyro_write_scale(struct iio_dev *indio_dev,
                                         int val, int val2)
 {
+       struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
        struct device *dev = regmap_get_device(st->map);
        unsigned int idx;
        struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
        int ret;
 
-       for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_gyro_scale); idx += 2) {
-               if (val == inv_icm42600_gyro_scale[idx] &&
-                   val2 == inv_icm42600_gyro_scale[idx + 1])
+       for (idx = 0; idx < gyro_st->scales_len; idx += 2) {
+               if (val == gyro_st->scales[idx] &&
+                   val2 == gyro_st->scales[idx + 1])
                        break;
        }
-       if (idx >= ARRAY_SIZE(inv_icm42600_gyro_scale))
+       if (idx >= gyro_st->scales_len)
                return -EINVAL;
 
        conf.fs = idx / 2;
                                       int val, int val2)
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
-       struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
+       struct inv_sensors_timestamp *ts = &gyro_st->ts;
        struct device *dev = regmap_get_device(st->map);
        unsigned int idx;
        struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
                *val = data;
                return IIO_VAL_INT;
        case IIO_CHAN_INFO_SCALE:
-               return inv_icm42600_gyro_read_scale(st, val, val2);
+               return inv_icm42600_gyro_read_scale(indio_dev, val, val2);
        case IIO_CHAN_INFO_SAMP_FREQ:
                return inv_icm42600_gyro_read_odr(st, val, val2);
        case IIO_CHAN_INFO_CALIBBIAS:
                                        const int **vals,
                                        int *type, int *length, long mask)
 {
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
+
        if (chan->type != IIO_ANGL_VEL)
                return -EINVAL;
 
        switch (mask) {
        case IIO_CHAN_INFO_SCALE:
-               *vals = inv_icm42600_gyro_scale;
+               *vals = gyro_st->scales;
                *type = IIO_VAL_INT_PLUS_NANO;
-               *length = ARRAY_SIZE(inv_icm42600_gyro_scale);
+               *length = gyro_st->scales_len;
                return IIO_AVAIL_LIST;
        case IIO_CHAN_INFO_SAMP_FREQ:
                *vals = inv_icm42600_gyro_odr;
                ret = iio_device_claim_direct_mode(indio_dev);
                if (ret)
                        return ret;
-               ret = inv_icm42600_gyro_write_scale(st, val, val2);
+               ret = inv_icm42600_gyro_write_scale(indio_dev, val, val2);
                iio_device_release_direct_mode(indio_dev);
                return ret;
        case IIO_CHAN_INFO_SAMP_FREQ:
 {
        struct device *dev = regmap_get_device(st->map);
        const char *name;
+       struct inv_icm42600_sensor_state *gyro_st;
        struct inv_sensors_timestamp_chip ts_chip;
-       struct inv_sensors_timestamp *ts;
        struct iio_dev *indio_dev;
        int ret;
 
        if (!name)
                return ERR_PTR(-ENOMEM);
 
-       indio_dev = devm_iio_device_alloc(dev, sizeof(*ts));
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
        if (!indio_dev)
                return ERR_PTR(-ENOMEM);
+       gyro_st = iio_priv(indio_dev);
+
+       switch (st->chip) {
+       case INV_CHIP_ICM42686:
+               gyro_st->scales = inv_icm42686_gyro_scale;
+               gyro_st->scales_len = ARRAY_SIZE(inv_icm42686_gyro_scale);
+               break;
+       default:
+               gyro_st->scales = inv_icm42600_gyro_scale;
+               gyro_st->scales_len = ARRAY_SIZE(inv_icm42600_gyro_scale);
+               break;
+       }
 
        /*
         * clock period is 32kHz (31250ns)
        ts_chip.clock_period = 31250;
        ts_chip.jitter = 20;
        ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
-       ts = iio_priv(indio_dev);
-       inv_sensors_timestamp_init(ts, &ts_chip);
+       inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);
 
        iio_device_set_drvdata(indio_dev, st);
        indio_dev->name = name;
 int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev)
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
-       struct inv_sensors_timestamp *ts = iio_priv(indio_dev);
+       struct inv_icm42600_sensor_state *gyro_st = iio_priv(indio_dev);
+       struct inv_sensors_timestamp *ts = &gyro_st->ts;
        ssize_t i, size;
        unsigned int no;
        const void *accel, *gyro, *timestamp;
 
        }, {
                .compatible = "invensense,icm42605",
                .data = (void *)INV_CHIP_ICM42605,
+       }, {
+               .compatible = "invensense,icm42686",
+               .data = (void *)INV_CHIP_ICM42686,
        }, {
                .compatible = "invensense,icm42622",
                .data = (void *)INV_CHIP_ICM42622,
 
        }, {
                .compatible = "invensense,icm42605",
                .data = (void *)INV_CHIP_ICM42605,
+       }, {
+               .compatible = "invensense,icm42686",
+               .data = (void *)INV_CHIP_ICM42686,
        }, {
                .compatible = "invensense,icm42622",
                .data = (void *)INV_CHIP_ICM42622,