* [PATCH v2 0/5] Add Invensense ICM42607
@ 2026-03-19 18:29 Chris Morgan
2026-03-19 18:29 ` [PATCH V2 1/5] dt-bindings: iio: imu: add icm42607 Chris Morgan
` (6 more replies)
0 siblings, 7 replies; 16+ messages in thread
From: Chris Morgan @ 2026-03-19 18:29 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
From: Chris Morgan <macromorgan@hotmail.com>
Add support for the ICM42607 IMU. This sensor shares the same
functionality but a different register layout with the existing
ICM42600.
This driver should work with the ICM42607 and ICM42607P over both I2C
and SPI, however only the ICM42607P over I2C could be tested.
Changes Since V1:
- Instead of creating a new driver, merged with the existing inv_icm42600
driver. This necessitated adding some code to the existing driver to
permit using a different register layout for the same functionality.
- Split changes up a bit more to decrease the size of the individual
patches. Note that patch 0004 is still pretty hefty; if I need to split
further I may need to create some temporary stub functions.
- Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
per Jonathan's recommendations.
Chris Morgan (5):
dt-bindings: iio: imu: add icm42607
iio: imu: inv_icm42600: Add support for using alternate registers
iio: imu: inv_icm42600: Add registers for icm42607
iio: imu: inv_icm42600: Add support for icm42607
arm64: dts: rockchip: Add icm42607p IMU for RG-DS
.../bindings/iio/imu/invensense,icm42600.yaml | 4 +
.../dts/rockchip/rk3568-anbernic-rg-ds.dts | 20 +-
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 333 +++++++-
.../iio/imu/inv_icm42600/inv_icm42600_accel.c | 497 ++++++++++-
.../imu/inv_icm42600/inv_icm42600_buffer.c | 240 +++++-
.../imu/inv_icm42600/inv_icm42600_buffer.h | 5 +
.../iio/imu/inv_icm42600/inv_icm42600_core.c | 795 +++++++++++++++---
.../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 379 ++++++++-
.../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 53 +-
.../iio/imu/inv_icm42600/inv_icm42600_spi.c | 59 +-
.../iio/imu/inv_icm42600/inv_icm42600_temp.c | 64 ++
.../iio/imu/inv_icm42600/inv_icm42600_temp.h | 4 +
12 files changed, 2289 insertions(+), 164 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH V2 1/5] dt-bindings: iio: imu: add icm42607
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
@ 2026-03-19 18:29 ` Chris Morgan
2026-03-20 17:39 ` Conor Dooley
2026-03-19 18:29 ` [PATCH V2 2/5] iio: imu: inv_icm42600: Add support for using alternate registers Chris Morgan
` (5 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Chris Morgan @ 2026-03-19 18:29 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
From: Chris Morgan <macromorgan@hotmail.com>
Add bindings for ICM-42607 and ICM-42607-P.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
.../devicetree/bindings/iio/imu/invensense,icm42600.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
index 119e28a833fd..b69c6bbb6f6b 100644
--- a/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
+++ b/Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
@@ -30,6 +30,8 @@ properties:
- invensense,icm42600
- invensense,icm42602
- invensense,icm42605
+ - invensense,icm42607
+ - invensense,icm42607p
- invensense,icm42622
- invensense,icm42631
- invensense,icm42686
@@ -53,6 +55,8 @@ properties:
drive-open-drain:
type: boolean
+ mount-matrix: true
+
vdd-supply:
description: Regulator that provides power to the sensor
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH V2 2/5] iio: imu: inv_icm42600: Add support for using alternate registers
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
2026-03-19 18:29 ` [PATCH V2 1/5] dt-bindings: iio: imu: add icm42607 Chris Morgan
@ 2026-03-19 18:29 ` Chris Morgan
2026-03-21 17:50 ` Jonathan Cameron
2026-03-19 18:29 ` [PATCH V2 3/5] iio: imu: inv_icm42600: Add registers for icm42607 Chris Morgan
` (4 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Chris Morgan @ 2026-03-19 18:29 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
From: Chris Morgan <macromorgan@hotmail.com>
Add support to the existing inv_icm42600 to support similar hardware
with slightly different register layouts. For example the icm42607
and icm42607p has most of the same functionality and even many of
the same registers, but the addresses for indiviual registers differ.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 28 +-
.../iio/imu/inv_icm42600/inv_icm42600_accel.c | 15 +-
.../iio/imu/inv_icm42600/inv_icm42600_core.c | 257 ++++++++++--------
.../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 13 +-
4 files changed, 188 insertions(+), 125 deletions(-)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index c8b48a5c5ed0..b89078cb5ba0 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -143,6 +143,26 @@ struct inv_icm42600_apex {
} wom;
};
+typedef int (*inv_icm42600_bus_setup)(struct inv_icm42600_state *);
+
+struct inv_icm42600_funcs {
+ int (*setup)(struct inv_icm42600_state *st,
+ inv_icm42600_bus_setup bus_setup);
+
+ /* timestamp_setup optional, not present on icm42607 */
+ int (*timestamp_setup)(struct inv_icm42600_state *st);
+
+ int (*buffer_init)(struct inv_icm42600_state *st);
+ int (*gyro_init)(struct inv_icm42600_state *st,
+ struct iio_dev *indio_dev);
+ int (*accel_init)(struct inv_icm42600_state *st,
+ struct iio_dev *indio_dev);
+ int (*suspend)(struct device *dev);
+ int (*resume)(struct device *dev);
+ int (*runtime_suspend)(struct device *dev);
+ int (*runtime_resume)(struct device *dev);
+};
+
/**
* struct inv_icm42600_state - driver state variables
* @lock: lock for serializing multiple registers access.
@@ -160,6 +180,7 @@ struct inv_icm42600_apex {
* @timestamp: interrupt timestamps.
* @apex: APEX (Advanced Pedometer and Event detection) management
* @fifo: FIFO management structure.
+ * @hw_funcs: Device specific hardware functions.
* @buffer: data transfer buffer aligned for DMA.
*/
struct inv_icm42600_state {
@@ -180,6 +201,7 @@ struct inv_icm42600_state {
} timestamp;
struct inv_icm42600_apex apex;
struct inv_icm42600_fifo fifo;
+ struct inv_icm42600_funcs *hw_funcs;
u8 buffer[3] __aligned(IIO_DMA_MINALIGN);
};
@@ -440,8 +462,6 @@ struct inv_icm42600_sensor_state {
#define INV_ICM42600_TEMP_STARTUP_TIME_MS 14
#define INV_ICM42600_SUSPEND_DELAY_MS 2000
-typedef int (*inv_icm42600_bus_setup)(struct inv_icm42600_state *);
-
extern const struct regmap_config inv_icm42600_regmap_config;
extern const struct regmap_config inv_icm42600_spi_regmap_config;
extern const struct dev_pm_ops inv_icm42600_pm_ops;
@@ -472,11 +492,11 @@ int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
int inv_icm42600_core_probe(struct regmap *regmap, int chip,
inv_icm42600_bus_setup bus_setup);
-struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st);
+int inv_icm42600_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev);
int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev);
-struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st);
+int inv_icm42600_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev);
int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index 0ab6eddf0543..cbb27c4e6b82 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -1137,22 +1137,21 @@ static const struct iio_info inv_icm42600_accel_info = {
.write_event_value = inv_icm42600_accel_write_event_value,
};
-struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
+int inv_icm42600_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
{
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 iio_dev *indio_dev;
int ret;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name);
if (!name)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
if (!indio_dev)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
accel_st = iio_priv(indio_dev);
switch (st->chip) {
@@ -1189,18 +1188,18 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
&inv_icm42600_buffer_ops);
if (ret)
- return ERR_PTR(ret);
+ return ret;
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
- return ERR_PTR(ret);
+ return ret;
/* accel events are wakeup capable */
ret = devm_device_init_wakeup(&indio_dev->dev);
if (ret)
- return ERR_PTR(ret);
+ return ret;
- return indio_dev;
+ return 0;
}
int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 76eb22488e5f..29c8c1871e06 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -703,113 +703,11 @@ static void inv_icm42600_disable_vddio_reg(void *_data)
regulator_disable(st->vddio_supply);
}
-int inv_icm42600_core_probe(struct regmap *regmap, int chip,
- inv_icm42600_bus_setup bus_setup)
-{
- struct device *dev = regmap_get_device(regmap);
- struct fwnode_handle *fwnode = dev_fwnode(dev);
- struct inv_icm42600_state *st;
- int irq, irq_type;
- bool open_drain;
- int ret;
-
- if (chip <= INV_CHIP_INVALID || chip >= INV_CHIP_NB) {
- dev_err(dev, "invalid chip = %d\n", chip);
- return -ENODEV;
- }
-
- /* get INT1 only supported interrupt or fallback to first interrupt */
- irq = fwnode_irq_get_byname(fwnode, "INT1");
- if (irq < 0 && irq != -EPROBE_DEFER) {
- dev_info(dev, "no INT1 interrupt defined, fallback to first interrupt\n");
- irq = fwnode_irq_get(fwnode, 0);
- }
- if (irq < 0)
- return dev_err_probe(dev, irq, "error missing INT1 interrupt\n");
-
- irq_type = irq_get_trigger_type(irq);
- if (!irq_type)
- irq_type = IRQF_TRIGGER_FALLING;
-
- open_drain = device_property_read_bool(dev, "drive-open-drain");
-
- st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
- if (!st)
- return -ENOMEM;
-
- dev_set_drvdata(dev, st);
- mutex_init(&st->lock);
- st->chip = chip;
- st->map = regmap;
- st->irq = irq;
-
- ret = iio_read_mount_matrix(dev, &st->orientation);
- if (ret) {
- dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
- return ret;
- }
-
- ret = devm_regulator_get_enable(dev, "vdd");
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to get vdd regulator\n");
-
- msleep(INV_ICM42600_POWER_UP_TIME_MS);
-
- st->vddio_supply = devm_regulator_get(dev, "vddio");
- if (IS_ERR(st->vddio_supply))
- return PTR_ERR(st->vddio_supply);
-
- ret = inv_icm42600_enable_regulator_vddio(st);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vddio_reg, st);
- if (ret)
- return ret;
-
- /* setup chip registers */
- ret = inv_icm42600_setup(st, bus_setup);
- if (ret)
- return ret;
-
- ret = inv_icm42600_timestamp_setup(st);
- if (ret)
- return ret;
-
- ret = inv_icm42600_buffer_init(st);
- if (ret)
- return ret;
-
- st->indio_gyro = inv_icm42600_gyro_init(st);
- if (IS_ERR(st->indio_gyro))
- return PTR_ERR(st->indio_gyro);
-
- st->indio_accel = inv_icm42600_accel_init(st);
- if (IS_ERR(st->indio_accel))
- return PTR_ERR(st->indio_accel);
-
- ret = inv_icm42600_irq_init(st, irq, irq_type, open_drain);
- if (ret)
- return ret;
-
- /* setup runtime power management */
- ret = devm_pm_runtime_set_active_enabled(dev);
- if (ret)
- return ret;
-
- pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS);
- pm_runtime_use_autosuspend(dev);
-
- return ret;
-}
-EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, "IIO_ICM42600");
-
/*
* Suspend saves sensors state and turns everything off.
* Check first if runtime suspend has not already done the job.
*/
-static int inv_icm42600_suspend(struct device *dev)
+static int inv_icm42600_hw_suspend(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
struct device *accel_dev;
@@ -867,7 +765,7 @@ static int inv_icm42600_suspend(struct device *dev)
* System resume gets the system back on and restores the sensors state.
* Manually put runtime power management in system active state.
*/
-static int inv_icm42600_resume(struct device *dev)
+static int inv_icm42600_hw_resume(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
struct inv_icm42600_sensor_state *gyro_st = iio_priv(st->indio_gyro);
@@ -920,7 +818,7 @@ static int inv_icm42600_resume(struct device *dev)
}
/* Runtime suspend will turn off sensors that are enabled by iio devices. */
-static int inv_icm42600_runtime_suspend(struct device *dev)
+static int inv_icm42600_hw_runtime_suspend(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
int ret;
@@ -940,7 +838,7 @@ static int inv_icm42600_runtime_suspend(struct device *dev)
}
/* Sensors are enabled by iio devices, no need to turn them back on here. */
-static int inv_icm42600_runtime_resume(struct device *dev)
+static int inv_icm42600_hw_runtime_resume(struct device *dev)
{
struct inv_icm42600_state *st = dev_get_drvdata(dev);
@@ -949,6 +847,153 @@ static int inv_icm42600_runtime_resume(struct device *dev)
return inv_icm42600_enable_regulator_vddio(st);
}
+static struct inv_icm42600_funcs inv_icm42600_hw_funcs = {
+ .setup = &inv_icm42600_setup,
+ .timestamp_setup = &inv_icm42600_timestamp_setup,
+ .buffer_init = &inv_icm42600_buffer_init,
+ .gyro_init = &inv_icm42600_gyro_init,
+ .accel_init = &inv_icm42600_accel_init,
+ .suspend = &inv_icm42600_hw_suspend,
+ .resume = &inv_icm42600_hw_resume,
+ .runtime_suspend = &inv_icm42600_hw_runtime_suspend,
+ .runtime_resume = &inv_icm42600_hw_runtime_resume,
+};
+
+int inv_icm42600_core_probe(struct regmap *regmap, int chip,
+ inv_icm42600_bus_setup bus_setup)
+{
+ struct device *dev = regmap_get_device(regmap);
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct inv_icm42600_state *st;
+ int irq, irq_type;
+ bool open_drain;
+ int ret;
+
+ if (chip <= INV_CHIP_INVALID || chip >= INV_CHIP_NB) {
+ dev_err(dev, "invalid chip = %d\n", chip);
+ return -ENODEV;
+ }
+
+ /* get INT1 only supported interrupt or fallback to first interrupt */
+ irq = fwnode_irq_get_byname(fwnode, "INT1");
+ if (irq < 0 && irq != -EPROBE_DEFER) {
+ dev_info(dev, "no INT1 interrupt defined, fallback to first interrupt\n");
+ irq = fwnode_irq_get(fwnode, 0);
+ }
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "error missing INT1 interrupt\n");
+
+ irq_type = irq_get_trigger_type(irq);
+ if (!irq_type)
+ irq_type = IRQF_TRIGGER_FALLING;
+
+ open_drain = device_property_read_bool(dev, "drive-open-drain");
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, st);
+ mutex_init(&st->lock);
+ st->chip = chip;
+ st->map = regmap;
+ st->irq = irq;
+
+ ret = iio_read_mount_matrix(dev, &st->orientation);
+ if (ret) {
+ dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get vdd regulator\n");
+
+ msleep(INV_ICM42600_POWER_UP_TIME_MS);
+
+ st->vddio_supply = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(st->vddio_supply))
+ return PTR_ERR(st->vddio_supply);
+
+ ret = inv_icm42600_enable_regulator_vddio(st);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, inv_icm42600_disable_vddio_reg, st);
+ if (ret)
+ return ret;
+
+ /* setup chip registers based on hardware */
+ st->hw_funcs = &inv_icm42600_hw_funcs;
+
+ ret = st->hw_funcs->setup(st, bus_setup);
+ if (ret)
+ return ret;
+
+ /* Timestamp setup optional for ICM42607 */
+ if (st->hw_funcs->timestamp_setup) {
+ ret = st->hw_funcs->timestamp_setup(st);
+ if (ret)
+ return ret;
+ }
+
+ ret = st->hw_funcs->buffer_init(st);
+ if (ret)
+ return ret;
+
+ ret = st->hw_funcs->gyro_init(st, st->indio_gyro);
+ if (ret)
+ return ret;
+
+ ret = st->hw_funcs->accel_init(st, st->indio_accel);
+ if (ret)
+ return ret;
+
+ ret = inv_icm42600_irq_init(st, irq, irq_type, open_drain);
+ if (ret)
+ return ret;
+
+ /* setup runtime power management */
+ ret = devm_pm_runtime_set_active_enabled(dev);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(inv_icm42600_core_probe, "IIO_ICM42600");
+
+static int inv_icm42600_suspend(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+
+ return st->hw_funcs->suspend(dev);
+}
+
+static int inv_icm42600_resume(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+
+ return st->hw_funcs->resume(dev);
+}
+
+static int inv_icm42600_runtime_suspend(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+
+ return st->hw_funcs->runtime_suspend(dev);
+}
+
+static int inv_icm42600_runtime_resume(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+
+ return st->hw_funcs->runtime_resume(dev);
+}
+
EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42600_pm_ops, IIO_ICM42600) = {
SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 11339ddf1da3..32aa2e52df2e 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -725,22 +725,21 @@ static const struct iio_info inv_icm42600_gyro_info = {
.hwfifo_flush_to_buffer = inv_icm42600_gyro_hwfifo_flush,
};
-struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
+int inv_icm42600_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
{
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 iio_dev *indio_dev;
int ret;
name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->name);
if (!name)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
if (!indio_dev)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
gyro_st = iio_priv(indio_dev);
switch (st->chip) {
@@ -775,13 +774,13 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
&inv_icm42600_buffer_ops);
if (ret)
- return ERR_PTR(ret);
+ return ret;
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
- return ERR_PTR(ret);
+ return ret;
- return indio_dev;
+ return 0;
}
int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev)
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH V2 3/5] iio: imu: inv_icm42600: Add registers for icm42607
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
2026-03-19 18:29 ` [PATCH V2 1/5] dt-bindings: iio: imu: add icm42607 Chris Morgan
2026-03-19 18:29 ` [PATCH V2 2/5] iio: imu: inv_icm42600: Add support for using alternate registers Chris Morgan
@ 2026-03-19 18:29 ` Chris Morgan
2026-03-21 17:25 ` Jonathan Cameron
2026-03-19 18:29 ` [PATCH V2 4/5] iio: imu: inv_icm42600: Add support " Chris Morgan
` (3 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Chris Morgan @ 2026-03-19 18:29 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
From: Chris Morgan <macromorgan@hotmail.com>
Add the register layout for the icm_42607. Most of the registers are
similar to that of the icm42600, though at different addresses.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 284 ++++++++++++++++++++
1 file changed, 284 insertions(+)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index b89078cb5ba0..ab3616c5ee1a 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -22,6 +22,8 @@ enum inv_icm42600_chip {
INV_CHIP_ICM42600,
INV_CHIP_ICM42602,
INV_CHIP_ICM42605,
+ INV_CHIP_ICM42607,
+ INV_CHIP_ICM42607P,
INV_CHIP_ICM42686,
INV_CHIP_ICM42622,
INV_CHIP_ICM42688,
@@ -70,6 +72,13 @@ enum inv_icm42686_gyro_fs {
INV_ICM42686_GYRO_FS_31_25DPS,
INV_ICM42686_GYRO_FS_NB,
};
+enum inv_icm42607_gyro_fs {
+ INV_ICM42607_GYRO_FS_2000DPS,
+ INV_ICM42607_GYRO_FS_1000DPS,
+ INV_ICM42607_GYRO_FS_500DPS,
+ INV_ICM42607_GYRO_FS_250DPS,
+ INV_ICM42607_GYRO_FS_NB
+};
/* accelerometer fullscale values */
enum inv_icm42600_accel_fs {
@@ -106,6 +115,21 @@ enum inv_icm42600_odr {
INV_ICM42600_ODR_NB,
};
+enum inv_icm42607_odr {
+ INV_ICM42607_ODR_1600HZ = 5,
+ INV_ICM42607_ODR_800HZ,
+ INV_ICM42607_ODR_400HZ,
+ INV_ICM42607_ODR_200HZ,
+ INV_ICM42607_ODR_100HZ,
+ INV_ICM42607_ODR_50HZ,
+ INV_ICM42607_ODR_25HZ,
+ INV_ICM42607_ODR_12_5HZ,
+ INV_ICM42607_ODR_6_25HZ_LP,
+ INV_ICM42607_ODR_3_125HZ_LP,
+ INV_ICM42607_ODR_1_5625HZ_LP,
+ INV_ICM42607_ODR_NB
+};
+
enum inv_icm42600_filter {
/* Low-Noise mode sensor data filter (3rd order filter by default) */
INV_ICM42600_FILTER_BW_ODR_DIV_2,
@@ -115,6 +139,26 @@ enum inv_icm42600_filter {
INV_ICM42600_FILTER_AVG_16X = 6,
};
+enum inv_icm42607_filter {
+ /* Low-Noise mode sensor data filter */
+ INV_ICM42607_FILTER_BYPASS,
+ INV_ICM42607_FILTER_BW_180HZ,
+ INV_ICM42607_FILTER_BW_121HZ,
+ INV_ICM42607_FILTER_BW_73HZ,
+ INV_ICM42607_FILTER_BW_53HZ,
+ INV_ICM42607_FILTER_BW_34HZ,
+ INV_ICM42607_FILTER_BW_25HZ,
+ INV_ICM42607_FILTER_BW_16HZ,
+
+ /* Low-Power mode sensor data filter (averaging) */
+ INV_ICM42607_FILTER_AVG_2X = 0,
+ INV_ICM42607_FILTER_AVG_4X,
+ INV_ICM42607_FILTER_AVG_8X,
+ INV_ICM42607_FILTER_AVG_16X,
+ INV_ICM42607_FILTER_AVG_32X,
+ INV_ICM42607_FILTER_AVG_64X,
+};
+
struct inv_icm42600_sensor_conf {
int mode;
int fs;
@@ -453,6 +497,246 @@ struct inv_icm42600_sensor_state {
#define INV_ICM42600_REG_OFFSET_USER7 0x407E
#define INV_ICM42600_REG_OFFSET_USER8 0x407F
+/* ICM42607 Specific registers. */
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_DEVICE_CONFIG 0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET 0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1 0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR(_rate) \
+FIELD_PREP(INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK, (_rate))
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK GENMASK(2, 0)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR(_rate) \
+FIELD_PREP(INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK, (_rate))
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2 0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_I2C(_rate) \
+FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, (_rate))
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK GENMASK(2, 0)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL(_rate) \
+FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_ALL_MASK, (_rate))
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3 0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK GENMASK(2, 0)
+#define INV_ICM42607_DRIVE_CONFIG3_SPI(_rate) \
+FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, (_rate))
+
+#define INV_ICM42607_REG_INT_CONFIG 0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW 0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW 0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1 0x09
+#define INV_ICM42607_REG_TEMP_DATA0 0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1 0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0 0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1 0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0 0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1 0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0 0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1 0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0 0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1 0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0 0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1 0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0 0x16
+#define INV_ICM42607_DATA_INVALID -32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH 0x17
+#define INV_ICM42607_REG_TMST_FSYNCL 0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0 0x31
+#define INV_ICM42607_REG_APEX_DATA1 0x32
+#define INV_ICM42607_REG_APEX_DATA2 0x33
+#define INV_ICM42607_REG_APEX_DATA3 0x34
+#define INV_ICM42607_REG_APEX_DATA4 0x1D
+#define INV_ICM42607_REG_APEX_DATA5 0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0 0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_GYRO(_mode) \
+FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, (_mode))
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK GENMASK(1, 0)
+#define INV_ICM42607_PWR_MGMT0_ACCEL(_mode) \
+FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, (_mode))
+
+#define INV_ICM42607_REG_GYRO_CONFIG0 0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL(_fs) \
+FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, (_fs))
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK GENMASK(3, 0)
+#define INV_ICM42607_GYRO_CONFIG0_ODR(_odr) \
+FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, (_odr))
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0 0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL(_fs) \
+FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, (_fs))
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK GENMASK(3, 0)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR(_odr) \
+FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, (_odr))
+
+#define INV_ICM42607_REG_TEMP_CONFIG0 0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK GENMASK(6, 4)
+#define INV_ICM42607_TEMP_CONFIG0_FILTER(_filter) \
+FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, (_filter))
+
+#define INV_ICM42607_REG_GYRO_CONFIG1 0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK GENMASK(2, 0)
+#define INV_ICM42607_GYRO_CONFIG1_FILTER(_filter) \
+FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, (_filter))
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1 0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_AVG(_avg) \
+FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, (_avg))
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK GENMASK(2, 0)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER(_filter) \
+FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, (_filter))
+
+#define INV_ICM42607_REG_APEX_CONFIG0 0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1 0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK GENMASK(1, 0)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR(_odr) \
+FIELD_PREP(INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK, (_odr))
+
+#define INV_ICM42607_REG_WOM_CONFIG 0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_DUR(_dur) \
+FIELD_PREP(INV_ICM42607_WOM_CONFIG_INT_DUR_MASK, (_dur))
+#define INV_ICM42607_WOM_CONFIG_INT_MODE BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1 0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2 0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3 0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm) \
+ cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX (2048 - 12 * 16)
+
+#define INV_ICM42607_REG_INT_SOURCE0 0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1 0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3 0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4 0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0 0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1 0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0 0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS \
+FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS \
+FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
+
+#define INV_ICM42607_REG_INTF_CONFIG1 0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL \
+FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK, 1)
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY 0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS 0x3A
+#define INV_ICM42607_INT_STATUS_ST BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2 0x3B
+#define INV_ICM42607_INT_STATUS2_SMD BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3 0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH 0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL 0x3E
+#define INV_ICM42607_REG_FIFO_DATA 0x3F
+
+#define INV_ICM42607_REG_ACCEL_WOM_X_THR 0x4b
+#define INV_ICM42607_REG_ACCEL_WOM_Y_THR 0x4c
+#define INV_ICM42607_REG_ACCEL_WOM_Z_THR 0x4d
+
+#define INV_ICM42607_REG_WHOAMI 0x75
+#define INV_ICM42607P_WHOAMI 0x60
+#define INV_ICM42607_WHOAMI 0x67
+
/* Sleep times required by the driver */
#define INV_ICM42600_POWER_UP_TIME_MS 100
#define INV_ICM42600_RESET_TIME_MS 1
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH V2 4/5] iio: imu: inv_icm42600: Add support for icm42607
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
` (2 preceding siblings ...)
2026-03-19 18:29 ` [PATCH V2 3/5] iio: imu: inv_icm42600: Add registers for icm42607 Chris Morgan
@ 2026-03-19 18:29 ` Chris Morgan
2026-03-20 16:44 ` kernel test robot
` (2 more replies)
2026-03-19 18:29 ` [PATCH V2 5/5] arm64: dts: rockchip: Add icm42607p IMU for RG-DS Chris Morgan
` (2 subsequent siblings)
6 siblings, 3 replies; 16+ messages in thread
From: Chris Morgan @ 2026-03-19 18:29 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
From: Chris Morgan <macromorgan@hotmail.com>
Add support for the icm42607 and icm42607p over both I2C and SPI.
Note that at this time only the icm42607 over i2c has been tested.
This driver was updated based on the existing icm42600 along with
the datasheet from Invensense and out-of-tree sources included
in the LineageOS kernels [1] and Rockchip kernels [2], both derived
from sources provided by Invensense.
[1] https://github.com/LineageOS/android_kernel_nvidia_kernel-nx/tree/lineage-23.0/drivers/iio/imu/inv_icm42607x
[2] https://github.com/rockchip-linux/kernel/tree/develop-6.6/drivers/iio/imu/inv_icm42670
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
drivers/iio/imu/inv_icm42600/inv_icm42600.h | 25 +-
.../iio/imu/inv_icm42600/inv_icm42600_accel.c | 482 +++++++++++++++-
.../imu/inv_icm42600/inv_icm42600_buffer.c | 240 +++++++-
.../imu/inv_icm42600/inv_icm42600_buffer.h | 5 +
.../iio/imu/inv_icm42600/inv_icm42600_core.c | 544 +++++++++++++++++-
.../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 366 +++++++++++-
.../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 53 +-
.../iio/imu/inv_icm42600/inv_icm42600_spi.c | 59 +-
.../iio/imu/inv_icm42600/inv_icm42600_temp.c | 64 +++
.../iio/imu/inv_icm42600/inv_icm42600_temp.h | 4 +
10 files changed, 1799 insertions(+), 43 deletions(-)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
index ab3616c5ee1a..9f25632f1915 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
@@ -262,7 +262,7 @@ struct inv_icm42600_sensor_state {
const int *scales;
size_t scales_len;
enum inv_icm42600_sensor_mode power_mode;
- enum inv_icm42600_filter filter;
+ int filter; /* either inv_icm42600_filter or inv_icm42607_filter */
struct inv_sensors_timestamp ts;
};
@@ -748,6 +748,7 @@ FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK, 1)
extern const struct regmap_config inv_icm42600_regmap_config;
extern const struct regmap_config inv_icm42600_spi_regmap_config;
+extern const struct regmap_config inv_icm42607_regmap_config;
extern const struct dev_pm_ops inv_icm42600_pm_ops;
const struct iio_mount_matrix *
@@ -755,20 +756,32 @@ inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan);
u32 inv_icm42600_odr_to_period(enum inv_icm42600_odr odr);
+u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr);
int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
struct inv_icm42600_sensor_conf *conf,
unsigned int *sleep_ms);
+int inv_icm42607_set_accel_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms);
int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
struct inv_icm42600_sensor_conf *conf,
unsigned int *sleep_ms);
+int inv_icm42607_set_gyro_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms);
int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
unsigned int *sleep_ms);
+int inv_icm42607_set_temp_conf(struct inv_icm42600_state *st, bool enable,
+ unsigned int *sleep_ms);
int inv_icm42600_enable_wom(struct inv_icm42600_state *st);
+int inv_icm42607_enable_wom(struct inv_icm42600_state *st);
+
int inv_icm42600_disable_wom(struct inv_icm42600_state *st);
+int inv_icm42607_disable_wom(struct inv_icm42600_state *st);
int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval);
@@ -776,11 +789,17 @@ int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
int inv_icm42600_core_probe(struct regmap *regmap, int chip,
inv_icm42600_bus_setup bus_setup);
-int inv_icm42600_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev);
+int inv_icm42600_gyro_init(struct inv_icm42600_state *st,
+ struct iio_dev *indio_dev);
+int inv_icm42607_gyro_init(struct inv_icm42600_state *st,
+ struct iio_dev *indio_dev);
int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev);
-int inv_icm42600_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev);
+int inv_icm42600_accel_init(struct inv_icm42600_state *st,
+ struct iio_dev *indio_dev);
+int inv_icm42607_accel_init(struct inv_icm42600_state *st,
+ struct iio_dev *indio_dev);
int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
index cbb27c4e6b82..27066635d5f4 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
@@ -50,6 +50,31 @@
.ext_info = _ext_info, \
}
+#define INV_ICM42607_ACCEL_CHAN(_modifier, _index, _ext_info) \
+ { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = _modifier, \
+ .info_mask_separate = \
+ BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ .ext_info = _ext_info, \
+ }
+
#define INV_ICM42600_ACCEL_EVENT_CHAN(_modifier, _events, _events_nb) \
{ \
.type = IIO_ACCEL, \
@@ -80,6 +105,10 @@ static const int inv_icm42600_accel_filter_values[] = {
INV_ICM42600_FILTER_BW_ODR_DIV_2,
INV_ICM42600_FILTER_AVG_16X,
};
+static const int inv_icm42607_accel_filter_values[] = {
+ INV_ICM42607_FILTER_BW_25HZ,
+ INV_ICM42607_FILTER_AVG_16X,
+};
static int inv_icm42600_accel_power_mode_set(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
@@ -197,6 +226,19 @@ static const struct iio_chan_spec inv_icm42600_accel_channels[] = {
ARRAY_SIZE(inv_icm42600_wom_events)),
};
+static const struct iio_chan_spec inv_icm42607_accel_channels[] = {
+ INV_ICM42607_ACCEL_CHAN(IIO_MOD_X, INV_ICM42600_ACCEL_SCAN_X,
+ inv_icm42600_accel_ext_infos),
+ INV_ICM42607_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42600_ACCEL_SCAN_Y,
+ inv_icm42600_accel_ext_infos),
+ INV_ICM42607_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z,
+ inv_icm42600_accel_ext_infos),
+ INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP),
+ IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP),
+ INV_ICM42600_ACCEL_EVENT_CHAN(IIO_MOD_X_OR_Y_OR_Z, inv_icm42600_wom_events,
+ ARRAY_SIZE(inv_icm42600_wom_events)),
+};
+
/*
* IIO buffer data: size must be a power of 2 and timestamp aligned
* 16 bytes: 6 bytes acceleration, 2 bytes temperature, 8 bytes timestamp
@@ -265,6 +307,49 @@ static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev,
return ret;
}
+static int inv_icm42607_accel_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int fifo_en = 0;
+ unsigned int sleep_temp = 0;
+ unsigned int sleep_accel = 0;
+ unsigned int sleep;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_TEMP) {
+ /* enable temp sensor */
+ ret = inv_icm42607_set_temp_conf(st, true, &sleep_temp);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_TEMP;
+ }
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_ACCEL_3AXIS) {
+ /* enable accel sensor */
+ conf.mode = accel_st->power_mode;
+ conf.filter = accel_st->filter;
+ ret = inv_icm42607_set_accel_conf(st, &conf, &sleep_accel);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_ACCEL;
+ }
+
+ /* update data FIFO write */
+ ret = inv_icm42607_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
+
+out_unlock:
+ /* sleep maximum required time */
+ sleep = max(sleep_accel, sleep_temp);
+ if (sleep)
+ msleep(sleep);
+ return ret;
+}
+
static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
s16 *val)
@@ -319,6 +404,61 @@ static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev,
return ret;
}
+static int inv_icm42607_accel_read_sensor(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ s16 *val)
+{
+ 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);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int reg;
+ __be16 *data;
+ int ret;
+
+ if (chan->type != IIO_ACCEL)
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ reg = INV_ICM42607_REG_ACCEL_DATA_X1;
+ break;
+ case IIO_MOD_Y:
+ reg = INV_ICM42607_REG_ACCEL_DATA_Y1;
+ break;
+ case IIO_MOD_Z:
+ reg = INV_ICM42607_REG_ACCEL_DATA_Z1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return -ENXIO;
+
+ guard(mutex)(&st->lock);
+
+ /* enable accel sensor */
+ conf.mode = accel_st->power_mode;
+ conf.filter = accel_st->filter;
+ ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+ if (ret)
+ return ret;
+
+ /* read accel register data */
+ data = (__be16 *)&st->buffer[0];
+ ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+ if (ret)
+ return ret;
+
+ *val = (int16_t)be16_to_cpup(data);
+ if (*val == INV_ICM42600_DATA_INVALID)
+ ret = -EINVAL;
+
+ return ret;
+}
+
static unsigned int inv_icm42600_accel_convert_roc_to_wom(u64 roc,
int accel_hz, int accel_uhz)
{
@@ -359,6 +499,7 @@ static int inv_icm42600_accel_set_wom_threshold(struct inv_icm42600_state *st,
{
unsigned int threshold;
int ret;
+ u32 wom_thresh_reg;
/* convert roc to wom threshold and convert back to handle clipping */
threshold = inv_icm42600_accel_convert_roc_to_wom(value, accel_hz, accel_uhz);
@@ -366,11 +507,20 @@ static int inv_icm42600_accel_set_wom_threshold(struct inv_icm42600_state *st,
dev_dbg(regmap_get_device(st->map), "wom_threshold: 0x%x\n", threshold);
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ wom_thresh_reg = INV_ICM42607_REG_ACCEL_WOM_X_THR;
+ break;
+ default:
+ wom_thresh_reg = INV_ICM42600_REG_ACCEL_WOM_X_THR;
+ break;
+ }
/* set accel WoM threshold for the 3 axes */
st->buffer[0] = threshold;
st->buffer[1] = threshold;
st->buffer[2] = threshold;
- ret = regmap_bulk_write(st->map, INV_ICM42600_REG_ACCEL_WOM_X_THR, st->buffer, 3);
+ ret = regmap_bulk_write(st->map, wom_thresh_reg, st->buffer, 3);
if (ret)
return ret;
@@ -410,6 +560,37 @@ static int _inv_icm42600_accel_enable_wom(struct iio_dev *indio_dev)
return 0;
}
+static int _inv_icm42607_accel_enable_wom(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int sleep_ms = 0;
+ int ret;
+
+ scoped_guard(mutex, &st->lock) {
+ /* turn on accel sensor */
+ conf.mode = accel_st->power_mode;
+ conf.filter = accel_st->filter;
+ ret = inv_icm42607_set_accel_conf(st, &conf, &sleep_ms);
+ if (ret)
+ return ret;
+ }
+
+ if (sleep_ms)
+ msleep(sleep_ms);
+
+ scoped_guard(mutex, &st->lock) {
+ ret = inv_icm42607_enable_wom(st);
+ if (ret)
+ return ret;
+ st->apex.on++;
+ st->apex.wom.enable = true;
+ }
+
+ return 0;
+}
+
static int inv_icm42600_accel_enable_wom(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
@@ -420,7 +601,15 @@ static int inv_icm42600_accel_enable_wom(struct iio_dev *indio_dev)
if (ret)
return ret;
- ret = _inv_icm42600_accel_enable_wom(indio_dev);
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ ret = _inv_icm42607_accel_enable_wom(indio_dev);
+ break;
+ default:
+ ret = _inv_icm42600_accel_enable_wom(indio_dev);
+ break;
+ }
if (ret) {
pm_runtime_mark_last_busy(pdev);
pm_runtime_put_autosuspend(pdev);
@@ -464,13 +653,49 @@ static int _inv_icm42600_accel_disable_wom(struct iio_dev *indio_dev)
return 0;
}
+static int _inv_icm42607_accel_disable_wom(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int sleep_ms = 0;
+ int ret;
+
+ scoped_guard(mutex, &st->lock) {
+ st->apex.wom.enable = false;
+ st->apex.on--;
+ ret = inv_icm42607_disable_wom(st);
+ if (ret)
+ return ret;
+ /* turn off accel sensor if not used */
+ if (!st->apex.on && !iio_buffer_enabled(indio_dev)) {
+ conf.mode = INV_ICM42600_SENSOR_MODE_OFF;
+ ret = inv_icm42607_set_accel_conf(st, &conf, &sleep_ms);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (sleep_ms)
+ msleep(sleep_ms);
+
+ return 0;
+}
+
static int inv_icm42600_accel_disable_wom(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
struct device *pdev = regmap_get_device(st->map);
int ret;
- ret = _inv_icm42600_accel_disable_wom(indio_dev);
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ ret = _inv_icm42607_accel_disable_wom(indio_dev);
+ break;
+ default:
+ ret = _inv_icm42600_accel_disable_wom(indio_dev);
+ break;
+ }
pm_runtime_mark_last_busy(pdev);
pm_runtime_put_autosuspend(pdev);
@@ -560,12 +785,21 @@ static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev,
conf.fs = idx / 2;
- pm_runtime_get_sync(dev);
-
- scoped_guard(mutex, &st->lock)
- ret = inv_icm42600_set_accel_conf(st, &conf, NULL);
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return -ENXIO;
- pm_runtime_put_autosuspend(dev);
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ scoped_guard(mutex, &st->lock)
+ ret = inv_icm42600_set_accel_conf(st, &conf, NULL);
+ break;
+ default:
+ scoped_guard(mutex, &st->lock)
+ ret = inv_icm42600_set_accel_conf(st, &conf, NULL);
+ break;
+ }
return ret;
}
@@ -596,6 +830,20 @@ static const int inv_icm42600_accel_odr[] = {
4000, 0,
};
+static const int inv_icm42607_accel_odr[] = {
+ 1, 562500, /* 1.5625Hz */
+ 3, 125000, /* 3.125Hz */
+ 6, 250000, /* 6.25Hz */
+ 12, 500000, /* 12.5Hz */
+ 25, 0, /* 25Hz */
+ 50, 0, /* 50Hz */
+ 100, 0, /* 100Hz */
+ 200, 0, /* 200Hz */
+ 400, 0, /* 400Hz */
+ 800, 0, /* 800Hz */
+ 1600, 0, /* 1600Hz */
+};
+
static const int inv_icm42600_accel_odr_conv[] = {
INV_ICM42600_ODR_1_5625HZ_LP,
INV_ICM42600_ODR_3_125HZ_LP,
@@ -610,6 +858,20 @@ static const int inv_icm42600_accel_odr_conv[] = {
INV_ICM42600_ODR_4KHZ_LN,
};
+static const int inv_icm42607_accel_odr_conv[] = {
+ INV_ICM42607_ODR_1_5625HZ_LP,
+ INV_ICM42607_ODR_3_125HZ_LP,
+ INV_ICM42607_ODR_6_25HZ_LP,
+ INV_ICM42607_ODR_12_5HZ,
+ INV_ICM42607_ODR_25HZ,
+ INV_ICM42607_ODR_50HZ,
+ INV_ICM42607_ODR_100HZ,
+ INV_ICM42607_ODR_200HZ,
+ INV_ICM42607_ODR_400HZ,
+ INV_ICM42607_ODR_800HZ,
+ INV_ICM42607_ODR_1600HZ,
+};
+
static int inv_icm42600_accel_read_odr(struct inv_icm42600_state *st,
int *val, int *val2)
{
@@ -631,6 +893,27 @@ static int inv_icm42600_accel_read_odr(struct inv_icm42600_state *st,
return IIO_VAL_INT_PLUS_MICRO;
}
+static int inv_icm42607_accel_read_odr(struct inv_icm42600_state *st,
+ int *val, int *val2)
+{
+ unsigned int odr;
+ unsigned int i;
+
+ odr = st->conf.accel.odr;
+
+ for (i = 0; i < ARRAY_SIZE(inv_icm42607_accel_odr_conv); ++i) {
+ if (inv_icm42607_accel_odr_conv[i] == odr)
+ break;
+ }
+ if (i >= ARRAY_SIZE(inv_icm42607_accel_odr_conv))
+ return -EINVAL;
+
+ *val = inv_icm42607_accel_odr[2 * i];
+ *val2 = inv_icm42607_accel_odr[2 * i + 1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev,
int val, int val2)
{
@@ -679,6 +962,50 @@ static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev,
return ret;
}
+static int inv_icm42607_accel_write_odr(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 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;
+ int ret;
+
+ for (idx = 0; idx < ARRAY_SIZE(inv_icm42607_accel_odr); idx += 2) {
+ if (val == inv_icm42607_accel_odr[idx] &&
+ val2 == inv_icm42607_accel_odr[idx + 1])
+ break;
+ }
+ if (idx >= ARRAY_SIZE(inv_icm42607_accel_odr))
+ return -EINVAL;
+
+ conf.odr = inv_icm42607_accel_odr_conv[idx / 2];
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return -ENXIO;
+
+ guard(mutex)(&st->lock);
+
+ ret = inv_sensors_timestamp_update_odr(ts, inv_icm42607_odr_to_period(conf.odr),
+ iio_buffer_enabled(indio_dev));
+ if (ret)
+ return ret;
+
+ ret = inv_icm42607_set_accel_conf(st, &conf, NULL);
+ if (ret)
+ return ret;
+ ret = inv_icm42600_accel_set_wom_threshold(st, st->apex.wom.value, val, val2);
+ if (ret)
+ return ret;
+ inv_icm42607_buffer_update_fifo_period(st);
+ inv_icm42600_buffer_update_watermark(st);
+
+ return 0;
+}
+
/*
* Calibration bias values, IIO range format int + micro.
* Value is limited to +/-1g coded on 12 bits signed. Step is 0.5mg.
@@ -904,6 +1231,42 @@ static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev,
}
}
+static int inv_icm42607_accel_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ s16 data;
+ int ret;
+
+ switch (chan->type) {
+ case IIO_ACCEL:
+ break;
+ case IIO_TEMP:
+ return inv_icm42607_temp_read_raw(indio_dev, chan, val, val2, mask);
+ default:
+ return -EINVAL;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = inv_icm42607_accel_read_sensor(indio_dev, chan, &data);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return inv_icm42600_accel_read_scale(indio_dev, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_accel_read_odr(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
static int inv_icm42600_accel_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals,
@@ -964,6 +1327,29 @@ static int inv_icm42600_accel_write_raw(struct iio_dev *indio_dev,
}
}
+static int inv_icm42607_accel_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
+
+ if (chan->type != IIO_ACCEL)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = inv_icm42600_accel_write_scale(indio_dev, val, val2);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_accel_write_odr(indio_dev, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
static int inv_icm42600_accel_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
@@ -1082,7 +1468,15 @@ static int _inv_icm42600_accel_wom_value(struct inv_icm42600_state *st,
guard(mutex)(&st->lock);
- ret = inv_icm42600_accel_read_odr(st, &accel_hz, &accel_uhz);
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ ret = inv_icm42607_accel_read_odr(st, &accel_hz, &accel_uhz);
+ break;
+ default:
+ ret = inv_icm42600_accel_read_odr(st, &accel_hz, &accel_uhz);
+ break;
+ }
if (ret < 0)
return ret;
@@ -1137,6 +1531,20 @@ static const struct iio_info inv_icm42600_accel_info = {
.write_event_value = inv_icm42600_accel_write_event_value,
};
+static const struct iio_info inv_icm42607_accel_info = {
+ .read_raw = inv_icm42607_accel_read_raw,
+ .write_raw = inv_icm42607_accel_write_raw,
+ .write_raw_get_fmt = inv_icm42600_accel_write_raw_get_fmt,
+ .debugfs_reg_access = inv_icm42600_debugfs_reg,
+ .update_scan_mode = inv_icm42607_accel_update_scan_mode,
+ .hwfifo_set_watermark = inv_icm42600_accel_hwfifo_set_watermark,
+ .hwfifo_flush_to_buffer = inv_icm42600_accel_hwfifo_flush,
+ .read_event_config = inv_icm42600_accel_read_event_config,
+ .write_event_config = inv_icm42600_accel_write_event_config,
+ .read_event_value = inv_icm42600_accel_read_event_value,
+ .write_event_value = inv_icm42600_accel_write_event_value,
+};
+
int inv_icm42600_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
{
struct device *dev = regmap_get_device(st->map);
@@ -1202,6 +1610,62 @@ int inv_icm42600_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio
return 0;
}
+int inv_icm42607_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
+{
+ 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;
+ int ret;
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name);
+ if (!name)
+ return -ENOMEM;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st));
+ if (!indio_dev)
+ return -ENOMEM;
+ accel_st = iio_priv(indio_dev);
+
+ accel_st->scales = inv_icm42600_accel_scale;
+ accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale);
+ accel_st->power_mode = INV_ICM42600_SENSOR_MODE_LOW_POWER;
+ accel_st->filter = INV_ICM42607_FILTER_AVG_16X;
+
+ /*
+ * clock period is 32kHz (31250ns)
+ * jitter is +/- 2% (20 per mille)
+ */
+ ts_chip.clock_period = 31250;
+ ts_chip.jitter = 20;
+ ts_chip.init_period = inv_icm42607_odr_to_period(st->conf.accel.odr);
+ inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);
+
+ iio_device_set_drvdata(indio_dev, st);
+ indio_dev->name = name;
+ indio_dev->info = &inv_icm42607_accel_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = inv_icm42607_accel_channels;
+ indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_accel_channels);
+ indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks;
+
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ &inv_icm42607_buffer_ops);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return ret;
+
+ /* accel events are wakeup capable */
+ ret = devm_device_init_wakeup(&indio_dev->dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
index 68a395758031..d9b10bf4c9df 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
@@ -116,6 +116,23 @@ void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st)
st->fifo.period = min(period_gyro, period_accel);
}
+void inv_icm42607_buffer_update_fifo_period(struct inv_icm42600_state *st)
+{
+ u32 period_gyro, period_accel;
+
+ if (st->fifo.en & INV_ICM42600_SENSOR_GYRO)
+ period_gyro = inv_icm42607_odr_to_period(st->conf.gyro.odr);
+ else
+ period_gyro = U32_MAX;
+
+ if (st->fifo.en & INV_ICM42600_SENSOR_ACCEL)
+ period_accel = inv_icm42607_odr_to_period(st->conf.accel.odr);
+ else
+ period_accel = U32_MAX;
+
+ st->fifo.period = min(period_gyro, period_accel);
+}
+
int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st,
unsigned int fifo_en)
{
@@ -146,6 +163,31 @@ int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st,
return 0;
}
+int inv_icm42607_buffer_set_fifo_en(struct inv_icm42600_state *st,
+ unsigned int fifo_en)
+{
+ unsigned int val;
+ int ret;
+
+ /* update FIFO EN bits for accel and gyro */
+ val = 0;
+ if (fifo_en & INV_ICM42600_SENSOR_GYRO)
+ val |= INV_ICM42607_FIFO_CONFIG1_MODE;
+ if (fifo_en & INV_ICM42600_SENSOR_ACCEL)
+ val |= INV_ICM42607_FIFO_CONFIG1_MODE;
+ if (fifo_en & INV_ICM42600_SENSOR_TEMP)
+ val |= INV_ICM42607_FIFO_CONFIG1_MODE;
+
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, val);
+ if (ret)
+ return ret;
+
+ st->fifo.en = fifo_en;
+ inv_icm42607_buffer_update_fifo_period(st);
+
+ return 0;
+}
+
static size_t inv_icm42600_get_packet_size(unsigned int fifo_en)
{
size_t packet_size;
@@ -202,6 +244,7 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
unsigned int wm_gyro, wm_accel, watermark;
u32 period_gyro, period_accel;
u32 latency_gyro, latency_accel, latency;
+ u32 fifo_reg, int_reg;
bool restore;
__le16 raw_wm;
int ret;
@@ -249,8 +292,19 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
/* compute watermark value in bytes */
wm_size = watermark * packet_size;
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ fifo_reg = INV_ICM42607_REG_FIFO_CONFIG2;
+ int_reg = INV_ICM42607_REG_INT_SOURCE0;
+ break;
+ default:
+ fifo_reg = INV_ICM42600_REG_FIFO_WATERMARK;
+ int_reg = INV_ICM42600_REG_INT_SOURCE0;
+ break;
+ }
/* changing FIFO watermark requires to turn off watermark interrupt */
- ret = regmap_update_bits_check(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ ret = regmap_update_bits_check(st->map, int_reg,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN,
0, &restore);
if (ret)
@@ -258,14 +312,14 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
raw_wm = INV_ICM42600_FIFO_WATERMARK_VAL(wm_size);
memcpy(st->buffer, &raw_wm, sizeof(raw_wm));
- ret = regmap_bulk_write(st->map, INV_ICM42600_REG_FIFO_WATERMARK,
+ ret = regmap_bulk_write(st->map, fifo_reg,
st->buffer, sizeof(raw_wm));
if (ret)
return ret;
/* restore watermark interrupt */
if (restore) {
- ret = regmap_set_bits(st->map, INV_ICM42600_REG_INT_SOURCE0,
+ ret = regmap_set_bits(st->map, int_reg,
INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_EN);
if (ret)
return ret;
@@ -333,6 +387,47 @@ static int inv_icm42600_buffer_postenable(struct iio_dev *indio_dev)
return 0;
}
+static int inv_icm42607_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ /* exit if FIFO is already on */
+ if (st->fifo.on) {
+ st->fifo.on++;
+ return 0;
+ }
+
+ /* set FIFO threshold interrupt */
+ ret = regmap_set_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);
+ if (ret)
+ return ret;
+
+ /* flush FIFO data */
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH);
+ if (ret)
+ return ret;
+
+ /* set FIFO in streaming mode */
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_MODE);
+ if (ret)
+ return ret;
+
+ /* workaround: first read of FIFO count after reset is always 0 */
+ ret = regmap_bulk_read(st->map, INV_ICM42607_REG_FIFO_COUNTH, st->buffer, 2);
+ if (ret)
+ return ret;
+
+ st->fifo.on++;
+
+ return 0;
+}
+
static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
@@ -368,6 +463,41 @@ static int inv_icm42600_buffer_predisable(struct iio_dev *indio_dev)
return 0;
}
+static int inv_icm42607_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ if (st->fifo.on > 1) {
+ st->fifo.on--;
+ return 0;
+ }
+
+ /* set FIFO in bypass mode */
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_BYPASS);
+ if (ret)
+ return ret;
+
+ /* flush FIFO data */
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH);
+ if (ret)
+ return ret;
+
+ /* disable FIFO threshold interrupt */
+ ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INT_SOURCE0,
+ INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN);
+ if (ret)
+ return ret;
+
+ st->fifo.on--;
+
+ return 0;
+}
+
static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
@@ -430,6 +560,66 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
return ret;
}
+static int inv_icm42607_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_state *sensor_st = iio_priv(indio_dev);
+ struct inv_sensors_timestamp *ts = &sensor_st->ts;
+ struct device *dev = regmap_get_device(st->map);
+ unsigned int sensor;
+ unsigned int *watermark;
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int sleep_temp = 0;
+ unsigned int sleep_sensor = 0;
+ unsigned int sleep;
+ int ret;
+
+ if (indio_dev == st->indio_gyro) {
+ sensor = INV_ICM42600_SENSOR_GYRO;
+ watermark = &st->fifo.watermark.gyro;
+ } else if (indio_dev == st->indio_accel) {
+ sensor = INV_ICM42600_SENSOR_ACCEL;
+ watermark = &st->fifo.watermark.accel;
+ } else {
+ return -EINVAL;
+ }
+
+ guard(mutex)(&st->lock);
+
+ inv_sensors_timestamp_apply_odr(ts, 0, 0, 0);
+
+ ret = inv_icm42607_buffer_set_fifo_en(st, st->fifo.en & ~sensor);
+ if (ret)
+ goto out_unlock;
+
+ *watermark = 0;
+ ret = inv_icm42600_buffer_update_watermark(st);
+ if (ret)
+ goto out_unlock;
+
+ conf.mode = INV_ICM42600_SENSOR_MODE_OFF;
+ if (sensor == INV_ICM42600_SENSOR_GYRO)
+ ret = inv_icm42607_set_gyro_conf(st, &conf, &sleep_sensor);
+ else if (!st->apex.on)
+ ret = inv_icm42607_set_accel_conf(st, &conf, &sleep_sensor);
+ if (ret)
+ goto out_unlock;
+
+ /* if FIFO is off, turn temperature off */
+ if (!st->fifo.on)
+ ret = inv_icm42607_set_temp_conf(st, false, &sleep_temp);
+
+out_unlock:
+ /* sleep maximum required time */
+ sleep = max(sleep_sensor, sleep_temp);
+ if (sleep)
+ msleep(sleep);
+
+ pm_runtime_put_autosuspend(dev);
+
+ return ret;
+}
+
const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = {
.preenable = inv_icm42600_buffer_preenable,
.postenable = inv_icm42600_buffer_postenable,
@@ -437,6 +627,13 @@ const struct iio_buffer_setup_ops inv_icm42600_buffer_ops = {
.postdisable = inv_icm42600_buffer_postdisable,
};
+const struct iio_buffer_setup_ops inv_icm42607_buffer_ops = {
+ .preenable = inv_icm42600_buffer_preenable,
+ .postenable = inv_icm42607_buffer_postenable,
+ .predisable = inv_icm42607_buffer_predisable,
+ .postdisable = inv_icm42607_buffer_postdisable,
+};
+
int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
unsigned int max)
{
@@ -447,6 +644,7 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
const s8 *temp;
unsigned int odr;
int ret;
+ u32 fifo_cnt_reg, fifo_data_reg;
/* reset all samples counters */
st->fifo.count = 0;
@@ -460,9 +658,21 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
else
max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
+
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ fifo_cnt_reg = INV_ICM42607_REG_FIFO_COUNTH;
+ fifo_data_reg = INV_ICM42607_REG_FIFO_DATA;
+ break;
+ default:
+ fifo_cnt_reg = INV_ICM42600_REG_FIFO_COUNT;
+ fifo_data_reg = INV_ICM42600_REG_FIFO_DATA;
+ break;
+ }
/* read FIFO count value */
raw_fifo_count = (__be16 *)st->buffer;
- ret = regmap_bulk_read(st->map, INV_ICM42600_REG_FIFO_COUNT,
+ ret = regmap_bulk_read(st->map, fifo_cnt_reg,
raw_fifo_count, sizeof(*raw_fifo_count));
if (ret)
return ret;
@@ -475,7 +685,7 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
st->fifo.count = max_count;
/* read all FIFO data in internal buffer */
- ret = regmap_noinc_read(st->map, INV_ICM42600_REG_FIFO_DATA,
+ ret = regmap_noinc_read(st->map, fifo_data_reg,
st->fifo.data, st->fifo.count);
if (ret)
return ret;
@@ -596,3 +806,23 @@ int inv_icm42600_buffer_init(struct inv_icm42600_state *st)
return regmap_update_bits(st->map, INV_ICM42600_REG_FIFO_CONFIG1,
GENMASK(6, 5) | GENMASK(3, 0), val);
}
+
+int inv_icm42607_buffer_init(struct inv_icm42600_state *st)
+{
+ unsigned int val;
+ int ret;
+
+ st->fifo.watermark.eff_gyro = 1;
+ st->fifo.watermark.eff_accel = 1;
+
+ /* Configure FIFO_COUNT format in bytes and big endian */
+ val = INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN;
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ val, val);
+ if (ret)
+ return ret;
+
+ /* Initialize FIFO in bypass mode */
+ return regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_BYPASS);
+}
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
index ffca4da1e249..900ee12fdb9d 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.h
@@ -79,13 +79,18 @@ ssize_t inv_icm42600_fifo_decode_packet(const void *packet, const void **accel,
const void **timestamp, unsigned int *odr);
extern const struct iio_buffer_setup_ops inv_icm42600_buffer_ops;
+extern const struct iio_buffer_setup_ops inv_icm42607_buffer_ops;
int inv_icm42600_buffer_init(struct inv_icm42600_state *st);
+int inv_icm42607_buffer_init(struct inv_icm42600_state *st);
void inv_icm42600_buffer_update_fifo_period(struct inv_icm42600_state *st);
+void inv_icm42607_buffer_update_fifo_period(struct inv_icm42600_state *st);
int inv_icm42600_buffer_set_fifo_en(struct inv_icm42600_state *st,
unsigned int fifo_en);
+int inv_icm42607_buffer_set_fifo_en(struct inv_icm42600_state *st,
+ unsigned int fifo_en);
int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
index 29c8c1871e06..949dbf9c2cd3 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
@@ -102,6 +102,26 @@ const struct regmap_config inv_icm42600_spi_regmap_config = {
};
EXPORT_SYMBOL_NS_GPL(inv_icm42600_spi_regmap_config, "IIO_ICM42600");
+static const struct regmap_range_cfg inv_icm42607_regmap_ranges[] = {
+ {
+ .name = "user bank",
+ .range_min = 0x0000,
+ .range_max = 0x00FF,
+ .window_start = 0,
+ .window_len = 0x0100,
+ },
+};
+
+const struct regmap_config inv_icm42607_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x00FF,
+ .ranges = inv_icm42607_regmap_ranges,
+ .num_ranges = ARRAY_SIZE(inv_icm42607_regmap_ranges),
+ .cache_type = REGCACHE_NONE,
+};
+EXPORT_SYMBOL_NS_GPL(inv_icm42607_regmap_config, "IIO_ICM42600");
+
struct inv_icm42600_hw {
u8 whoami;
const char *name;
@@ -125,6 +145,22 @@ static const struct inv_icm42600_conf inv_icm42600_default_conf = {
.temp_en = false,
};
+static const struct inv_icm42600_conf inv_icm42607_default_conf = {
+ .gyro = {
+ .mode = INV_ICM42600_SENSOR_MODE_OFF,
+ .fs = INV_ICM42600_GYRO_FS_1000DPS,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+ .accel = {
+ .mode = INV_ICM42600_SENSOR_MODE_OFF,
+ .fs = INV_ICM42600_ACCEL_FS_4G,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+ .temp_en = false,
+};
+
static const struct inv_icm42600_conf inv_icm42686_default_conf = {
.gyro = {
.mode = INV_ICM42600_SENSOR_MODE_OFF,
@@ -157,6 +193,16 @@ static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
.name = "icm42605",
.conf = &inv_icm42600_default_conf,
},
+ [INV_CHIP_ICM42607] = {
+ .whoami = INV_ICM42607_WHOAMI,
+ .name = "icm42607",
+ .conf = &inv_icm42607_default_conf,
+ },
+ [INV_CHIP_ICM42607P] = {
+ .whoami = INV_ICM42607P_WHOAMI,
+ .name = "icm42607p",
+ .conf = &inv_icm42607_default_conf,
+ },
[INV_CHIP_ICM42686] = {
.whoami = INV_ICM42600_WHOAMI_ICM42686,
.name = "icm42686",
@@ -224,6 +270,26 @@ u32 inv_icm42600_odr_to_period(enum inv_icm42600_odr odr)
return odr_periods[odr];
}
+u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr)
+{
+ static u32 odr_periods[INV_ICM42607_ODR_NB] = {
+ 0, 0, 0, 0, 0, /* Reserved values */
+ 625000, /* 1600Hz */
+ 1250000, /* 800Hz */
+ 2500000, /* 400Hz */
+ 5000000, /* 200Hz */
+ 10000000, /* 100 Hz */
+ 20000000, /* 50Hz */
+ 40000000, /* 25Hz */
+ 80000000, /* 12.5Hz */
+ 160000000, /* 6.25Hz */
+ 320000000, /* 3.125Hz */
+ 640000000, /* 1.5625Hz */
+ };
+
+ return odr_periods[odr];
+}
+
static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st,
enum inv_icm42600_sensor_mode gyro,
enum inv_icm42600_sensor_mode accel,
@@ -289,6 +355,62 @@ static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st,
return 0;
}
+static int inv_icm42607_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)
+{
+ enum inv_icm42600_sensor_mode oldgyro = st->conf.gyro.mode;
+ enum inv_icm42600_sensor_mode oldaccel = st->conf.accel.mode;
+ bool oldtemp = st->conf.temp_en;
+ unsigned int sleepval;
+ unsigned int val;
+ int ret;
+
+ if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
+ return 0;
+
+ val = INV_ICM42607_PWR_MGMT0_GYRO(gyro) |
+ INV_ICM42607_PWR_MGMT0_ACCEL(accel);
+ if (!temp)
+ val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+ ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ st->conf.gyro.mode = gyro;
+ st->conf.accel.mode = accel;
+ st->conf.temp_en = temp;
+
+ sleepval = 0;
+ if (temp && !oldtemp) {
+ if (sleepval < INV_ICM42600_TEMP_STARTUP_TIME_MS)
+ sleepval = INV_ICM42600_TEMP_STARTUP_TIME_MS;
+ }
+ if (accel != oldaccel && oldaccel == INV_ICM42600_SENSOR_MODE_OFF) {
+ usleep_range(200, 300);
+ if (sleepval < INV_ICM42600_ACCEL_STARTUP_TIME_MS)
+ sleepval = INV_ICM42600_ACCEL_STARTUP_TIME_MS;
+ }
+ if (gyro != oldgyro) {
+ if (oldgyro == INV_ICM42600_SENSOR_MODE_OFF) {
+ usleep_range(200, 300);
+ if (sleepval < INV_ICM42600_GYRO_STARTUP_TIME_MS)
+ sleepval = INV_ICM42600_GYRO_STARTUP_TIME_MS;
+ } else if (gyro == INV_ICM42600_SENSOR_MODE_OFF) {
+ if (sleepval < INV_ICM42600_GYRO_STOP_TIME_MS)
+ sleepval = INV_ICM42600_GYRO_STOP_TIME_MS;
+ }
+ }
+
+ if (sleep_ms)
+ *sleep_ms = sleepval;
+ else if (sleepval)
+ msleep(sleepval);
+
+ return 0;
+}
+
int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
struct inv_icm42600_sensor_conf *conf,
unsigned int *sleep_ms)
@@ -350,6 +472,52 @@ int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
st->conf.temp_en, sleep_ms);
}
+int inv_icm42607_set_accel_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms)
+{
+ struct inv_icm42600_sensor_conf *oldconf = &st->conf.accel;
+ unsigned int val;
+ int ret;
+
+ if (conf->mode < 0)
+ conf->mode = oldconf->mode;
+ if (conf->fs < 0)
+ conf->fs = oldconf->fs;
+ if (conf->odr < 0)
+ conf->odr = oldconf->odr;
+ if (conf->filter < 0)
+ conf->filter = oldconf->filter;
+
+ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+ val = INV_ICM42607_ACCEL_CONFIG0_FS_SEL(conf->fs) |
+ INV_ICM42607_ACCEL_CONFIG0_ODR(conf->odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+ oldconf->fs = conf->fs;
+ oldconf->odr = conf->odr;
+ }
+
+ if (conf->filter != oldconf->filter) {
+ if (conf->mode == INV_ICM42600_SENSOR_MODE_LOW_POWER) {
+ val = INV_ICM42607_ACCEL_CONFIG1_AVG(conf->filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+ INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, val);
+ } else {
+ val = INV_ICM42607_ACCEL_CONFIG1_FILTER(conf->filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_ACCEL_CONFIG1,
+ INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, val);
+ }
+ if (ret)
+ return ret;
+ oldconf->filter = conf->filter;
+ }
+
+ return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
+ st->conf.temp_en, sleep_ms);
+}
+
int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
struct inv_icm42600_sensor_conf *conf,
unsigned int *sleep_ms)
@@ -396,6 +564,46 @@ int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
return 0;
}
+int inv_icm42607_set_gyro_conf(struct inv_icm42600_state *st,
+ struct inv_icm42600_sensor_conf *conf,
+ unsigned int *sleep_ms)
+{
+ struct inv_icm42600_sensor_conf *oldconf = &st->conf.gyro;
+ unsigned int val;
+ int ret;
+
+ if (conf->mode < 0)
+ conf->mode = oldconf->mode;
+ if (conf->fs < 0)
+ conf->fs = oldconf->fs;
+ if (conf->odr < 0)
+ conf->odr = oldconf->odr;
+ if (conf->filter < 0)
+ conf->filter = oldconf->filter;
+
+ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
+ val = INV_ICM42607_GYRO_CONFIG0_FS_SEL(conf->fs) |
+ INV_ICM42607_GYRO_CONFIG0_ODR(conf->odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+ if (ret)
+ return ret;
+ oldconf->fs = conf->fs;
+ oldconf->odr = conf->odr;
+ }
+
+ if (conf->filter != oldconf->filter) {
+ val = INV_ICM42607_GYRO_CONFIG1_FILTER(conf->filter);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_GYRO_CONFIG1,
+ INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, val);
+ if (ret)
+ return ret;
+ oldconf->filter = conf->filter;
+ }
+
+ return inv_icm42607_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
+ st->conf.temp_en, sleep_ms);
+}
+
int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
unsigned int *sleep_ms)
{
@@ -404,6 +612,23 @@ int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
sleep_ms);
}
+int inv_icm42607_set_temp_conf(struct inv_icm42600_state *st, bool enable,
+ unsigned int *sleep_ms)
+{
+ unsigned int val;
+ int ret;
+
+ val = INV_ICM42607_TEMP_CONFIG0_FILTER(INV_ICM42607_FILTER_BW_34HZ);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_TEMP_CONFIG0,
+ INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, val);
+ if (ret)
+ return ret;
+
+ return inv_icm42607_set_pwr_mgmt0(st, st->conf.gyro.mode,
+ st->conf.accel.mode, enable,
+ sleep_ms);
+}
+
int inv_icm42600_enable_wom(struct inv_icm42600_state *st)
{
int ret;
@@ -420,6 +645,23 @@ int inv_icm42600_enable_wom(struct inv_icm42600_state *st)
INV_ICM42600_INT_SOURCE1_WOM_INT1_EN);
}
+int inv_icm42607_enable_wom(struct inv_icm42600_state *st)
+{
+ int ret;
+
+ /* enable WoM hardware */
+ ret = regmap_write(st->map, INV_ICM42607_REG_WOM_CONFIG,
+ INV_ICM42607_WOM_CONFIG_INT_DUR(1) |
+ INV_ICM42607_WOM_CONFIG_MODE |
+ INV_ICM42607_WOM_CONFIG_EN);
+ if (ret)
+ return ret;
+
+ /* enable WoM interrupt */
+ return regmap_set_bits(st->map, INV_ICM42607_REG_INT_SOURCE1,
+ INV_ICM42607_INT_SOURCE1_WOM_INT1_EN);
+}
+
int inv_icm42600_disable_wom(struct inv_icm42600_state *st)
{
int ret;
@@ -435,6 +677,21 @@ int inv_icm42600_disable_wom(struct inv_icm42600_state *st)
INV_ICM42600_SMD_CONFIG_SMD_MODE_OFF);
}
+int inv_icm42607_disable_wom(struct inv_icm42600_state *st)
+{
+ int ret;
+
+ /* disable WoM interrupt */
+ ret = regmap_clear_bits(st->map, INV_ICM42607_REG_INT_SOURCE1,
+ INV_ICM42607_INT_SOURCE1_WOM_INT1_EN);
+ if (ret)
+ return ret;
+
+ /* disable WoM hardware */
+ return regmap_clear_bits(st->map, INV_ICM42607_REG_WOM_CONFIG,
+ INV_ICM42607_WOM_CONFIG_EN);
+}
+
int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
unsigned int writeval, unsigned int *readval)
{
@@ -490,6 +747,53 @@ static int inv_icm42600_set_conf(struct inv_icm42600_state *st,
return 0;
}
+static int inv_icm42607_set_conf(struct inv_icm42600_state *st,
+ const struct inv_icm42600_conf *conf)
+{
+ unsigned int val;
+ int ret;
+
+ val = INV_ICM42607_PWR_MGMT0_GYRO(conf->gyro.mode) |
+ INV_ICM42607_PWR_MGMT0_ACCEL(conf->accel.mode);
+ /*
+ * No temperature enable reg in datasheet, but BSP driver
+ * selected RC oscillator clock in LP mode when temperature
+ * was disabled.
+ */
+ if (!conf->temp_en)
+ val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+ ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_GYRO_CONFIG0_FS_SEL(conf->gyro.fs) |
+ INV_ICM42607_GYRO_CONFIG0_ODR(conf->gyro.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_ACCEL_CONFIG0_FS_SEL(conf->accel.fs) |
+ INV_ICM42607_ACCEL_CONFIG0_ODR(conf->accel.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_GYRO_CONFIG1_FILTER(conf->gyro.filter);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG1, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_ACCEL_CONFIG1_FILTER(conf->accel.filter);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG1, val);
+ if (ret)
+ return ret;
+
+ /* update internal conf */
+ st->conf = *conf;
+
+ return 0;
+}
+
/**
* inv_icm42600_setup() - check and setup chip
* @st: driver internal state
@@ -555,6 +859,64 @@ static int inv_icm42600_setup(struct inv_icm42600_state *st,
return inv_icm42600_set_conf(st, hw->conf);
}
+/**
+ * inv_icm42607_setup() - check and setup chip
+ * @st: driver internal state
+ * @bus_setup: callback for setting up bus specific registers
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int inv_icm42607_setup(struct inv_icm42600_state *st,
+ inv_icm42600_bus_setup bus_setup)
+{
+ const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip];
+ const struct device *dev = regmap_get_device(st->map);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+ if (ret)
+ return ret;
+
+ if (val != hw->whoami)
+ return dev_err_probe(dev, -ENODEV,
+ "invalid whoami %#02x expected %#02x (%s)\n",
+ val, hw->whoami, hw->name);
+
+ st->name = hw->name;
+
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+ if (ret)
+ return ret;
+ msleep(INV_ICM42600_RESET_TIME_MS);
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_INT_STATUS, &val);
+ if (ret)
+ return ret;
+ if (!(val & INV_ICM42607_INT_STATUS_RESET_DONE))
+ return dev_err_probe(dev, -ENODEV,
+ "reset error, reset done bit not set\n");
+
+ ret = bus_setup(st);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN,
+ INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+ if (ret)
+ return ret;
+
+ return inv_icm42607_set_conf(st, hw->conf);
+}
+
static irqreturn_t inv_icm42600_irq_timestamp(int irq, void *_data)
{
struct inv_icm42600_state *st = _data;
@@ -571,6 +933,19 @@ static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
struct device *dev = regmap_get_device(st->map);
unsigned int status;
int ret;
+ u32 int_sts_reg, int_sts2_reg;
+
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ int_sts_reg = INV_ICM42607_REG_INT_STATUS;
+ int_sts2_reg = INV_ICM42607_REG_INT_STATUS2;
+ break;
+ default:
+ int_sts_reg = INV_ICM42600_REG_INT_STATUS;
+ int_sts2_reg = INV_ICM42600_REG_INT_STATUS2;
+ break;
+ }
mutex_lock(&st->lock);
@@ -578,7 +953,7 @@ static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
unsigned int status2, status3;
/* read INT_STATUS2 and INT_STATUS3 in 1 operation */
- ret = regmap_bulk_read(st->map, INV_ICM42600_REG_INT_STATUS2, st->buffer, 2);
+ ret = regmap_bulk_read(st->map, int_sts2_reg, st->buffer, 2);
if (ret)
goto out_unlock;
status2 = st->buffer[0];
@@ -587,7 +962,7 @@ static irqreturn_t inv_icm42600_irq_handler(int irq, void *_data)
st->timestamp.accel);
}
- ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &status);
+ ret = regmap_read(st->map, int_sts_reg, &status);
if (ret)
goto out_unlock;
@@ -651,13 +1026,19 @@ static int inv_icm42600_irq_init(struct inv_icm42600_state *st, int irq,
if (!open_drain)
val |= INV_ICM42600_INT_CONFIG_INT1_PUSH_PULL;
- ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val);
- if (ret)
- return ret;
-
- /* Deassert async reset for proper INT pin operation (cf datasheet) */
- ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
- INV_ICM42600_INT_CONFIG1_ASYNC_RESET);
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ ret = regmap_write(st->map, INV_ICM42607_REG_INT_CONFIG, val);
+ break;
+ default:
+ ret = regmap_write(st->map, INV_ICM42600_REG_INT_CONFIG, val);
+ if (ret)
+ return ret;
+ /* Deassert async reset for proper INT pin operation (cf datasheet) */
+ ret = regmap_clear_bits(st->map, INV_ICM42600_REG_INT_CONFIG1,
+ INV_ICM42600_INT_CONFIG1_ASYNC_RESET);
+ }
if (ret)
return ret;
@@ -761,6 +1142,59 @@ static int inv_icm42600_hw_suspend(struct device *dev)
return 0;
}
+static int inv_icm42607_hw_suspend(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+ struct device *accel_dev;
+ bool wakeup;
+ int accel_conf;
+ int ret = 0;
+
+ guard(mutex)(&st->lock);
+
+ st->suspended.gyro = st->conf.gyro.mode;
+ st->suspended.accel = st->conf.accel.mode;
+ st->suspended.temp = st->conf.temp_en;
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ if (st->fifo.on) {
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_BYPASS);
+ if (ret)
+ return ret;
+ }
+
+ /* keep chip on and wake-up capable if APEX and wakeup on */
+ accel_dev = &st->indio_accel->dev;
+ wakeup = st->apex.on && device_may_wakeup(accel_dev);
+ if (wakeup) {
+ /* keep accel on and setup irq for wakeup */
+ accel_conf = st->conf.accel.mode;
+ enable_irq_wake(st->irq);
+ disable_irq(st->irq);
+ } else {
+ /* disable APEX features and accel if wakeup disabled */
+ if (st->apex.wom.enable) {
+ ret = inv_icm42607_disable_wom(st);
+ if (ret)
+ return ret;
+ }
+ accel_conf = INV_ICM42600_SENSOR_MODE_OFF;
+ }
+
+ ret = inv_icm42607_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
+ INV_ICM42600_SENSOR_MODE_OFF, false,
+ NULL);
+ if (ret)
+ return ret;
+
+ if (!wakeup)
+ regulator_disable(st->vddio_supply);
+
+ return 0;
+}
+
/*
* System resume gets the system back on and restores the sensors state.
* Manually put runtime power management in system active state.
@@ -817,6 +1251,59 @@ static int inv_icm42600_hw_resume(struct device *dev)
return 0;
}
+static int inv_icm42607_hw_resume(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+ 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 device *accel_dev;
+ bool wakeup;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ /* check wakeup capability */
+ accel_dev = &st->indio_accel->dev;
+ wakeup = st->apex.on && device_may_wakeup(accel_dev);
+ /* restore irq state or vddio if cut off */
+ if (wakeup) {
+ enable_irq(st->irq);
+ disable_irq_wake(st->irq);
+ } else {
+ ret = inv_icm42600_enable_regulator_vddio(st);
+ if (ret)
+ return ret;
+ }
+
+ /* restore sensors state */
+ ret = inv_icm42607_set_pwr_mgmt0(st, st->suspended.gyro,
+ st->suspended.accel,
+ st->suspended.temp, NULL);
+ if (ret)
+ return ret;
+
+ /* restore APEX features if disabled */
+ if (!wakeup && st->apex.wom.enable) {
+ ret = inv_icm42607_enable_wom(st);
+ if (ret)
+ return ret;
+ }
+
+ if (st->fifo.on) {
+ inv_sensors_timestamp_reset(&gyro_st->ts);
+ inv_sensors_timestamp_reset(&accel_st->ts);
+ ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
+ INV_ICM42607_FIFO_CONFIG1_MODE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
/* Runtime suspend will turn off sensors that are enabled by iio devices. */
static int inv_icm42600_hw_runtime_suspend(struct device *dev)
{
@@ -837,6 +1324,24 @@ static int inv_icm42600_hw_runtime_suspend(struct device *dev)
return 0;
}
+static int inv_icm42607_hw_runtime_suspend(struct device *dev)
+{
+ struct inv_icm42600_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ ret = inv_icm42607_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
+ INV_ICM42600_SENSOR_MODE_OFF, false,
+ NULL);
+ if (ret)
+ return ret;
+
+ regulator_disable(st->vddio_supply);
+
+ return 0;
+}
+
/* Sensors are enabled by iio devices, no need to turn them back on here. */
static int inv_icm42600_hw_runtime_resume(struct device *dev)
{
@@ -859,6 +1364,17 @@ static struct inv_icm42600_funcs inv_icm42600_hw_funcs = {
.runtime_resume = &inv_icm42600_hw_runtime_resume,
};
+static struct inv_icm42600_funcs inv_icm42607_hw_funcs = {
+ .setup = &inv_icm42607_setup,
+ .buffer_init = &inv_icm42607_buffer_init,
+ .gyro_init = &inv_icm42607_gyro_init,
+ .accel_init = &inv_icm42607_accel_init,
+ .suspend = &inv_icm42607_hw_suspend,
+ .resume = &inv_icm42607_hw_resume,
+ .runtime_suspend = &inv_icm42607_hw_runtime_suspend,
+ .runtime_resume = &inv_icm42600_hw_runtime_resume,
+};
+
int inv_icm42600_core_probe(struct regmap *regmap, int chip,
inv_icm42600_bus_setup bus_setup)
{
@@ -925,7 +1441,15 @@ int inv_icm42600_core_probe(struct regmap *regmap, int chip,
return ret;
/* setup chip registers based on hardware */
- st->hw_funcs = &inv_icm42600_hw_funcs;
+ switch (chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ st->hw_funcs = &inv_icm42607_hw_funcs;
+ break;
+ default:
+ st->hw_funcs = &inv_icm42600_hw_funcs;
+ break;
+ }
ret = st->hw_funcs->setup(st, bus_setup);
if (ret)
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
index 32aa2e52df2e..eb590eb4f397 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
@@ -47,6 +47,31 @@
.ext_info = _ext_info, \
}
+#define INV_ICM42607_GYRO_CHAN(_modifier, _index, _ext_info) \
+ { \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = _modifier, \
+ .info_mask_separate = \
+ BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type_available = \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_BE, \
+ }, \
+ .ext_info = _ext_info, \
+ }
+
enum inv_icm42600_gyro_scan {
INV_ICM42600_GYRO_SCAN_X,
INV_ICM42600_GYRO_SCAN_Y,
@@ -71,6 +96,17 @@ static const struct iio_chan_spec inv_icm42600_gyro_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_GYRO_SCAN_TIMESTAMP),
};
+static const struct iio_chan_spec inv_icm42607_gyro_channels[] = {
+ INV_ICM42607_GYRO_CHAN(IIO_MOD_X, INV_ICM42600_GYRO_SCAN_X,
+ inv_icm42600_gyro_ext_infos),
+ INV_ICM42607_GYRO_CHAN(IIO_MOD_Y, INV_ICM42600_GYRO_SCAN_Y,
+ inv_icm42600_gyro_ext_infos),
+ INV_ICM42607_GYRO_CHAN(IIO_MOD_Z, INV_ICM42600_GYRO_SCAN_Z,
+ inv_icm42600_gyro_ext_infos),
+ INV_ICM42600_TEMP_CHAN(INV_ICM42600_GYRO_SCAN_TEMP),
+ IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_GYRO_SCAN_TIMESTAMP),
+};
+
/*
* IIO buffer data: size must be a power of 2 and timestamp aligned
* 16 bytes: 6 bytes angular velocity, 2 bytes temperature, 8 bytes timestamp
@@ -137,6 +173,47 @@ static int inv_icm42600_gyro_update_scan_mode(struct iio_dev *indio_dev,
return ret;
}
+static int inv_icm42607_gyro_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int fifo_en = 0;
+ unsigned int sleep_gyro = 0;
+ unsigned int sleep_temp = 0;
+ unsigned int sleep;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_TEMP) {
+ /* enable temp sensor */
+ ret = inv_icm42607_set_temp_conf(st, true, &sleep_temp);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_TEMP;
+ }
+
+ if (*scan_mask & INV_ICM42600_SCAN_MASK_GYRO_3AXIS) {
+ /* enable gyro sensor */
+ conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
+ ret = inv_icm42607_set_gyro_conf(st, &conf, &sleep_gyro);
+ if (ret)
+ goto out_unlock;
+ fifo_en |= INV_ICM42600_SENSOR_GYRO;
+ }
+
+ /* update data FIFO write */
+ ret = inv_icm42607_buffer_set_fifo_en(st, fifo_en | st->fifo.en);
+
+out_unlock:
+ /* sleep maximum required time */
+ sleep = max(sleep_gyro, sleep_temp);
+ if (sleep)
+ msleep(sleep);
+ return ret;
+}
+
static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st,
struct iio_chan_spec const *chan,
s16 *val)
@@ -188,6 +265,58 @@ static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st,
return ret;
}
+static int inv_icm42607_gyro_read_sensor(struct inv_icm42600_state *st,
+ struct iio_chan_spec const *chan,
+ s16 *val)
+{
+ struct device *dev = regmap_get_device(st->map);
+ struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
+ unsigned int reg;
+ __be16 *data;
+ int ret;
+
+ if (chan->type != IIO_ANGL_VEL)
+ return -EINVAL;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ reg = INV_ICM42607_REG_GYRO_DATA_X1;
+ break;
+ case IIO_MOD_Y:
+ reg = INV_ICM42607_REG_GYRO_DATA_Y1;
+ break;
+ case IIO_MOD_Z:
+ reg = INV_ICM42607_REG_GYRO_DATA_Z1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return -ENXIO;
+
+ guard(mutex)(&st->lock);
+
+ /* enable gyro sensor */
+ conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
+ ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+ if (ret)
+ return ret;
+
+ /* read gyro register data */
+ data = (__be16 *)&st->buffer[0];
+ ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
+ if (ret)
+ return ret;
+
+ *val = (s16)be16_to_cpup(data);
+ if (*val == INV_ICM42607_DATA_INVALID)
+ ret = -EINVAL;
+
+ return ret;
+}
+
/* IIO format int + nano */
static const int inv_icm42600_gyro_scale[] = {
/* +/- 2000dps => 0.001065264 rad/s */
@@ -241,6 +370,20 @@ static const int inv_icm42686_gyro_scale[] = {
[2 * INV_ICM42686_GYRO_FS_31_25DPS] = 0,
[2 * INV_ICM42686_GYRO_FS_31_25DPS + 1] = 16645,
};
+static const int inv_icm42607_gyro_scale[] = {
+ /* +/- 2000dps => 0.001065264 rad/s */
+ [2 * INV_ICM42607_GYRO_FS_2000DPS] = 0,
+ [2 * INV_ICM42607_GYRO_FS_2000DPS + 1] = 1065264,
+ /* +/- 1000dps => 0.000532632 rad/s */
+ [2 * INV_ICM42607_GYRO_FS_1000DPS] = 0,
+ [2 * INV_ICM42607_GYRO_FS_1000DPS + 1] = 532632,
+ /* +/- 500dps => 0.000266316 rad/s */
+ [2 * INV_ICM42607_GYRO_FS_500DPS] = 0,
+ [2 * INV_ICM42607_GYRO_FS_500DPS + 1] = 266316,
+ /* +/- 250dps => 0.000133158 rad/s */
+ [2 * INV_ICM42607_GYRO_FS_250DPS] = 0,
+ [2 * INV_ICM42607_GYRO_FS_250DPS + 1] = 133158,
+};
static int inv_icm42600_gyro_read_scale(struct iio_dev *indio_dev,
int *val, int *val2)
@@ -276,12 +419,21 @@ static int inv_icm42600_gyro_write_scale(struct iio_dev *indio_dev,
conf.fs = idx / 2;
- pm_runtime_get_sync(dev);
-
- scoped_guard(mutex, &st->lock)
- ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return -ENXIO;
- pm_runtime_put_autosuspend(dev);
+ switch (st->chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ scoped_guard(mutex, &st->lock)
+ ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+ break;
+ default:
+ scoped_guard(mutex, &st->lock)
+ ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
+ break;
+ }
return ret;
}
@@ -306,6 +458,17 @@ static const int inv_icm42600_gyro_odr[] = {
4000, 0,
};
+static const int inv_icm42607_gyro_odr[] = {
+ 12, 500000, /* 12.5Hz */
+ 25, 0, /* 25Hz */
+ 50, 0, /* 50Hz */
+ 100, 0, /* 100Hz */
+ 200, 0, /* 200Hz */
+ 400, 0, /* 400Hz */
+ 800, 0, /* 800Hz */
+ 1600, 0, /* 1600Hz */
+};
+
static const int inv_icm42600_gyro_odr_conv[] = {
INV_ICM42600_ODR_12_5HZ,
INV_ICM42600_ODR_25HZ,
@@ -317,6 +480,17 @@ static const int inv_icm42600_gyro_odr_conv[] = {
INV_ICM42600_ODR_4KHZ_LN,
};
+static const int inv_icm42607_gyro_odr_conv[] = {
+ INV_ICM42607_ODR_12_5HZ,
+ INV_ICM42607_ODR_25HZ,
+ INV_ICM42607_ODR_50HZ,
+ INV_ICM42607_ODR_100HZ,
+ INV_ICM42607_ODR_200HZ,
+ INV_ICM42607_ODR_400HZ,
+ INV_ICM42607_ODR_800HZ,
+ INV_ICM42607_ODR_1600HZ,
+};
+
static int inv_icm42600_gyro_read_odr(struct inv_icm42600_state *st,
int *val, int *val2)
{
@@ -338,6 +512,27 @@ static int inv_icm42600_gyro_read_odr(struct inv_icm42600_state *st,
return IIO_VAL_INT_PLUS_MICRO;
}
+static int inv_icm42607_gyro_read_odr(struct inv_icm42600_state *st,
+ int *val, int *val2)
+{
+ unsigned int odr;
+ unsigned int i;
+
+ odr = st->conf.gyro.odr;
+
+ for (i = 0; i < ARRAY_SIZE(inv_icm42607_gyro_odr_conv); ++i) {
+ if (inv_icm42607_gyro_odr_conv[i] == odr)
+ break;
+ }
+ if (i >= ARRAY_SIZE(inv_icm42607_gyro_odr_conv))
+ return -EINVAL;
+
+ *val = inv_icm42607_gyro_odr[2 * i];
+ *val2 = inv_icm42607_gyro_odr[2 * i + 1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev,
int val, int val2)
{
@@ -382,6 +577,48 @@ static int inv_icm42600_gyro_write_odr(struct iio_dev *indio_dev,
return ret;
}
+static int inv_icm42607_gyro_write_odr(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 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;
+ int ret;
+
+ for (idx = 0; idx < ARRAY_SIZE(inv_icm42607_gyro_odr); idx += 2) {
+ if (val == inv_icm42607_gyro_odr[idx] &&
+ val2 == inv_icm42607_gyro_odr[idx + 1])
+ break;
+ }
+ if (idx >= ARRAY_SIZE(inv_icm42607_gyro_odr))
+ return -EINVAL;
+
+ conf.odr = inv_icm42607_gyro_odr_conv[idx / 2];
+ if (conf.odr == st->conf.gyro.odr)
+ return 0;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return -ENXIO;
+ guard(mutex)(&st->lock);
+
+ ret = inv_sensors_timestamp_update_odr(ts, inv_icm42607_odr_to_period(conf.odr),
+ iio_buffer_enabled(indio_dev));
+ if (ret)
+ return ret;
+
+ ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
+ if (ret)
+ return ret;
+ inv_icm42607_buffer_update_fifo_period(st);
+ inv_icm42600_buffer_update_watermark(st);
+
+ return 0;
+}
+
/*
* Calibration bias values, IIO range format int + nano.
* Value is limited to +/-64dps coded on 12 bits signed. Step is 1/32 dps.
@@ -606,6 +843,42 @@ static int inv_icm42600_gyro_read_raw(struct iio_dev *indio_dev,
}
}
+static int inv_icm42607_gyro_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ s16 data;
+ int ret;
+
+ switch (chan->type) {
+ case IIO_ANGL_VEL:
+ break;
+ case IIO_TEMP:
+ return inv_icm42607_temp_read_raw(indio_dev, chan, val, val2, mask);
+ default:
+ return -EINVAL;
+ }
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = inv_icm42607_gyro_read_sensor(st, chan, &data);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+ *val = data;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ return inv_icm42600_gyro_read_scale(indio_dev, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_gyro_read_odr(st, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
static int inv_icm42600_gyro_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals,
@@ -666,6 +939,29 @@ static int inv_icm42600_gyro_write_raw(struct iio_dev *indio_dev,
}
}
+static int inv_icm42607_gyro_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
+
+ if (chan->type != IIO_ANGL_VEL)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = inv_icm42600_gyro_write_scale(indio_dev, val, val2);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return inv_icm42607_gyro_write_odr(indio_dev, val, val2);
+ default:
+ return -EINVAL;
+ }
+}
+
static int inv_icm42600_gyro_write_raw_get_fmt(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
long mask)
@@ -725,6 +1021,16 @@ static const struct iio_info inv_icm42600_gyro_info = {
.hwfifo_flush_to_buffer = inv_icm42600_gyro_hwfifo_flush,
};
+static const struct iio_info inv_icm42607_gyro_info = {
+ .read_raw = inv_icm42607_gyro_read_raw,
+ .write_raw = inv_icm42607_gyro_write_raw,
+ .write_raw_get_fmt = inv_icm42600_gyro_write_raw_get_fmt,
+ .debugfs_reg_access = inv_icm42600_debugfs_reg,
+ .update_scan_mode = inv_icm42607_gyro_update_scan_mode,
+ .hwfifo_set_watermark = inv_icm42600_gyro_hwfifo_set_watermark,
+ .hwfifo_flush_to_buffer = inv_icm42600_gyro_hwfifo_flush,
+};
+
int inv_icm42600_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
{
struct device *dev = regmap_get_device(st->map);
@@ -783,6 +1089,56 @@ int inv_icm42600_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_
return 0;
}
+int inv_icm42607_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
+{
+ 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;
+ int ret;
+
+ name = devm_kasprintf(dev, GFP_KERNEL, "%s-gyro", st->name);
+ if (!name)
+ return -ENOMEM;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*gyro_st));
+ if (!indio_dev)
+ return -ENOMEM;
+ gyro_st = iio_priv(indio_dev);
+
+ gyro_st->scales = inv_icm42607_gyro_scale;
+ gyro_st->scales_len = ARRAY_SIZE(inv_icm42607_gyro_scale);
+
+ /*
+ * clock period is 32kHz (31250ns)
+ * jitter is +/- 2% (20 per mille)
+ */
+ ts_chip.clock_period = 31250;
+ ts_chip.jitter = 20;
+ ts_chip.init_period = inv_icm42607_odr_to_period(st->conf.accel.odr);
+ inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);
+
+ iio_device_set_drvdata(indio_dev, st);
+ indio_dev->name = name;
+ indio_dev->info = &inv_icm42607_gyro_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = inv_icm42607_gyro_channels;
+ indio_dev->num_channels = ARRAY_SIZE(inv_icm42607_gyro_channels);
+ indio_dev->available_scan_masks = inv_icm42600_gyro_scan_masks;
+ indio_dev->setup_ops = &inv_icm42607_buffer_ops;
+
+ ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
+ &inv_icm42607_buffer_ops);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
int inv_icm42600_gyro_parse_fifo(struct iio_dev *indio_dev)
{
struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
index 7e4d3ea68721..cd2071969b9a 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c
@@ -49,6 +49,29 @@ static int inv_icm42600_i2c_bus_setup(struct inv_icm42600_state *st)
INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
}
+static int inv_icm42607_i2c_bus_setup(struct inv_icm42600_state *st)
+{
+ unsigned int mask, val;
+ int ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+ INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN, 0);
+ if (ret)
+ return ret;
+
+ mask = INV_ICM42607_DRIVE_CONFIG2_I2C_MASK;
+ val = INV_ICM42607_DRIVE_CONFIG2_I2C(INV_ICM42600_SLEW_RATE_12_36NS);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG2,
+ mask, val);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS);
+}
+
static int inv_icm42600_probe(struct i2c_client *client)
{
const void *match;
@@ -63,11 +86,23 @@ static int inv_icm42600_probe(struct i2c_client *client)
return -EINVAL;
chip = (uintptr_t)match;
- regmap = devm_regmap_init_i2c(client, &inv_icm42600_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- return inv_icm42600_core_probe(regmap, chip, inv_icm42600_i2c_bus_setup);
+ switch (chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ regmap = devm_regmap_init_i2c(client,
+ &inv_icm42607_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+ return inv_icm42600_core_probe(regmap, chip,
+ inv_icm42607_i2c_bus_setup);
+ default:
+ regmap = devm_regmap_init_i2c(client,
+ &inv_icm42600_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+ return inv_icm42600_core_probe(regmap, chip,
+ inv_icm42600_i2c_bus_setup);
+ }
}
/*
@@ -78,6 +113,8 @@ static const struct i2c_device_id inv_icm42600_id[] = {
{ "icm42600", INV_CHIP_ICM42600 },
{ "icm42602", INV_CHIP_ICM42602 },
{ "icm42605", INV_CHIP_ICM42605 },
+ { "icm42607", INV_CHIP_ICM42607 },
+ { "icm42607p", INV_CHIP_ICM42607P },
{ "icm42686", INV_CHIP_ICM42686 },
{ "icm42622", INV_CHIP_ICM42622 },
{ "icm42688", INV_CHIP_ICM42688 },
@@ -96,6 +133,12 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
}, {
.compatible = "invensense,icm42605",
.data = (void *)INV_CHIP_ICM42605,
+ }, {
+ .compatible = "invensense,icm42607",
+ .data = (void *)INV_CHIP_ICM42607,
+ }, {
+ .compatible = "invensense,icm42607p",
+ .data = (void *)INV_CHIP_ICM42607P,
}, {
.compatible = "invensense,icm42686",
.data = (void *)INV_CHIP_ICM42686,
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
index 13e2e7d38638..6bfd5598b262 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
@@ -48,6 +48,35 @@ static int inv_icm42600_spi_bus_setup(struct inv_icm42600_state *st)
INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
}
+static int inv_icm42607_spi_bus_setup(struct inv_icm42600_state *st)
+{
+ unsigned int mask, val;
+ int ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_DEVICE_CONFIG,
+ INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE,
+ INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN |
+ INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN, 0);
+ if (ret)
+ return ret;
+
+ mask = INV_ICM42607_DRIVE_CONFIG3_SPI_MASK;
+ val = INV_ICM42607_DRIVE_CONFIG3_SPI(INV_ICM42600_SLEW_RATE_INF_2NS);
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_DRIVE_CONFIG3,
+ mask, val);
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK,
+ INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS);
+}
+
static int inv_icm42600_probe(struct spi_device *spi)
{
const void *match;
@@ -59,12 +88,22 @@ static int inv_icm42600_probe(struct spi_device *spi)
return -EINVAL;
chip = (uintptr_t)match;
- /* use SPI specific regmap */
- regmap = devm_regmap_init_spi(spi, &inv_icm42600_spi_regmap_config);
- if (IS_ERR(regmap))
- return PTR_ERR(regmap);
-
- return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup);
+ switch (chip) {
+ case INV_CHIP_ICM42607:
+ case INV_CHIP_ICM42607P:
+ regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+ return inv_icm42600_core_probe(regmap, chip,
+ inv_icm42607_spi_bus_setup);
+ default:
+ /* use SPI specific regmap */
+ regmap = devm_regmap_init_spi(spi, &inv_icm42600_spi_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+ return inv_icm42600_core_probe(regmap, chip,
+ inv_icm42600_spi_bus_setup);
+ }
}
/*
@@ -75,6 +114,8 @@ static const struct spi_device_id inv_icm42600_id[] = {
{ "icm42600", INV_CHIP_ICM42600 },
{ "icm42602", INV_CHIP_ICM42602 },
{ "icm42605", INV_CHIP_ICM42605 },
+ { "icm42607", INV_CHIP_ICM42607 },
+ { "icm42607p", INV_CHIP_ICM42607P },
{ "icm42686", INV_CHIP_ICM42686 },
{ "icm42622", INV_CHIP_ICM42622 },
{ "icm42688", INV_CHIP_ICM42688 },
@@ -93,6 +134,12 @@ static const struct of_device_id inv_icm42600_of_matches[] = {
}, {
.compatible = "invensense,icm42605",
.data = (void *)INV_CHIP_ICM42605,
+ }, {
+ .compatible = "invensense,icm42607",
+ .data = (void *)INV_CHIP_ICM42607,
+ }, {
+ .compatible = "invensense,icm42607p",
+ .data = (void *)INV_CHIP_ICM42607P,
}, {
.compatible = "invensense,icm42686",
.data = (void *)INV_CHIP_ICM42686,
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
index 727b03d541a5..fdda555dbd16 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
@@ -46,6 +46,34 @@ static int inv_icm42600_temp_read(struct inv_icm42600_state *st, s16 *temp)
return ret;
}
+static int inv_icm42607_temp_read(struct inv_icm42600_state *st, s16 *temp)
+{
+ struct device *dev = regmap_get_device(st->map);
+ __be16 *raw;
+ int ret;
+
+ PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+ if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+ return -ENXIO;
+
+ guard(mutex)(&st->lock);
+
+ ret = inv_icm42607_set_temp_conf(st, true, NULL);
+ if (ret)
+ return ret;
+
+ raw = (__be16 *)&st->buffer[0];
+ ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1, raw, sizeof(*raw));
+ if (ret)
+ return ret;
+
+ *temp = (s16)be16_to_cpup(raw);
+ if (*temp == INV_ICM42600_DATA_INVALID)
+ ret = -EINVAL;
+
+ return 0;
+}
+
int inv_icm42600_temp_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -83,3 +111,39 @@ int inv_icm42600_temp_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
}
+
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
+ s16 temp;
+ int ret;
+
+ if (chan->type != IIO_TEMP)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = inv_icm42607_temp_read(st, &temp);
+ if (ret)
+ return ret;
+ *val = temp;
+ return IIO_VAL_INT;
+ /*
+ * T°C = (temp / 128) + 25
+ * Tm°C = 1000 * ((temp * 100 / 12800) + 25)
+ * scale: 100000 / 12800 ~= 7.8125
+ * offset: 25000
+ */
+ case IIO_CHAN_INFO_SCALE:
+ *val = 7;
+ *val2 = 812500;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = 25000;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h
index 3941186512fb..b5b9e4fe3d0e 100644
--- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h
+++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.h
@@ -27,4 +27,8 @@ int inv_icm42600_temp_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask);
+int inv_icm42607_temp_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask);
+
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH V2 5/5] arm64: dts: rockchip: Add icm42607p IMU for RG-DS
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
` (3 preceding siblings ...)
2026-03-19 18:29 ` [PATCH V2 4/5] iio: imu: inv_icm42600: Add support " Chris Morgan
@ 2026-03-19 18:29 ` Chris Morgan
2026-03-19 19:55 ` [PATCH v2 0/5] Add Invensense ICM42607 Jean-Baptiste Maneyrol
2026-03-20 20:00 ` Andy Shevchenko
6 siblings, 0 replies; 16+ messages in thread
From: Chris Morgan @ 2026-03-19 18:29 UTC (permalink / raw)
To: linux-iio
Cc: andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
From: Chris Morgan <macromorgan@hotmail.com>
Add the Invensense ICM42607P IMU for the Anbernic RG-DS. Mount-matrix
was tested with iio-sensor-proxy and reports correct orientation.
Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
---
.../dts/rockchip/rk3568-anbernic-rg-ds.dts | 20 ++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
index 8d906ab02c5f..dca270abc475 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts
@@ -871,7 +871,18 @@ aw87391_pa_r: audio-codec@5b {
sound-name-prefix = "Right Amp";
};
- /* invensense,icm42607p at 0x68 */
+ icm42607p: imu@68 {
+ compatible = "invensense,icm42607p";
+ reg = <0x68>;
+ interrupt-names = "INT1";
+ interrupt-parent = <&gpio0>;
+ interrupts = <RK_PD6 IRQ_TYPE_EDGE_FALLING>;
+ mount-matrix = "-1", "0", "0",
+ "0", "1", "0",
+ "0", "0", "-1";
+ pinctrl-0 = <&accel_irq>;
+ pinctrl-names = "default";
+ };
};
&i2c3 {
@@ -932,6 +943,13 @@ &i2s1_8ch {
};
&pinctrl {
+ accel {
+ accel_irq: accel-irq {
+ rockchip,pins =
+ <0 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
gpio-keys {
vol_keys_l: vol-keys_l {
rockchip,pins =
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v2 0/5] Add Invensense ICM42607
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
` (4 preceding siblings ...)
2026-03-19 18:29 ` [PATCH V2 5/5] arm64: dts: rockchip: Add icm42607p IMU for RG-DS Chris Morgan
@ 2026-03-19 19:55 ` Jean-Baptiste Maneyrol
2026-03-19 21:31 ` Chris Morgan
[not found] ` <abxrQ7MUw4QXnYZG@wintermute.localhost.fail>
2026-03-20 20:00 ` Andy Shevchenko
6 siblings, 2 replies; 16+ messages in thread
From: Jean-Baptiste Maneyrol @ 2026-03-19 19:55 UTC (permalink / raw)
To: Chris Morgan, linux-iio@vger.kernel.org
Cc: andy@kernel.org, nuno.sa@analog.com, dlechner@baylibre.com,
jic23@kernel.org, linux-rockchip@lists.infradead.org,
devicetree@vger.kernel.org, heiko@sntech.de, conor+dt@kernel.org,
krzk+dt@kernel.org, robh@kernel.org, andriy.shevchenko@intel.com,
Chris Morgan
>
>________________________________________
>From: Chris Morgan <macroalpha82@gmail.com>
>Sent: Thursday, March 19, 2026 19:29
>To: linux-iio@vger.kernel.org <linux-iio@vger.kernel.org>
>Cc: andy@kernel.org <andy@kernel.org>; nuno.sa@analog.com <nuno.sa@analog.com>; dlechner@baylibre.com <dlechner@baylibre.com>; jic23@kernel.org <jic23@kernel.org>; Jean-Baptiste Maneyrol <Jean-Baptiste.Maneyrol@tdk.com>; linux-rockchip@lists.infradead.org <linux-rockchip@lists.infradead.org>; devicetree@vger.kernel.org <devicetree@vger.kernel.org>; heiko@sntech.de <heiko@sntech.de>; conor+dt@kernel.org <conor+dt@kernel.org>; krzk+dt@kernel.org <krzk+dt@kernel.org>; robh@kernel.org <robh@kernel.org>; andriy.shevchenko@intel.com <andriy.shevchenko@intel.com>; Chris Morgan <macromorgan@hotmail.com>
>Subject: [PATCH v2 0/5] Add Invensense ICM42607
>
>From: Chris Morgan <macromorgan@ hotmail. com> Add support for the ICM42607 IMU. This sensor shares the same functionality but a different register layout with the existing ICM42600. This driver should work with the ICM42607 and ICM42607P
>ZjQcmQRYFpfptBannerStart
>This Message Is From an Untrusted Sender
>You have not previously corresponded with this sender.
>
>ZjQcmQRYFpfptBannerEnd
>From: Chris Morgan <macromorgan@hotmail.com>
>
>Add support for the ICM42607 IMU. This sensor shares the same
>functionality but a different register layout with the existing
>ICM42600.
>
>This driver should work with the ICM42607 and ICM42607P over both I2C
>and SPI, however only the ICM42607P over I2C could be tested.
>
>Changes Since V1:
> - Instead of creating a new driver, merged with the existing inv_icm42600
> driver. This necessitated adding some code to the existing driver to
> permit using a different register layout for the same functionality.
> - Split changes up a bit more to decrease the size of the individual
> patches. Note that patch 0004 is still pretty hefty; if I need to split
> further I may need to create some temporary stub functions.
> - Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
> per Jonathan's recommendations.
>
>Chris Morgan (5):
> dt-bindings: iio: imu: add icm42607
> iio: imu: inv_icm42600: Add support for using alternate registers
> iio: imu: inv_icm42600: Add registers for icm42607
> iio: imu: inv_icm42600: Add support for icm42607
> arm64: dts: rockchip: Add icm42607p IMU for RG-DS
>
> .../bindings/iio/imu/invensense,icm42600.yaml | 4 +
> .../dts/rockchip/rk3568-anbernic-rg-ds.dts | 20 +-
> drivers/iio/imu/inv_icm42600/inv_icm42600.h | 333 +++++++-
> .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 497 ++++++++++-
> .../imu/inv_icm42600/inv_icm42600_buffer.c | 240 +++++-
> .../imu/inv_icm42600/inv_icm42600_buffer.h | 5 +
> .../iio/imu/inv_icm42600/inv_icm42600_core.c | 795 +++++++++++++++---
> .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 379 ++++++++-
> .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 53 +-
> .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 59 +-
> .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 64 ++
> .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 4 +
> 12 files changed, 2289 insertions(+), 164 deletions(-)
>
>--
>2.43.0
>
>
Hello Chris,
thanks for the patch, but beware that there is a major difference between this
chip and inv_icm42600 chips family that is preventing to have a common driver.
inv_icm42600 chips are using direct register access with bank while icm42607
chip is using indirect register access using IREG specific registers. Some
registers cannot be read/write directly and requires programming specific
registers. The mechanism is similar to the one in inv_icm45600 driver, you can
have a look in this driver.
Using the same driver is not possible I think, since register access is different.
And there are also more differences between the 2 chip families that is making
a common driver quite difficult to do.
Thanks,
JB
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 0/5] Add Invensense ICM42607
2026-03-19 19:55 ` [PATCH v2 0/5] Add Invensense ICM42607 Jean-Baptiste Maneyrol
@ 2026-03-19 21:31 ` Chris Morgan
[not found] ` <abxrQ7MUw4QXnYZG@wintermute.localhost.fail>
1 sibling, 0 replies; 16+ messages in thread
From: Chris Morgan @ 2026-03-19 21:31 UTC (permalink / raw)
To: Jean-Baptiste Maneyrol
Cc: Chris Morgan, linux-iio@vger.kernel.org, andy@kernel.org,
nuno.sa@analog.com, dlechner@baylibre.com, jic23@kernel.org,
linux-rockchip@lists.infradead.org, devicetree@vger.kernel.org,
heiko@sntech.de, conor+dt@kernel.org, krzk+dt@kernel.org,
robh@kernel.org, andriy.shevchenko@intel.com
On Thu, Mar 19, 2026 at 07:55:19PM +0000, Jean-Baptiste Maneyrol wrote:
> >
> >________________________________________
> >From: Chris Morgan <macroalpha82@gmail.com>
> >Sent: Thursday, March 19, 2026 19:29
> >To: linux-iio@vger.kernel.org <linux-iio@vger.kernel.org>
> >Cc: andy@kernel.org <andy@kernel.org>; nuno.sa@analog.com <nuno.sa@analog.com>; dlechner@baylibre.com <dlechner@baylibre.com>; jic23@kernel.org <jic23@kernel.org>; Jean-Baptiste Maneyrol <Jean-Baptiste.Maneyrol@tdk.com>; linux-rockchip@lists.infradead.org <linux-rockchip@lists.infradead.org>; devicetree@vger.kernel.org <devicetree@vger.kernel.org>; heiko@sntech.de <heiko@sntech.de>; conor+dt@kernel.org <conor+dt@kernel.org>; krzk+dt@kernel.org <krzk+dt@kernel.org>; robh@kernel.org <robh@kernel.org>; andriy.shevchenko@intel.com <andriy.shevchenko@intel.com>; Chris Morgan <macromorgan@hotmail.com>
> >Subject: [PATCH v2 0/5] Add Invensense ICM42607
> >
> >From: Chris Morgan <macromorgan@ hotmail. com> Add support for the ICM42607 IMU. This sensor shares the same functionality but a different register layout with the existing ICM42600. This driver should work with the ICM42607 and ICM42607P
> >ZjQcmQRYFpfptBannerStart
> >This Message Is From an Untrusted Sender
> >You have not previously corresponded with this sender.
> >
> >ZjQcmQRYFpfptBannerEnd
> >From: Chris Morgan <macromorgan@hotmail.com>
> >
> >Add support for the ICM42607 IMU. This sensor shares the same
> >functionality but a different register layout with the existing
> >ICM42600.
> >
> >This driver should work with the ICM42607 and ICM42607P over both I2C
> >and SPI, however only the ICM42607P over I2C could be tested.
> >
> >Changes Since V1:
> > - Instead of creating a new driver, merged with the existing inv_icm42600
> > driver. This necessitated adding some code to the existing driver to
> > permit using a different register layout for the same functionality.
> > - Split changes up a bit more to decrease the size of the individual
> > patches. Note that patch 0004 is still pretty hefty; if I need to split
> > further I may need to create some temporary stub functions.
> > - Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
> > per Jonathan's recommendations.
> >
> >Chris Morgan (5):
> > dt-bindings: iio: imu: add icm42607
> > iio: imu: inv_icm42600: Add support for using alternate registers
> > iio: imu: inv_icm42600: Add registers for icm42607
> > iio: imu: inv_icm42600: Add support for icm42607
> > arm64: dts: rockchip: Add icm42607p IMU for RG-DS
> >
> > .../bindings/iio/imu/invensense,icm42600.yaml | 4 +
> > .../dts/rockchip/rk3568-anbernic-rg-ds.dts | 20 +-
> > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 333 +++++++-
> > .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 497 ++++++++++-
> > .../imu/inv_icm42600/inv_icm42600_buffer.c | 240 +++++-
> > .../imu/inv_icm42600/inv_icm42600_buffer.h | 5 +
> > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 795 +++++++++++++++---
> > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 379 ++++++++-
> > .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 53 +-
> > .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 59 +-
> > .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 64 ++
> > .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 4 +
> > 12 files changed, 2289 insertions(+), 164 deletions(-)
> >
> >--
> >2.43.0
> >
> >
>
> Hello Chris,
>
> thanks for the patch, but beware that there is a major difference between this
> chip and inv_icm42600 chips family that is preventing to have a common driver.
>
> inv_icm42600 chips are using direct register access with bank while icm42607
> chip is using indirect register access using IREG specific registers. Some
> registers cannot be read/write directly and requires programming specific
> registers. The mechanism is similar to the one in inv_icm45600 driver, you can
> have a look in this driver.
I didn't see anything in the datasheet for the 42607P in regards to the IREG,
but I did see something in the 42607C. That said, near as I can tell from the
drivers that I used as a reference from the Rockchip and Lineage trees this driver
doesn't access anything from those registers.
Still, I'll defer to you on what you think is best. As long as I can use my
accelerometer that's all I care about.
>
> Using the same driver is not possible I think, since register access is different.
>
> And there are also more differences between the 2 chip families that is making
> a common driver quite difficult to do.
>
> Thanks,
> JB
Chris
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH V2 4/5] iio: imu: inv_icm42600: Add support for icm42607
2026-03-19 18:29 ` [PATCH V2 4/5] iio: imu: inv_icm42600: Add support " Chris Morgan
@ 2026-03-20 16:44 ` kernel test robot
2026-03-20 16:55 ` kernel test robot
2026-03-21 17:48 ` Jonathan Cameron
2 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2026-03-20 16:44 UTC (permalink / raw)
To: Chris Morgan, linux-iio
Cc: llvm, oe-kbuild-all, andy, nuno.sa, dlechner, jic23,
jean-baptiste.maneyrol, linux-rockchip, devicetree, heiko,
conor+dt, krzk+dt, robh, andriy.shevchenko, Chris Morgan
Hi Chris,
kernel test robot noticed the following build warnings:
[auto build test WARNING on rockchip/for-next]
[also build test WARNING on linus/master v7.0-rc4 next-20260320]
[cannot apply to jic23-iio/togreg]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Chris-Morgan/dt-bindings-iio-imu-add-icm42607/20260320-061927
base: https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
patch link: https://lore.kernel.org/r/20260319182956.146976-5-macroalpha82%40gmail.com
patch subject: [PATCH V2 4/5] iio: imu: inv_icm42600: Add support for icm42607
config: i386-buildonly-randconfig-003-20260320 (https://download.01.org/0day-ci/archive/20260321/202603210243.jegPzaTL-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260321/202603210243.jegPzaTL-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603210243.jegPzaTL-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c:108:18: warning: unused variable 'inv_icm42607_accel_filter_values' [-Wunused-const-variable]
108 | static const int inv_icm42607_accel_filter_values[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
vim +/inv_icm42607_accel_filter_values +108 drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
95
96 static const char * const inv_icm42600_accel_power_mode_items[] = {
97 "low-noise",
98 "low-power",
99 };
100 static const int inv_icm42600_accel_power_mode_values[] = {
101 INV_ICM42600_SENSOR_MODE_LOW_NOISE,
102 INV_ICM42600_SENSOR_MODE_LOW_POWER,
103 };
104 static const int inv_icm42600_accel_filter_values[] = {
105 INV_ICM42600_FILTER_BW_ODR_DIV_2,
106 INV_ICM42600_FILTER_AVG_16X,
107 };
> 108 static const int inv_icm42607_accel_filter_values[] = {
109 INV_ICM42607_FILTER_BW_25HZ,
110 INV_ICM42607_FILTER_AVG_16X,
111 };
112
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH V2 4/5] iio: imu: inv_icm42600: Add support for icm42607
2026-03-19 18:29 ` [PATCH V2 4/5] iio: imu: inv_icm42600: Add support " Chris Morgan
2026-03-20 16:44 ` kernel test robot
@ 2026-03-20 16:55 ` kernel test robot
2026-03-21 17:48 ` Jonathan Cameron
2 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2026-03-20 16:55 UTC (permalink / raw)
To: Chris Morgan, linux-iio
Cc: oe-kbuild-all, andy, nuno.sa, dlechner, jic23,
jean-baptiste.maneyrol, linux-rockchip, devicetree, heiko,
conor+dt, krzk+dt, robh, andriy.shevchenko, Chris Morgan
Hi Chris,
kernel test robot noticed the following build warnings:
[auto build test WARNING on rockchip/for-next]
[also build test WARNING on linus/master v7.0-rc4 next-20260320]
[cannot apply to jic23-iio/togreg]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Chris-Morgan/dt-bindings-iio-imu-add-icm42607/20260320-061927
base: https://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git for-next
patch link: https://lore.kernel.org/r/20260319182956.146976-5-macroalpha82%40gmail.com
patch subject: [PATCH V2 4/5] iio: imu: inv_icm42600: Add support for icm42607
config: i386-randconfig-r134-20260320 (https://download.01.org/0day-ci/archive/20260321/202603210032.xLBroWQu-lkp@intel.com/config)
compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
sparse: v0.6.5-rc1
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260321/202603210032.xLBroWQu-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603210032.xLBroWQu-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/iio/imu/inv_icm42600/inv_icm42600_core.c: In function 'inv_icm42607_hw_suspend':
>> drivers/iio/imu/inv_icm42600/inv_icm42600_core.c:1150:13: warning: variable 'accel_conf' set but not used [-Wunused-but-set-variable]
1150 | int accel_conf;
| ^~~~~~~~~~
--
>> drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c:108:18: warning: 'inv_icm42607_accel_filter_values' defined but not used [-Wunused-const-variable=]
108 | static const int inv_icm42607_accel_filter_values[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vim +/accel_conf +1150 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
1144
1145 static int inv_icm42607_hw_suspend(struct device *dev)
1146 {
1147 struct inv_icm42600_state *st = dev_get_drvdata(dev);
1148 struct device *accel_dev;
1149 bool wakeup;
> 1150 int accel_conf;
1151 int ret = 0;
1152
1153 guard(mutex)(&st->lock);
1154
1155 st->suspended.gyro = st->conf.gyro.mode;
1156 st->suspended.accel = st->conf.accel.mode;
1157 st->suspended.temp = st->conf.temp_en;
1158 if (pm_runtime_suspended(dev))
1159 return 0;
1160
1161 if (st->fifo.on) {
1162 ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
1163 INV_ICM42607_FIFO_CONFIG1_BYPASS);
1164 if (ret)
1165 return ret;
1166 }
1167
1168 /* keep chip on and wake-up capable if APEX and wakeup on */
1169 accel_dev = &st->indio_accel->dev;
1170 wakeup = st->apex.on && device_may_wakeup(accel_dev);
1171 if (wakeup) {
1172 /* keep accel on and setup irq for wakeup */
1173 accel_conf = st->conf.accel.mode;
1174 enable_irq_wake(st->irq);
1175 disable_irq(st->irq);
1176 } else {
1177 /* disable APEX features and accel if wakeup disabled */
1178 if (st->apex.wom.enable) {
1179 ret = inv_icm42607_disable_wom(st);
1180 if (ret)
1181 return ret;
1182 }
1183 accel_conf = INV_ICM42600_SENSOR_MODE_OFF;
1184 }
1185
1186 ret = inv_icm42607_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
1187 INV_ICM42600_SENSOR_MODE_OFF, false,
1188 NULL);
1189 if (ret)
1190 return ret;
1191
1192 if (!wakeup)
1193 regulator_disable(st->vddio_supply);
1194
1195 return 0;
1196 }
1197
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH V2 1/5] dt-bindings: iio: imu: add icm42607
2026-03-19 18:29 ` [PATCH V2 1/5] dt-bindings: iio: imu: add icm42607 Chris Morgan
@ 2026-03-20 17:39 ` Conor Dooley
0 siblings, 0 replies; 16+ messages in thread
From: Conor Dooley @ 2026-03-20 17:39 UTC (permalink / raw)
To: Chris Morgan
Cc: linux-iio, andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
[-- Attachment #1: Type: text/plain, Size: 75 bytes --]
Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 0/5] Add Invensense ICM42607
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
` (5 preceding siblings ...)
2026-03-19 19:55 ` [PATCH v2 0/5] Add Invensense ICM42607 Jean-Baptiste Maneyrol
@ 2026-03-20 20:00 ` Andy Shevchenko
6 siblings, 0 replies; 16+ messages in thread
From: Andy Shevchenko @ 2026-03-20 20:00 UTC (permalink / raw)
To: Chris Morgan
Cc: linux-iio, andy, nuno.sa, dlechner, jic23, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
Chris Morgan
On Thu, Mar 19, 2026 at 01:29:36PM -0500, Chris Morgan wrote:
> Add support for the ICM42607 IMU. This sensor shares the same
> functionality but a different register layout with the existing
> ICM42600.
>
> This driver should work with the ICM42607 and ICM42607P over both I2C
> and SPI, however only the ICM42607P over I2C could be tested.
Please, make sure each patch is ~750 ±150 LoC, so it's reviewable.
Last patch is unreviewable 2k+ LoC!
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH V2 3/5] iio: imu: inv_icm42600: Add registers for icm42607
2026-03-19 18:29 ` [PATCH V2 3/5] iio: imu: inv_icm42600: Add registers for icm42607 Chris Morgan
@ 2026-03-21 17:25 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2026-03-21 17:25 UTC (permalink / raw)
To: Chris Morgan
Cc: linux-iio, andy, nuno.sa, dlechner, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
On Thu, 19 Mar 2026 13:29:39 -0500
Chris Morgan <macroalpha82@gmail.com> wrote:
> From: Chris Morgan <macromorgan@hotmail.com>
>
> Add the register layout for the icm_42607. Most of the registers are
> similar to that of the icm42600, though at different addresses.
>
> Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Hi Chris,
Just taking a quick look given Jean-Baptiste's concerns
about doing this in the existing driver.
Thanks,
Jonathan
>
> +/* ICM42607 Specific registers. */
> +
> +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
> +
> +/* Register Map for User Bank 0 */
> +#define INV_ICM42607_REG_DEVICE_CONFIG 0x01
> +#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE BIT(2)
> +#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE BIT(0)
> +
> +#define INV_ICM42607_REG_SIGNAL_PATH_RESET 0x02
> +#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET BIT(4)
> +#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH BIT(2)
> +
> +#define INV_ICM42607_REG_DRIVE_CONFIG1 0x03
> +#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK GENMASK(5, 3)
> +#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR(_rate) \
> +FIELD_PREP(INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK, (_rate))
I'd indent the second line of these two line defines to make it easier to
see it's a continuation.
> +#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK GENMASK(2, 0)
> +#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR(_rate) \
> +FIELD_PREP(INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK, (_rate))
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH V2 4/5] iio: imu: inv_icm42600: Add support for icm42607
2026-03-19 18:29 ` [PATCH V2 4/5] iio: imu: inv_icm42600: Add support " Chris Morgan
2026-03-20 16:44 ` kernel test robot
2026-03-20 16:55 ` kernel test robot
@ 2026-03-21 17:48 ` Jonathan Cameron
2 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2026-03-21 17:48 UTC (permalink / raw)
To: Chris Morgan
Cc: linux-iio, andy, nuno.sa, dlechner, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
On Thu, 19 Mar 2026 13:29:40 -0500
Chris Morgan <macroalpha82@gmail.com> wrote:
> From: Chris Morgan <macromorgan@hotmail.com>
>
> Add support for the icm42607 and icm42607p over both I2C and SPI.
> Note that at this time only the icm42607 over i2c has been tested.
>
> This driver was updated based on the existing icm42600 along with
> the datasheet from Invensense and out-of-tree sources included
> in the LineageOS kernels [1] and Rockchip kernels [2], both derived
> from sources provided by Invensense.
>
> [1] https://github.com/LineageOS/android_kernel_nvidia_kernel-nx/tree/lineage-23.0/drivers/iio/imu/inv_icm42607x
> [2] https://github.com/rockchip-linux/kernel/tree/develop-6.6/drivers/iio/imu/inv_icm42670
>
> Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Hi Chris,
Just a quick look to see what was here.
A few comments inline but the big question is clearly whether or not it makes sense
to share the driver at all.
Thanks,
Jonathan
> int inv_icm42600_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
> {
> struct device *dev = regmap_get_device(st->map);
> @@ -1202,6 +1610,62 @@ int inv_icm42600_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio
> return 0;
> }
>
> +int inv_icm42607_accel_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
> +{
> + /* accel events are wakeup capable */
> + ret = devm_device_init_wakeup(&indio_dev->dev);
> + if (ret)
> + return ret;
> +
> + return 0;
return devm_device_init_wakeup();
> +}
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> index 29c8c1871e06..949dbf9c2cd3 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
> .gyro = {
> .mode = INV_ICM42600_SENSOR_MODE_OFF,
> @@ -157,6 +193,16 @@ static const struct inv_icm42600_hw inv_icm42600_hw[INV_CHIP_NB] = {
> .name = "icm42605",
> .conf = &inv_icm42600_default_conf,
> },
> + [INV_CHIP_ICM42607] = {
If this goes ahead, we'd probably want to break up the structure arrays, drop
the enum and instead have extern lines for each individual names structure in the header.
The aim is both give more readable handling using the generic functions to get
the data from whatever firmware is in use and ensure all control is via 'data' in
the chip type specific structures.
We used to do the enum thing a lot but it proved to be a not particularly
good idea and we've been slowly ripping it out again in recent years!
> + .whoami = INV_ICM42607_WHOAMI,
> + .name = "icm42607",
> + .conf = &inv_icm42607_default_conf,
> + },
> + [INV_CHIP_ICM42607P] = {
> + .whoami = INV_ICM42607P_WHOAMI,
> + .name = "icm42607p",
> + .conf = &inv_icm42607_default_conf,
> + },
> +/**
> + * inv_icm42607_setup() - check and setup chip
> + * @st: driver internal state
> + * @bus_setup: callback for setting up bus specific registers
> + *
> + * Returns 0 on success, a negative error code otherwise.
> + */
> +static int inv_icm42607_setup(struct inv_icm42600_state *st,
> + inv_icm42600_bus_setup bus_setup)
> +{
> + const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip];
> + const struct device *dev = regmap_get_device(st->map);
> + unsigned int val;
> + int ret;
> +
> + ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
> + if (ret)
> + return ret;
> +
> + if (val != hw->whoami)
I guess the driver is doing this for other devices. That's a historical
thing. For new code (+ slowly fixing up drivers) we always accept the
dt binding value even if there is a whoami match failure because that enables
fallback compatibles. That is newer devices can be supported by older
kernels without requiring code changes.
Instead just print an info message as it might help with debugging.
> + return dev_err_probe(dev, -ENODEV,
> + "invalid whoami %#02x expected %#02x (%s)\n",
> + val, hw->whoami, hw->name);
> +
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> index 32aa2e52df2e..eb590eb4f397 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st,
> struct iio_chan_spec const *chan,
> s16 *val)
> @@ -188,6 +265,58 @@ static int inv_icm42600_gyro_read_sensor(struct inv_icm42600_state *st,
> return ret;
> }
>
> +static int inv_icm42607_gyro_read_sensor(struct inv_icm42600_state *st,
> + struct iio_chan_spec const *chan,
> + s16 *val)
> +{
...
> + conf.mode = INV_ICM42600_SENSOR_MODE_LOW_NOISE;
> + ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
> + if (ret)
> + return ret;
> +
> + /* read gyro register data */
> + data = (__be16 *)&st->buffer[0];
Similar to below, I'd be use the buffer directly in the call and
an unaligned get to reduce alignment assumptions.
And sizeof(__be16) given then there won't be a local variable to use.
> + ret = regmap_bulk_read(st->map, reg, data, sizeof(*data));
> + if (ret)
> + return ret;
> +
> + *val = (s16)be16_to_cpup(data);
> + if (*val == INV_ICM42607_DATA_INVALID)
> + ret = -EINVAL;
return -EINVAL;
return 0;
> +
> + return ret;
> +}
>
> static int inv_icm42600_gyro_read_scale(struct iio_dev *indio_dev,
> int *val, int *val2)
> @@ -276,12 +419,21 @@ static int inv_icm42600_gyro_write_scale(struct iio_dev *indio_dev,
>
> conf.fs = idx / 2;
>
> - pm_runtime_get_sync(dev);
> -
> - scoped_guard(mutex, &st->lock)
> - ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
> + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
> + if (PM_RUNTIME_ACQUIRE_ERR(&pm))
> + return -ENXIO;
>
> - pm_runtime_put_autosuspend(dev);
Do this in a precursor patch, not buried in here.
> + switch (st->chip) {
> + case INV_CHIP_ICM42607:
> + case INV_CHIP_ICM42607P:
> + scoped_guard(mutex, &st->lock)
> + ret = inv_icm42607_set_gyro_conf(st, &conf, NULL);
> + break;
> + default:
> + scoped_guard(mutex, &st->lock)
> + ret = inv_icm42600_set_gyro_conf(st, &conf, NULL);
> + break;
> + }
>
> return ret;
> }
> @@ -783,6 +1089,56 @@ int inv_icm42600_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_
> return 0;
> }
>
> +int inv_icm42607_gyro_init(struct inv_icm42600_state *st, struct iio_dev *indio_dev)
> +{
...
> +
> + ret = devm_iio_device_register(dev, indio_dev);
> + if (ret)
> + return ret;
return devm_iio_device_register();
> +
> + return 0;
> +}
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
> index 13e2e7d38638..6bfd5598b262 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c
> static int inv_icm42600_probe(struct spi_device *spi)
> {
> const void *match;
> @@ -59,12 +88,22 @@ static int inv_icm42600_probe(struct spi_device *spi)
> return -EINVAL;
> chip = (uintptr_t)match;
>
> - /* use SPI specific regmap */
> - regmap = devm_regmap_init_spi(spi, &inv_icm42600_spi_regmap_config);
> - if (IS_ERR(regmap))
> - return PTR_ERR(regmap);
> -
> - return inv_icm42600_core_probe(regmap, chip, inv_icm42600_spi_bus_setup);
> + switch (chip) {
> + case INV_CHIP_ICM42607:
> + case INV_CHIP_ICM42607P:
> + regmap = devm_regmap_init_spi(spi, &inv_icm42607_regmap_config);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> + return inv_icm42600_core_probe(regmap, chip,
> + inv_icm42607_spi_bus_setup);
> + default:
> + /* use SPI specific regmap */
This comment is a bit odd given the above is also an SPI specific regmap
and the naming makes it obvious. Drop the comment.
> + regmap = devm_regmap_init_spi(spi, &inv_icm42600_spi_regmap_config);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> + return inv_icm42600_core_probe(regmap, chip,
> + inv_icm42600_spi_bus_setup);
> + }
> }
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
> index 727b03d541a5..fdda555dbd16 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_temp.c
> @@ -46,6 +46,34 @@ static int inv_icm42600_temp_read(struct inv_icm42600_state *st, s16 *temp)
> return ret;
> }
>
> +static int inv_icm42607_temp_read(struct inv_icm42600_state *st, s16 *temp)
> +{
> + struct device *dev = regmap_get_device(st->map);
> + __be16 *raw;
> + int ret;
> +
> + PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
> + if (PM_RUNTIME_ACQUIRE_ERR(&pm))
> + return -ENXIO;
No problem with this in general as it makes the code cleaner, but I'd kind
of expect to ensure consistent local style by updating other places in a
precursor patch.
> +
> + guard(mutex)(&st->lock);
> +
> + ret = inv_icm42607_set_temp_conf(st, true, NULL);
> + if (ret)
> + return ret;
> +
> + raw = (__be16 *)&st->buffer[0];
Whilst existing code does this, I'm not sure why we'd pass cast to __be16 * before
passing it to a function taking a void *
> + ret = regmap_bulk_read(st->map, INV_ICM42607_REG_TEMP_DATA1, raw, sizeof(*raw));
> + if (ret)
> + return ret;
> +
> + *temp = (s16)be16_to_cpup(raw);
Also true in existing code, but this is making a strong assumption about continued
behaviour of IIO_DMA_MINALIGN and that being at least 2.
I'd be tempted to use an unaligned get just to avoid that assumption.
> + if (*temp == INV_ICM42600_DATA_INVALID)
> + ret = -EINVAL;
return -EINVAL; ?
No point in setting it otherwise.
> +
> + return 0;
> +}
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH V2 2/5] iio: imu: inv_icm42600: Add support for using alternate registers
2026-03-19 18:29 ` [PATCH V2 2/5] iio: imu: inv_icm42600: Add support for using alternate registers Chris Morgan
@ 2026-03-21 17:50 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2026-03-21 17:50 UTC (permalink / raw)
To: Chris Morgan
Cc: linux-iio, andy, nuno.sa, dlechner, jean-baptiste.maneyrol,
linux-rockchip, devicetree, heiko, conor+dt, krzk+dt, robh,
andriy.shevchenko, Chris Morgan
On Thu, 19 Mar 2026 13:29:38 -0500
Chris Morgan <macroalpha82@gmail.com> wrote:
> From: Chris Morgan <macromorgan@hotmail.com>
>
> Add support to the existing inv_icm42600 to support similar hardware
> with slightly different register layouts. For example the icm42607
> and icm42607p has most of the same functionality and even many of
> the same registers, but the addresses for indiviual registers differ.
>
> Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
> diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> index 11339ddf1da3..32aa2e52df2e 100644
> --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_gyro.c
> @@ -775,13 +774,13 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
> ret = devm_iio_kfifo_buffer_setup(dev, indio_dev,
> &inv_icm42600_buffer_ops);
> if (ret)
> - return ERR_PTR(ret);
> + return ret;
>
> ret = devm_iio_device_register(dev, indio_dev);
return devm_iio_device_register() now make sense.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 0/5] Add Invensense ICM42607
[not found] ` <abxrQ7MUw4QXnYZG@wintermute.localhost.fail>
@ 2026-03-24 15:25 ` Chris Morgan
0 siblings, 0 replies; 16+ messages in thread
From: Chris Morgan @ 2026-03-24 15:25 UTC (permalink / raw)
To: Jean-Baptiste Maneyrol
Cc: Chris Morgan, linux-iio@vger.kernel.org, andy@kernel.org,
nuno.sa@analog.com, dlechner@baylibre.com, jic23@kernel.org,
linux-rockchip@lists.infradead.org, devicetree@vger.kernel.org,
heiko@sntech.de, conor+dt@kernel.org, krzk+dt@kernel.org,
robh@kernel.org, andriy.shevchenko@intel.com
On Thu, Mar 19, 2026 at 04:31:50PM -0500, Chris Morgan wrote:
> On Thu, Mar 19, 2026 at 07:55:19PM +0000, Jean-Baptiste Maneyrol wrote:
> > >
> > >________________________________________
> > >From: Chris Morgan <macroalpha82@gmail.com>
> > >Sent: Thursday, March 19, 2026 19:29
> > >To: linux-iio@vger.kernel.org <linux-iio@vger.kernel.org>
> > >Cc: andy@kernel.org <andy@kernel.org>; nuno.sa@analog.com <nuno.sa@analog.com>; dlechner@baylibre.com <dlechner@baylibre.com>; jic23@kernel.org <jic23@kernel.org>; Jean-Baptiste Maneyrol <Jean-Baptiste.Maneyrol@tdk.com>; linux-rockchip@lists.infradead.org <linux-rockchip@lists.infradead.org>; devicetree@vger.kernel.org <devicetree@vger.kernel.org>; heiko@sntech.de <heiko@sntech.de>; conor+dt@kernel.org <conor+dt@kernel.org>; krzk+dt@kernel.org <krzk+dt@kernel.org>; robh@kernel.org <robh@kernel.org>; andriy.shevchenko@intel.com <andriy.shevchenko@intel.com>; Chris Morgan <macromorgan@hotmail.com>
> > >Subject: [PATCH v2 0/5] Add Invensense ICM42607
> > >
> > >From: Chris Morgan <macromorgan@ hotmail. com> Add support for the ICM42607 IMU. This sensor shares the same functionality but a different register layout with the existing ICM42600. This driver should work with the ICM42607 and ICM42607P
> > >ZjQcmQRYFpfptBannerStart
> > >This Message Is From an Untrusted Sender
> > >You have not previously corresponded with this sender.
> > >
> > >ZjQcmQRYFpfptBannerEnd
> > >From: Chris Morgan <macromorgan@hotmail.com>
> > >
> > >Add support for the ICM42607 IMU. This sensor shares the same
> > >functionality but a different register layout with the existing
> > >ICM42600.
> > >
> > >This driver should work with the ICM42607 and ICM42607P over both I2C
> > >and SPI, however only the ICM42607P over I2C could be tested.
> > >
> > >Changes Since V1:
> > > - Instead of creating a new driver, merged with the existing inv_icm42600
> > > driver. This necessitated adding some code to the existing driver to
> > > permit using a different register layout for the same functionality.
> > > - Split changes up a bit more to decrease the size of the individual
> > > patches. Note that patch 0004 is still pretty hefty; if I need to split
> > > further I may need to create some temporary stub functions.
> > > - Used guard() and PM_RUNTIME_ACQUIRE_AUTOSUSPEND() on the new functions
> > > per Jonathan's recommendations.
> > >
> > >Chris Morgan (5):
> > > dt-bindings: iio: imu: add icm42607
> > > iio: imu: inv_icm42600: Add support for using alternate registers
> > > iio: imu: inv_icm42600: Add registers for icm42607
> > > iio: imu: inv_icm42600: Add support for icm42607
> > > arm64: dts: rockchip: Add icm42607p IMU for RG-DS
> > >
> > > .../bindings/iio/imu/invensense,icm42600.yaml | 4 +
> > > .../dts/rockchip/rk3568-anbernic-rg-ds.dts | 20 +-
> > > drivers/iio/imu/inv_icm42600/inv_icm42600.h | 333 +++++++-
> > > .../iio/imu/inv_icm42600/inv_icm42600_accel.c | 497 ++++++++++-
> > > .../imu/inv_icm42600/inv_icm42600_buffer.c | 240 +++++-
> > > .../imu/inv_icm42600/inv_icm42600_buffer.h | 5 +
> > > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 795 +++++++++++++++---
> > > .../iio/imu/inv_icm42600/inv_icm42600_gyro.c | 379 ++++++++-
> > > .../iio/imu/inv_icm42600/inv_icm42600_i2c.c | 53 +-
> > > .../iio/imu/inv_icm42600/inv_icm42600_spi.c | 59 +-
> > > .../iio/imu/inv_icm42600/inv_icm42600_temp.c | 64 ++
> > > .../iio/imu/inv_icm42600/inv_icm42600_temp.h | 4 +
> > > 12 files changed, 2289 insertions(+), 164 deletions(-)
> > >
> > >--
> > >2.43.0
> > >
> > >
> >
> > Hello Chris,
> >
> > thanks for the patch, but beware that there is a major difference between this
> > chip and inv_icm42600 chips family that is preventing to have a common driver.
> >
> > inv_icm42600 chips are using direct register access with bank while icm42607
> > chip is using indirect register access using IREG specific registers. Some
> > registers cannot be read/write directly and requires programming specific
> > registers. The mechanism is similar to the one in inv_icm45600 driver, you can
> > have a look in this driver.
>
> I didn't see anything in the datasheet for the 42607P in regards to the IREG,
> but I did see something in the 42607C. That said, near as I can tell from the
> drivers that I used as a reference from the Rockchip and Lineage trees this driver
> doesn't access anything from those registers.
>
> Still, I'll defer to you on what you think is best. As long as I can use my
> accelerometer that's all I care about.
So closer looking at the 42607-C datasheet, it looks like they have MREG banks, is
that what you're talking about?
If so I can either remove this and create a new driver (as I did with V1),
or I can just keep the 42607P in this driver since it does appear to use only
direct register access.
Let me know what you think so I can rewrite and resubmit it. I'll try to better
break it up this time too by seeing if I can make temp, gyro, and accel functions
all with different commits.
Thank you,
Chris
>
> >
> > Using the same driver is not possible I think, since register access is different.
> >
> > And there are also more differences between the 2 chip families that is making
> > a common driver quite difficult to do.
> >
> > Thanks,
> > JB
>
> Chris
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-03-24 15:25 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-19 18:29 [PATCH v2 0/5] Add Invensense ICM42607 Chris Morgan
2026-03-19 18:29 ` [PATCH V2 1/5] dt-bindings: iio: imu: add icm42607 Chris Morgan
2026-03-20 17:39 ` Conor Dooley
2026-03-19 18:29 ` [PATCH V2 2/5] iio: imu: inv_icm42600: Add support for using alternate registers Chris Morgan
2026-03-21 17:50 ` Jonathan Cameron
2026-03-19 18:29 ` [PATCH V2 3/5] iio: imu: inv_icm42600: Add registers for icm42607 Chris Morgan
2026-03-21 17:25 ` Jonathan Cameron
2026-03-19 18:29 ` [PATCH V2 4/5] iio: imu: inv_icm42600: Add support " Chris Morgan
2026-03-20 16:44 ` kernel test robot
2026-03-20 16:55 ` kernel test robot
2026-03-21 17:48 ` Jonathan Cameron
2026-03-19 18:29 ` [PATCH V2 5/5] arm64: dts: rockchip: Add icm42607p IMU for RG-DS Chris Morgan
2026-03-19 19:55 ` [PATCH v2 0/5] Add Invensense ICM42607 Jean-Baptiste Maneyrol
2026-03-19 21:31 ` Chris Morgan
[not found] ` <abxrQ7MUw4QXnYZG@wintermute.localhost.fail>
2026-03-24 15:25 ` Chris Morgan
2026-03-20 20:00 ` Andy Shevchenko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox