Add Invensense ICM42607
Subsystems (4)
v8 cover Add Invensense ICM42607
From: Chris Morgan <[email protected]>
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.
Changes Since V2:
- Went back to using a new driver on advice from Invensense engineer.
- Further split changes up into smaller chunks of functionality. Note still that the largest patch is approximately 900 lines, and that while the driver compiles cleanly at each commit it is not able to drive the hardware until the commit that adds the Interrupt (as it also adds the Makefile).
- Change the error to a warning when the devicetree binding does not match the hardware ID.
- Dropped the ack on the devicetree bindings, as I am creating a new file (for a new driver) instead of modifying the existing one.
Changes Since V3:
- Numerous small fixes (too many to list here). Thank you to everyone who provided feedback.
- Split power management additions into an additional commit to break things up further.
- Consolidated devicetree documentation in existing invensense,icm42600.yaml file.
- Removed most of the FIELD_PREP from header file to c files to make code easier to read.
- Changed scale values to 2D arrays for Gyro and Accelerometer.
- Removed IIO_CHAN_INFO_CALIBBIAS attribute.
Changes Since V4:
- Additional numerous small fixes, thank you again for all the feedback.
- Dropped power control API and instead run device in low noise mode.
- Split devicetree bindings into two distinct changes.
- Reordered adding of enums and structs to main header file so that they are only brought in when needed.
- Stopped using enum for driver data and instead am using pointer to device specific driver data.
Changes Since V5:
- Corrected use of "dev_warn_probe" to just "dev_warn".
- Fixed some return scenarios which would unconditionally return 0 when an error was present.
- Corrected use of max() to min() for bounds checking. max() was incorrect.
- Fixed using "st->conf.accel.odr" in the gyroscope function. It should have been "st->conf.gyro.odr" which it now is.
- Additional small fixes suggested by "sashiko.dev".
- Added a regmap cache. I used the datasheet to try and determine which registers might change without explicit writes.
Changes Since V6:
- Corrected additional errors identified by sashiko.dev, mostly fixing potential deadlocks, missing calls for pm runtime, and potential overflow issues.
Changes Since V7:
- Dropped Wake on Movement patches, since some of the functionality was only available for a device on which I cannot test.
- Dropped support for SPI 3-Wire mode, since it complicated the bus setup (and I lack the hardware to test such features anyway).
- Fixed a few additional bugs identified by sashiko.dev bot.
Chris Morgan (10):
dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
dt-bindings: iio: imu: icm42600: Add icm42607 binding
iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
iio: imu: inv_icm42607: Add I2C and SPI For icm42607
iio: imu: inv_icm42607: Add PM support for icm42607
iio: imu: inv_icm42607: Add Buffer support for icm42607
iio: imu: inv_icm42607: Add Temp Support in icm42607
iio: imu: inv_icm42607: Add Accelerometer for icm42607
iio: imu: inv_icm42607: Add Gyroscope to 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/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42607/Kconfig | 30 + drivers/iio/imu/inv_icm42607/Makefile | 14 + drivers/iio/imu/inv_icm42607/inv_icm42607.h | 428 +++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 587 +++++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.c | 573 +++++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.h | 95 +++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 597 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_gyro.c | 552 ++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 90 +++ .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 102 +++ .../iio/imu/inv_icm42607/inv_icm42607_temp.c | 80 +++ .../iio/imu/inv_icm42607/inv_icm42607_temp.h | 33 + 16 files changed, 3206 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig create mode 100644 drivers/iio/imu/inv_icm42607/Makefile create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
Signature · 1 line
2.43.0
PATCH v8 1/10 dt-bindings: iio: imu: icm42600: Add mount-matrix to icm42600
From: Chris Morgan <[email protected]>
Add mount-matrix attribute to schema. This attribute has been supported since the first revision of this driver, but was not documented.
--- .../devicetree/bindings/iio/imu/invensense,icm42600.yaml | 2 ++ 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +2 -0
@@ -53,6 +53,8 @@ properties: drive-open-drain: type: boolean + mount-matrix: true + vdd-supply: description: Regulator that provides power to the sensor
Signature · 1 line
2.43.0
PATCH v8 2/10 dt-bindings: iio: imu: icm42600: Add icm42607 binding
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add devicetree binding for the Invensense ICM42607 and Invensense ICM42607P inertial measurement unit. This unit is a combined accelerometer, gyroscope, and thermometer available via I2C or SPI.
This device is functionally very similar to the icm42600 series with a very different register layout.
--- .../devicetree/bindings/iio/imu/invensense,icm42600.yaml | 2 ++ 1 file changed, 2 insertions(+)
Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +2 -0
@@ -30,6 +30,8 @@ properties: - invensense,icm42600 - invensense,icm42602 - invensense,icm42605 + - invensense,icm42607 + - invensense,icm42607p - invensense,icm42622 - invensense,icm42631 - invensense,icm42686
Signature · 1 line
2.43.0
Jonathan Cameron
maintainerRe: [PATCH V8 02/10] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 11 lines · On Mon, 18 May 2026 15:05:17 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add devicetree binding for the Invensense ICM42607 and Invensense ICM42607P inertial measurement unit. This unit is a combined accelerometer, gyroscope, and thermometer available via I2C or SPI.
This device is functionally very similar to the icm42600 series with a very different register layout.
Signed-off-by Chris Morgan <[email protected]>
Note that Sashiko has highlighted that the binding this being added to has a potential problem.
interrupts are required but interrupt-names are not. That would be fine but the binding doesn't say there is a default ordering for the interrupts - so if we don't have names we have no idea which interrupt it is.
This needs fixing - probably by adding a default
Jonathan
Quoted 17 lines
--- .../devicetree/bindings/iio/imu/invensense,icm42600.yaml | 2 ++ 1 file changed, 2 insertions(+)Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +2
-0@@ -30,6 +30,8 @@ properties: - invensense,icm42600 - invensense,icm42602 - invensense,icm42605 + - invensense,icm42607 + - invensense,icm42607p - invensense,icm42622 - invensense,icm42631 - invensense,icm42686
Re: [PATCH V8 02/10] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 17 lines · Jonathan Cameron
Quoted 11 lines · On Mon, 18 May 2026 15:05:17 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add devicetree binding for the Invensense ICM42607 and Invensense ICM42607P inertial measurement unit. This unit is a combined accelerometer, gyroscope, and thermometer available via I2C or SPI.
This device is functionally very similar to the icm42600 series with a very different register layout.
Signed-off-by Chris Morgan <[email protected]>Note that Sashiko has highlighted that the binding this being added to has a potential problem.
Quoted 6 lines
interrupts are required but interrupt-names are not. That would be fine but the binding doesn't say there is a default ordering for the interrupts - so if we don't have names we have no idea which interrupt it is.
This needs fixing - probably by adding a default
Worth pointing out that this isn't an issue with this particular patch, the problem exists in mainline.
Re: [PATCH V8 02/10] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 23 lines · Conor Dooley
Quoted 22 lines · Jonathan Cameron
Quoted 11 lines · On Mon, 18 May 2026 15:05:17 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add devicetree binding for the Invensense ICM42607 and Invensense ICM42607P inertial measurement unit. This unit is a combined accelerometer, gyroscope, and thermometer available via I2C or SPI.
This device is functionally very similar to the icm42600 series with a very different register layout.
Signed-off-by Chris Morgan <[email protected]>Note that Sashiko has highlighted that the binding this being added to has a potential problem.
interrupts are required but interrupt-names are not. That would be fine but the binding doesn't say there is a default ordering for the interrupts - so if we don't have names we have no idea which interrupt it is.
Quoted 4 lines
Quoted 1 line
This needs fixing - probably by adding a default
Worth pointing out that this isn't an issue with this particular patch, the problem exists in mainline.
The driver I lovingly borrowed this code from seems to have fallback logic, basically picking the first interrupt if it couldn't find one named "INT1". I was told early on not to do this that way, so in my case the interrupt-names would be required (but not for the existing driver because of this fallback).
Should I make the requirement conditional just to my compatible strings?
Thank you,
Chris
Re: [PATCH V8 02/10] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 29 lines · Chris Morgan
Quoted 23 lines · Conor Dooley
Quoted 22 lines · Jonathan Cameron
Quoted 11 lines · On Mon, 18 May 2026 15:05:17 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add devicetree binding for the Invensense ICM42607 and Invensense ICM42607P inertial measurement unit. This unit is a combined accelerometer, gyroscope, and thermometer available via I2C or SPI.
This device is functionally very similar to the icm42600 series with a very different register layout.
Signed-off-by Chris Morgan <[email protected]>Note that Sashiko has highlighted that the binding this being added to has a potential problem.
interrupts are required but interrupt-names are not. That would be fine but the binding doesn't say there is a default ordering for the interrupts - so if we don't have names we have no idea which interrupt it is.
Quoted 4 lines
Quoted 1 line
This needs fixing - probably by adding a default
Worth pointing out that this isn't an issue with this particular patch, the problem exists in mainline.
Quoted 8 lines
The driver I lovingly borrowed this code from seems to have fallback logic, basically picking the first interrupt if it couldn't find one named "INT1". I was told early on not to do this that way, so in my case the interrupt-names would be required (but not for the existing driver because of this fallback).
Should I make the requirement conditional just to my compatible strings?
Sure, sounds like a good idea to me.
Jonathan Cameron
maintainerRe: [PATCH V8 02/10] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 30 lines · On Thu, 21 May 2026 21:08:07 +0100 Conor Dooley <[email protected]> wrote:
Quoted 29 lines · Chris Morgan
Quoted 27 lines · Conor Dooley
Quoted 17 lines · Jonathan Cameron
Quoted 11 lines · On Mon, 18 May 2026 15:05:17 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add devicetree binding for the Invensense ICM42607 and Invensense ICM42607P inertial measurement unit. This unit is a combined accelerometer, gyroscope, and thermometer available via I2C or SPI.
This device is functionally very similar to the icm42600 series with a very different register layout.
Signed-off-by Chris Morgan <[email protected]>Note that Sashiko has highlighted that the binding this being added to has a potential problem.
Quoted 6 lines
interrupts are required but interrupt-names are not. That would be fine but the binding doesn't say there is a default ordering for the interrupts - so if we don't have names we have no idea which interrupt it is.
This needs fixing - probably by adding a default
Worth pointing out that this isn't an issue with this particular patch, the problem exists in mainline.
Quoted 6 lines
Quoted 6 lines
The driver I lovingly borrowed this code from seems to have fallback logic, basically picking the first interrupt if it couldn't find one named "INT1". I was told early on not to do this that way, so in my case the interrupt-names would be required (but not for the existing driver because of this fallback).
Ah, so it has a default that we've elected not to document.
I can't remember the history of that - probably similar discussion about there being no right default when there are two (near?) identical operating interrupt pins.
Quoted 4 lines
Quoted 2 lines
Should I make the requirement conditional just to my compatible strings?
Sure, sounds like a good idea to me
Agreed - that closes this for this part without spitting lots of warnings for the older one.
J
PATCH v8 3/10 iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add the core component of a new inv_icm42607 driver. This includes a few setup functions and the full register definition in the header file.
--- drivers/iio/imu/inv_icm42607/inv_icm42607.h | 332 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 197 +++++++++++ 2 files changed, 529 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
drivers/iio/imu/inv_icm42607/inv_icm42607.h new file +332 -0
@@ -0,0 +1,332 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* +* Copyright (C) 2026 InvenSense, Inc. +*/ + +#ifndef INV_ICM42607_H_ +#define INV_ICM42607_H_ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/iio/iio.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +enum inv_icm42607_sensor_mode { +INV_ICM42607_SENSOR_MODE_OFF , +INV_ICM42607_SENSOR_MODE_STANDBY , +INV_ICM42607_SENSOR_MODE_LOW_POWER , +INV_ICM42607_SENSOR_MODE_LOW_NOISE , +INV_ICM42607_SENSOR_MODE_NB +}; + +/* gyroscope fullscale values */ +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_icm42607_accel_fs { +INV_ICM42607_ACCEL_FS_16G , +INV_ICM42607_ACCEL_FS_8G , +INV_ICM42607_ACCEL_FS_4G , +INV_ICM42607_ACCEL_FS_2G , +INV_ICM42607_ACCEL_FS_NB +}; + +/* ODR values */ +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_icm42607_filter_bw { +/* Low-Noise mode sensor data filter (bandwidth) */ +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 , +}; + +struct inv_icm42607_sensor_conf { +int mode; +int fs; +int odr; +int filter; +}; + +struct inv_icm42607_conf { +struct inv_icm42607_sensor_conf gyro; +struct inv_icm42607_sensor_conf accel; +bool temp_en; +}; + +struct inv_icm42607_hw { +uint8_t whoami; +const char *name; +const struct inv_icm42607_conf *conf; +}; + +/** +* struct inv_icm42607_state - driver state variables +* @lock: lock for serializing multiple registers access. +* @hw: Hardware specific data. +* @map: regmap pointer. +* @vddio_supply: I/O voltage regulator for the chip. +* @irq: chip irq, required to enable/disable and set wakeup +* @orientation: sensor chip orientation relative to main hardware. +* @conf: chip sensors configurations. +*/ +struct inv_icm42607_state { +struct mutex lock; +const struct inv_icm42607_hw *hw; +struct regmap *map; +struct regulator *vddio_supply; +int irq; +struct iio_mount_matrix orientation; +struct inv_icm42607_conf conf; +}; + +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */ + +/* Register Map for User Bank 0 */ +#define INV_ICM42607_REG_MCLK_RDY 0x00 + +#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_SDR_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_DRIVE_CONFIG2 0x04 +#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK GENMASK(5, 3) +#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_DRIVE_CONFIG3 0x05 +#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK GENMASK(2, 0) + +#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_ACCEL_MODE_MASK GENMASK(1, 0) + +#define INV_ICM42607_REG_GYRO_CONFIG0 0x20 +#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK GENMASK(6, 5) +#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK GENMASK(3, 0) + +#define INV_ICM42607_REG_ACCEL_CONFIG0 0x21 +#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK GENMASK(6, 5) +#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK GENMASK(3, 0) + +#define INV_ICM42607_REG_TEMP_CONFIG0 0x22 +#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK GENMASK(6, 4) + +#define INV_ICM42607_REG_GYRO_CONFIG1 0x23 +#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK GENMASK(2, 0) + +#define INV_ICM42607_REG_ACCEL_CONFIG1 0x24 +#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK GENMASK(6, 4) +#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK GENMASK(2, 0) + +#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_REG_WOM_CONFIG 0x27 +#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK GENMASK(4, 3) +#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_FIFO_1SENSOR_PACKET_SIZE 8 +#define INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE 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_INT 0 +#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL 1 +#define INV_ICM42607_INTF_CONFIG1_CLKSEL_OFF 2 + +#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 + +/* Timings as listed in section 3 of datasheet */ +#define INV_ICM42607_POWER_UP_TIME_US 100000 +#define INV_ICM42607_RESET_TIME_MS 1 +#define INV_ICM42607_ACCEL_STARTUP_TIME_MS 10 +#define INV_ICM42607_GYRO_STARTUP_TIME_MS 30 +#define INV_ICM42607_TEMP_STARTUP_TIME_MS 77 + +typedef int (*inv_icm42607_bus_setup )(struct inv_icm42607_state *); + +extern const struct regmap_config inv_icm42607_regmap_config; + +int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw, +inv_icm42607_bus_setup bus_setup); + +#endif
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +197 -0
197 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V8 03/10] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Unsafe hardware reset polling loop with premature timeouts and missing delay. - [High] Strict DT…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unsafe hardware reset polling loop with premature timeouts and missing delay.
- [High] Strict DT requirement for interrupt-names breaks compatibility with valid bindings. --
commit 32920ed238e36be6e7fdd4fa2b84b2b710397641
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
This commit adds the core component of the new inv_icm42607 driver. It includes setup functions and the full register definition in the header file.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +0
-0
[ ... ]
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +3
-0+static int inv_icm42607_setup (struct inv_icm42607_state *st, +inv_icm42607_bus_setup bus_setup) +{
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 93
Quoted 9 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +9
-0+ ret =regmap_write (st->map,INV_ICM42607_REG_SIGNAL_PATH_RESET , +INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET ); +if (ret) +return ret; + + ret =regmap_read_poll_timeout (st->map,INV_ICM42607_REG_INT_STATUS , + val, val &INV_ICM42607_INT_STATUS_RESET_DONE , +INV_ICM42607_RESET_TIME_MS *100 , +INV_ICM42607_RESET_TIME_MS *1000 );
Could this polling loop fail prematurely if the device returns a read error while resetting?
Since regmap_read_poll_timeout() evaluates the loop condition as __ret || (cond), any read error will immediately abort the loop and return the error. If the device is unresponsive on the bus during reset (e.g. returning an I2C NACK), it will instantly defeat the polling mechanism.
Additionally, could the timeout of exactly 1ms cause spurious probe failures?
Since 1ms is the typical hardware reset time, this doesn't leave any margin for scheduling variations or natural hardware differences.
Would it be better to add a mandatory sleep before polling, and increase the timeout margin?
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 146
Quoted 11 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +11
-0+int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw, +inv_icm42607_bus_setup bus_setup) +{ +struct device *dev =regmap_get_device (regmap); +struct inv_icm42607_state *st; +int irq; +int ret; + + irq =fwnode_irq_get_byname (dev_fwnode (dev),"INT1" ); +if (irq <0 ) +return dev_err_probe (dev, irq,"Unable to get INT1 interrupt\n" );
Does this break compatibility with valid device trees that omit the optional interrupt-names property?
If interrupt-names is not provided in the device tree, fwnode_irq_get_byname() will return -EINVAL and abort the probe.
Could this be modified to fallback to fetching the interrupt by index (e.g. fwnode_irq_get(dev_fwnode(dev), 0)) if the named lookup fails?
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +2
-0+ + st =devm_kzalloc (dev,sizeof (*st),GFP_KERNEL );
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Jonathan Cameron
maintainerRe: [PATCH V8 03/10] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In reply to Chris MorganQuoted 7 lines · On Mon, 18 May 2026 15:05:18 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add the core component of a new
inv_icm42607driver. This includes a few setup functions and the full register definition in the header file.Signed-off-by Chris Morgan <[email protected]>
Mainly the interrupt names thing - which is probably a case for a precursor fix for the existing binding.
Otherwise really small stuff I'd not have bothered you with if we weren't already looking like we'll need a v9
Jonathan
Quoted 12 lines
--- drivers/iio/imu/inv_icm42607/inv_icm42607.h | 332 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 197 +++++++++++ 2 files changed, 529 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.cdrivers/iio/imu/inv_icm42607/inv_icm42607.h new file +0
-0
drivers/iio/imu/inv_icm42607/inv_icm42607.h line 329
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h new file +6
-0+ +typedef int (*inv_icm42607_bus_setup )(struct inv_icm42607_state *); + +extern const struct regmap_config inv_icm42607_regmap_config; + +int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw *hw,
Trivial but I'd wrap the line above after first ,
Still prefer staying under 80 chars if it doesn't hurt readability and here it doesn't.
Quoted 13 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h new file +3
-0+ inv_icm42607_bus_setup bus_setup); + +#endif drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +4
-0@@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Copyright (C) 2026 InvenSense, Inc. +*/
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 14
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +10
-0+ +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/iio/iio.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h>
Give the includes another quick check. I'd expect at least dev_printk.h in here. There may be others missing to following the approximate include what you use approach preferred for kernel drivers.
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +11
-0+#include "inv_icm42607.h" +/** +* 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_icm42607_state *st, +inv_icm42607_bus_setup bus_setup) +{
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 82
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +10
-0+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 != st->hw->whoami) + dev_warn(dev, "invalid whoami %#02x expected %#02x (%s)\n",
Can we tweak that to unknown whoami
It might well be valid afterall!
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 89
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +7
-0+ val, st->hw->whoami, st->hw->name); + + ret =regmap_write (st->map,INV_ICM42607_REG_SIGNAL_PATH_RESET , +INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET ); +if (ret) +return ret; +
There is some moaning here from sashiko. I think it's wrong but take a look.
Quoted 26 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +25
-0+ ret =regmap_read_poll_timeout (st->map,INV_ICM42607_REG_INT_STATUS , + val, val &INV_ICM42607_INT_STATUS_RESET_DONE , +INV_ICM42607_RESET_TIME_MS *100 , +INV_ICM42607_RESET_TIME_MS *1000 ); +if (ret) +return dev_err_probe (dev, ret, +"reset error, reset done bit not set\n" ); + + ret =bus_setup (st); +if (ret) +return ret; + + ret =regmap_set_bits (st->map,INV_ICM42607_REG_INTF_CONFIG0 , +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, st->hw->conf); +}
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 144
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +9
-0+int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw, +inv_icm42607_bus_setup bus_setup) +{ +struct device *dev =regmap_get_device (regmap); +struct inv_icm42607_state *st; +int irq; +int ret; + + irq =fwnode_irq_get_byname (dev_fwnode (dev),"INT1" );
Sashiko raises a valid point on this one. The binding has interrupt-names as optional even if we have interrupts. The binding could document a default but doesn't.
Can you check the other drivers sharing that binding and either 'fix' the binding or add a default - I'd guess INT1 - but this wouldn't be the first time a driver has gotten written against a board that wires INT2 only and that's there for the default choice.
Note that sashiko's fallback is a bad idea if we don't have a default in the binding!
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +2
-0+if (irq <0 ) +return dev_err_probe (dev, irq,"Unable to get INT1 interrupt\n" );
Jonathan Cameron
maintainerRe: [PATCH V8 03/10] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In reply to Chris MorganQuoted 6 lines · On Mon, 18 May 2026 15:05:18 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add the core component of a new
inv_icm42607driver. This includes a few setup functions and the full register definition in the header file.
How are you driving the fifo capture? There isn't a trigger and the irq isn't wired up that I can find.
I'm struggling to see how this works.
I would expect to see something like:inv_icm42600_irq_handler()
Ah. This was previously in the wake up patch. That bit we still need for this driver to work.
Quoted 4 lines
Signed-off-by Chris Morgan <[email protected]>---
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +1
-0+int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw *hw,
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 146
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +10
-0+ inv_icm42607_bus_setup bus_setup) +{ +struct device *dev =regmap_get_device (regmap); +struct inv_icm42607_state *st; +int irq; +int ret; + + irq =fwnode_irq_get_byname (dev_fwnode (dev),"INT1" ); +if (irq <0 ) +return dev_err_probe (dev, irq,"Unable to get INT1 interrupt\n" );
This doesn't seem to be used?
Quoted 1 line
+
PATCH v8 4/10 iio: imu: inv_icm42607: Add I2C and SPI For icm42607
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add I2C and SPI driver support for InvenSense ICM-42607 devices. Add necessary Kconfig and Makefile to allow building of (incomplete) driver.
--- drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm42607/Kconfig | 30 ++++++ drivers/iio/imu/inv_icm42607/Makefile | 10 ++ drivers/iio/imu/inv_icm42607/inv_icm42607.h | 12 +++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 62 +++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 89 +++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 101 ++++++++++++++++++ 8 files changed, 306 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42607/Kconfig create mode 100644 drivers/iio/imu/inv_icm42607/Makefile create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c
drivers/iio/imu/Kconfig +1 -0
@@ -109,6 +109,7 @@ config KMX61 be called kmx61. source "drivers/iio/imu/inv_icm42600/Kconfig" +source "drivers/iio/imu/inv_icm42607/Kconfig" source "drivers/iio/imu/inv_icm45600/Kconfig" source "drivers/iio/imu/inv_mpu6050/Kconfig"
drivers/iio/imu/Makefile +1 -0
@@ -25,6 +25,7 @@ obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o obj-y += inv_icm42600/ +obj-y += inv_icm42607/ obj-y += inv_icm45600/ obj-y += inv_mpu6050/
drivers/iio/imu/inv_icm42607/Kconfig new file +30 -0
@@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +config INV_ICM42607 + tristate + select IIO_BUFFER + select IIO_INV_SENSORS_TIMESTAMP + +config INV_ICM42607_I2C + tristate "InvenSense ICM-42607X I2C driver" + depends on I2C + select INV_ICM42607 + select REGMAP_I2C + help + This driver supports the InvenSense ICM-42607 motion tracking + device over I2C. + + This driver can be built as a module. The module will be called + inv-icm42607-i2c. + +config INV_ICM42607_SPI + tristate "InvenSense ICM-42607X SPI driver" + depends on SPI_MASTER + select INV_ICM42607 + select REGMAP_SPI + help + This driver supports the InvenSense ICM-42607 motion tracking + device over SPI. + + This driver can be built as a module. The module will be called + inv-icm42607-spi.
drivers/iio/imu/inv_icm42607/Makefile new file +10 -0
@@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o +inv-icm42607-y += inv_icm42607_core.o + +obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o +inv-icm42607-i2c-y += inv_icm42607_i2c.o + +obj-$(CONFIG_INV_ICM42607_SPI) += inv-icm42607-spi.o +inv-icm42607-spi-y += inv_icm42607_spi.o
drivers/iio/imu/inv_icm42607/inv_icm42607.h +12 -0
@@ -13,6 +13,16 @@#include <linux/regmap.h> #include <linux/regulator/consumer.h> +/* serial bus slew rates */ +enum inv_icm42607_slew_rate { +INV_ICM42607_SLEW_RATE_20_60NS , +INV_ICM42607_SLEW_RATE_12_36NS , +INV_ICM42607_SLEW_RATE_6_18NS , +INV_ICM42607_SLEW_RATE_4_12NS , +INV_ICM42607_SLEW_RATE_2_6NS , +INV_ICM42607_SLEW_RATE_INF_2NS +}; +enum inv_icm42607_sensor_mode {INV_ICM42607_SENSOR_MODE_OFF ,INV_ICM42607_SENSOR_MODE_STANDBY ,
@@ -325,6 +335,8 @@ struct inv_icm42607_state {typedef int (*inv_icm42607_bus_setup )(struct inv_icm42607_state *);extern const struct regmap_config inv_icm42607_regmap_config; +extern const struct inv_icm42607_hw inv_icm42607_hw_data; +extern const struct inv_icm42607_hw inv_icm42607p_hw_data;int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw,inv_icm42607_bus_setup bus_setup);
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +62 -0
74 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +89 -0
89 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c new file +101 -0
101 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V8 04/10] iio: imu: inv_icm42607: Add I2C and SPI For icm42607
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] The driver unconditionally fails to probe if the `interrupt-names` property is missing from the…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The driver unconditionally fails to probe if the interrupt-names property is missing from the devicetree. --
commit f16907e397de069b83b61a52946a989d7853c245
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add I2C and SPI For icm42607
This commit adds I2C and SPI driver support for InvenSense ICM-42607 devices. It introduces the necessary Kconfig and Makefile entries to allow building the new modules.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +0
-0
[ ... ]
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +8
-0+static int inv_icm42607_probe (struct i2c_client *client) +{ +const struct inv_icm42607_hw *hw; +struct regmap *regmap; + + hw =i2c_get_match_data (client); +if (!hw) + return dev_err_probe(&client->dev, -ENODEV,
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c line 55
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +10
-0+ "Failed to get i2c data\n"); + + regmap =devm_regmap_init_i2c (client, &inv_icm42607_regmap_config); +if (IS_ERR (regmap)) +return dev_err_probe (&client->dev,PTR_ERR (regmap), +"Failed to register i2c regmap %ld\n" , +PTR_ERR (regmap)); + +return inv_icm42607_core_probe (regmap, hw, inv_icm42607_i2c_bus_setup); +}
This isn't a bug in this patch specifically, but since this patch enables the I2C and SPI probing, it exposes an issue introduced in the core driver patch.
If the interrupt-names property is missing from the devicetree, the probe unconditionally fails because inv_icm42607_core_probe() does:
irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1");
if (irq < 0)
return dev_err_probe(dev, irq, "Unable to get INT1 interrupt\n");Since interrupt-names is not a required property in the devicetree bindings for invensense,icm42600 (which covers icm42607), a valid devicetree might only provide the interrupts property. In this case, fwnode_irq_get_byname() returns -EINVAL, causing the probe to fail unconditionally and rendering the device unusable.
Should the core driver instead use the pre-resolved client->irq or spi->irq, or fallback to fwnode_irq_get(dev_fwnode(dev), 0) like other drivers in the subsystem do?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Jonathan Cameron
maintainerRe: [PATCH V8 04/10] iio: imu: inv_icm42607: Add I2C and SPI For icm42607
In reply to Chris MorganQuoted 7 lines · On Mon, 18 May 2026 15:05:19 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add I2C and SPI driver support for InvenSense ICM-42607 devices. Add necessary
KconfigandMakefileto allow building of (incomplete) driver.Signed-off-by Chris Morgan <[email protected]>
Hi Chris.
More trivial stuff. Some of which is just to save having to do a follow up patch to move to named initializers for the id tables.
Thanks,
Jonathan
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +0
-0@@ -13,6 +13,16 @@#include <linux/regmap.h>
drivers/iio/imu/inv_icm42607/inv_icm42607.h line 23
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +8
-0#include <linux/regulator/consumer.h> +/* serial bus slew rates */ +enum inv_icm42607_slew_rate { +INV_ICM42607_SLEW_RATE_20_60NS , +INV_ICM42607_SLEW_RATE_12_36NS , +INV_ICM42607_SLEW_RATE_6_18NS , +INV_ICM42607_SLEW_RATE_4_12NS , +INV_ICM42607_SLEW_RATE_2_6NS , +INV_ICM42607_SLEW_RATE_INF_2NS
Probably missing trailing comma. Mind you I'm confused on what the meaning is of INF_2NS - so maybe a comment?
drivers/iio/imu/inv_icm42607/inv_icm42607.h struct inv_icm42607_state { · line 337
Quoted 9 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +2
-0+}; +enum inv_icm42607_sensor_mode {INV_ICM42607_SENSOR_MODE_OFF ,INV_ICM42607_SENSOR_MODE_STANDBY ,@@ -325,6 +335,8 @@ struct inv_icm42607_state {typedef int (*inv_icm42607_bus_setup )(struct inv_icm42607_state *);extern const struct regmap_config inv_icm42607_regmap_config;
This is only introduced in this patch. I'd argue maybe that should have been in the earlier one?
drivers/iio/imu/inv_icm42607/inv_icm42607.h struct inv_icm42607_state { · line 339
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +2
-0+extern const struct inv_icm42607_hw inv_icm42607_hw_data; +extern const struct inv_icm42607_hw inv_icm42607p_hw_data;
I'd also have been tempted to push these into the previous patch even though like the regmap they would have had no users briefly.
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +0
-0int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw,inv_icm42607_bus_setup bus_setup);drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0static int inv_icm42607_set_conf (struct inv_icm42607_state *st,const struct inv_icm42607_conf *conf) {
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_setup(struct inv_icm42607_state *st, · line 156
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0@@ -95,6 +152,11 @@ static int inv_icm42607_setup(struct inv_icm42607_state *st,return dev_err_probe (dev, ret,"reset error, reset done bit not set\n" ); +/* Sync the regcache again after a reset. */ + ret =regcache_sync (st->map);
Silly question but what has this to do with the bus support? Should it be in the previous patch. I suppose you could argue this is where the cache got introduced.
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+if (ret) +return ret; + ret =bus_setup (st);if (ret)return ret;drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +0
-0
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c line 59
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +4
-0@@ -0,0 +1,89 @@ + +static const struct i2c_device_id inv_icm42607_id[] = { + {"icm42607" , (kernel_ulong_t)&inv_icm42607_hw_data }, + {"icm42607p" , (kernel_ulong_t)&inv_icm42607p_hw_data },
Named initializers please. (see below)
Quoted 43 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +30
-0+ { } +}; +MODULE_DEVICE_TABLE (i2c, inv_icm42607_id); + +static const struct of_device_id inv_icm42607_of_matches[] = { + { + .compatible ="invensense,icm42607" , + .data = &inv_icm42607_hw_data, + }, { + .compatible ="invensense,icm42607p" , + .data = &inv_icm42607p_hw_data, + }, + { } +}; +MODULE_DEVICE_TABLE (of, inv_icm42607_of_matches); + +static struct i2c_driver inv_icm42607_driver = { + .driver = { + .name ="inv-icm42607-i2c" , + .of_match_table = inv_icm42607_of_matches, + }, + .id_table = inv_icm42607_id, + .probe = inv_icm42607_probe, +}; +module_i2c_driver (inv_icm42607_driver); + +MODULE_AUTHOR ("InvenSense, Inc." ); +MODULE_DESCRIPTION ("InvenSense ICM-42607x I2C driver" ); +MODULE_LICENSE ("GPL" ); +MODULE_IMPORT_NS ("IIO_ICM42607" );drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c new file +6
-0@@ -0,0 +1,101 @@ +static const struct of_device_id inv_icm42607_of_matches[] = { + { + .compatible ="invensense,icm42607" , + .data = &inv_icm42607_hw_data, + }, + {
drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c line 83
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c new file +10
-0+ .compatible = "invensense,icm42607p", + .data = &inv_icm42607p_hw_data, + }, + { } +}; +MODULE_DEVICE_TABLE (of, inv_icm42607_of_matches); + +static const struct spi_device_id inv_icm42607_spi_id_table[] = { + {"icm42607" , (kernel_ulong_t)&inv_icm42607_hw_data }, + { "icm42607p", (kernel_ulong_t)&inv_icm42607p_hw_data },
Please use named initializers (see the work Uwe is doing currently to clean this up). It has always been odd that we do it for of_ but not spi_device_id / i2c_device_id.
That work from Uwe crossed with the development of this series but I'd rather avoid an immediate follow up patch if we can just tidy it up from the start. I'd definitely have fixed this whilst applying if there was no other reason for a v9.
Jonathan
Quoted 18 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c new file +18
-0+ { } +}; +MODULE_DEVICE_TABLE (spi, inv_icm42607_spi_id_table); + +static struct spi_driver inv_icm42607_driver = { + .driver = { + .name ="inv-icm42607-spi" , + .of_match_table = inv_icm42607_of_matches, + }, + .id_table = inv_icm42607_spi_id_table, + .probe = inv_icm42607_probe, +}; +module_spi_driver (inv_icm42607_driver); + +MODULE_AUTHOR ("InvenSense, Inc." ); +MODULE_DESCRIPTION ("InvenSense ICM-42607x SPI driver" ); +MODULE_LICENSE ("GPL" ); +MODULE_IMPORT_NS ("IIO_ICM42607" );
PATCH v8 5/10 iio: imu: inv_icm42607: Add PM support for icm42607
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add power management support for the ICM42607 device driver.
--- drivers/iio/imu/inv_icm42607/inv_icm42607.h | 18 +++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 147 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 1 + .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 1 + 4 files changed, 167 insertions(+)
drivers/iio/imu/inv_icm42607/inv_icm42607.h +18 -0
@@ -10,6 +10,7 @@#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/mutex.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h>
@@ -96,24 +97,34 @@ struct inv_icm42607_hw {const struct inv_icm42607_conf *conf; }; +struct inv_icm42607_suspended { +enum inv_icm42607_sensor_mode gyro; +enum inv_icm42607_sensor_mode accel; +bool temp; +}; +/** * struct inv_icm42607_state - driver state variables * @lock: lock for serializing multiple registers access. * @hw: Hardware specific data. * @map: regmap pointer. * @vddio_supply: I/O voltage regulator for the chip. +* @vddio_en: I/O voltage status for runtime PM. * @irq: chip irq, required to enable/disable and set wakeup * @orientation: sensor chip orientation relative to main hardware. * @conf: chip sensors configurations. +* @suspended: suspended sensors configuration. */ struct inv_icm42607_state {struct mutex lock;const struct inv_icm42607_hw *hw;struct regmap *map;struct regulator *vddio_supply; +bool vddio_en;int irq;struct iio_mount_matrix orientation;struct inv_icm42607_conf conf; +struct inv_icm42607_suspended suspended; };/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
@@ -332,11 +343,18 @@ struct inv_icm42607_state {#define INV_ICM42607_GYRO_STARTUP_TIME_MS 30#define INV_ICM42607_TEMP_STARTUP_TIME_MS 77 +/* +* Suspend delay assumed from other icm42600 series device, not +* documented in datasheet. +*/ +#define INV_ICM42607_SUSPEND_DELAY_MS 2000 +typedef int (*inv_icm42607_bus_setup )(struct inv_icm42607_state *);extern const struct regmap_config inv_icm42607_regmap_config;extern const struct inv_icm42607_hw inv_icm42607_hw_data;extern const struct inv_icm42607_hw inv_icm42607p_hw_data; +extern const struct dev_pm_ops inv_icm42607_pm_ops;int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw,inv_icm42607_bus_setup bus_setup);
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +147 -0
188 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c +1 -0
@@ -77,6 +77,7 @@ static struct i2c_driver inv_icm42607_driver = { .driver = { .name = "inv-icm42607-i2c", .of_match_table = inv_icm42607_of_matches, + .pm = pm_ptr(&inv_icm42607_pm_ops), }, .id_table = inv_icm42607_id, .probe = inv_icm42607_probe,
drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c +1 -0
@@ -89,6 +89,7 @@ static struct spi_driver inv_icm42607_driver = { .driver = { .name = "inv-icm42607-spi", .of_match_table = inv_icm42607_of_matches, + .pm = pm_ptr(&inv_icm42607_pm_ops), }, .id_table = inv_icm42607_spi_id_table, .probe = inv_icm42607_probe,
Signature · 1 line
2.43.0
Jonathan Cameron
maintainerRe: [PATCH V8 05/10] iio: imu: inv_icm42607: Add PM support for icm42607
Quoted 5 lines · On Mon, 18 May 2026 15:05:20 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add power management support for the ICM42607 device driver.
Signed-off-by Chris Morgan <[email protected]>
Hi Chris, runtime PM is my current place to look closest for bugs because we've had a lot of them recently.
Anyhow, took another look and here I think we can optimize things a little more.
Quoted 41 lines
--- drivers/iio/imu/inv_icm42607/inv_icm42607.h | 18 +++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 147 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 1 + .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 1 + 4 files changed, 167 insertions(+)drivers/iio/imu/inv_icm42607/inv_icm42607.h +9
-0@@ -10,6 +10,7 @@#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/mutex.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -96,24 +97,34 @@ struct inv_icm42607_hw {const struct inv_icm42607_conf *conf; }; +struct inv_icm42607_suspended { +enum inv_icm42607_sensor_mode gyro; +enum inv_icm42607_sensor_mode accel; +bool temp; +}; +/** * struct inv_icm42607_state - driver state variables * @lock: lock for serializing multiple registers access. * @hw: Hardware specific data. * @map: regmap pointer. * @vddio_supply: I/O voltage regulator for the chip. +* @vddio_en: I/O voltage status for runtime PM. * @irq: chip irq, required to enable/disable and set wakeup * @orientation: sensor chip orientation relative to main hardware. * @conf: chip sensors configurations. +* @suspended: suspended sensors configuration. */
drivers/iio/imu/inv_icm42607/inv_icm42607.h struct inv_icm42607_hw { · line 127
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +2
-0struct inv_icm42607_state {struct mutex lock;const struct inv_icm42607_hw *hw;struct regmap *map;struct regulator *vddio_supply; +bool vddio_en;int irq;struct iio_mount_matrix orientation;struct inv_icm42607_conf conf; +struct inv_icm42607_suspended suspended;
Is this used? If not bring it in only when needed.
Quoted 39 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +0
-0};drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +22
-0@@ -9,6 +9,7 @@#include <linux/irq.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -72,6 +73,62 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = { };EXPORT_SYMBOL_NS_GPL (inv_icm42607p_hw_data,"IIO_ICM42607" ); +static int inv_icm42607_set_pwr_mgmt0 (struct inv_icm42607_state *st, +enum inv_icm42607_sensor_mode gyro, +enum inv_icm42607_sensor_mode accel, +bool temp,unsigned int *sleep_ms) +{ +enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode; +enum inv_icm42607_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 =FIELD_PREP (INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK , gyro); + val |=FIELD_PREP (INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK , 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)
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 106
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+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_ICM42607_TEMP_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_TEMP_STARTUP_TIME_MS ;
sleepval = max(sleepval,)
or just assign it here if not later patches add stuff in between the assignment to 0 and here.
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 109
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+ } +if (accel != oldaccel && oldaccel ==INV_ICM42607_SENSOR_MODE_OFF ) { +usleep_range (200 ,300 );
fsleep() + add a comment on why we are sleeping in here.
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 111
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0+if (sleepval <INV_ICM42607_ACCEL_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_ACCEL_STARTUP_TIME_MS ;
sleepval = max(sleepval, INV...);
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 115
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0+ } +if (gyro != oldgyro) { +if (oldgyro ==INV_ICM42607_SENSOR_MODE_OFF ) { +usleep_range (200 ,300 );
fsleep()
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 117
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0+if (sleepval <INV_ICM42607_GYRO_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_GYRO_STARTUP_TIME_MS ;
I'd use max for these as well.
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +12
-0+ }else if (gyro ==INV_ICM42607_SENSOR_MODE_OFF ) { +if (sleepval <INV_ICM42607_GYRO_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_GYRO_STARTUP_TIME_MS ; + } + } + +if (sleep_ms) + *sleep_ms = sleepval; +else if (sleepval) +msleep (sleepval); + +return 0 ;
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = {
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +8
-0+} +static int inv_icm42607_suspend (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); +
Could you use pm_runtime_force_suspend()?
Quoted 11 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +11
-0+if (pm_runtime_suspended (dev)) +return 0 ; + + ret =inv_icm42607_set_pwr_mgmt0 (st,INV_ICM42607_SENSOR_MODE_OFF , +INV_ICM42607_SENSOR_MODE_OFF , + false,NULL ); +if (ret) +return ret; + +inv_icm42607_disable_vddio_reg (st); +
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 357
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+return 0 ; +} + +static int inv_icm42607_resume (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); +
Given the bunch of stuff we've run into recently around these I'm getting more paranoid.
Similar to above, could you use pm_runtime_force_resume() You would need to gate stuff added later to not occur though if it wasn't runtime suspended.
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +12
-0+if (pm_runtime_suspended (dev)) +return 0 ; + + ret =inv_icm42607_enable_vddio_reg (st); +if (ret) +return ret; + +/* Nothing else to restore at this time. */ + +return 0 ; +} +
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 379
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+static int inv_icm42607_runtime_suspend (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); + + ret =inv_icm42607_set_pwr_mgmt0 (st,INV_ICM42607_SENSOR_MODE_OFF , +INV_ICM42607_SENSOR_MODE_OFF , false, +NULL );
Different alignment to above - aim for consistent choices on this.
Quoted 23 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +23
-0+if (ret) +return ret; + +inv_icm42607_disable_vddio_reg (st); + +return 0 ; +} + +static int inv_icm42607_runtime_resume (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); + +guard (mutex)(&st->lock); + +return inv_icm42607_enable_vddio_reg (st); +} + +EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = { + SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume) +RUNTIME_PM_OPS (inv_icm42607_runtime_suspend, + inv_icm42607_runtime_resume,NULL ) +}; +
Re: [PATCH V8 05/10] iio: imu: inv_icm42607: Add PM support for icm42607
Quoted 113 lines · Jonathan Cameron
Quoted 5 lines · On Mon, 18 May 2026 15:05:20 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add power management support for the ICM42607 device driver.
Signed-off-by Chris Morgan <[email protected]>Hi Chris, runtime PM is my current place to look closest for bugs because we've had a lot of them recently.
Anyhow, took another look and here I think we can optimize things a little more.
Quoted 41 lines
--- drivers/iio/imu/inv_icm42607/inv_icm42607.h | 18 +++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 147 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 1 + .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 1 + 4 files changed, 167 insertions(+)drivers/iio/imu/inv_icm42607/inv_icm42607.h +9
-0@@ -10,6 +10,7 @@#include <linux/bitops.h> #include <linux/iio/iio.h> #include <linux/mutex.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -96,24 +97,34 @@ struct inv_icm42607_hw {const struct inv_icm42607_conf *conf; }; +struct inv_icm42607_suspended { +enum inv_icm42607_sensor_mode gyro; +enum inv_icm42607_sensor_mode accel; +bool temp; +}; +/** * struct inv_icm42607_state - driver state variables * @lock: lock for serializing multiple registers access. * @hw: Hardware specific data. * @map: regmap pointer. * @vddio_supply: I/O voltage regulator for the chip. +* @vddio_en: I/O voltage status for runtime PM. * @irq: chip irq, required to enable/disable and set wakeup * @orientation: sensor chip orientation relative to main hardware. * @conf: chip sensors configurations. +* @suspended: suspended sensors configuration. */ drivers/iio/imu/inv_icm42607/inv_icm42607.h struct inv_icm42607_hw { · line 127
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +2
-0struct inv_icm42607_state {struct mutex lock;const struct inv_icm42607_hw *hw;struct regmap *map;struct regulator *vddio_supply; +bool vddio_en;int irq;struct iio_mount_matrix orientation;struct inv_icm42607_conf conf; +struct inv_icm42607_suspended suspended;Is this used? If not bring it in only when needed.
Quoted 44 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +0
-0};drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +27
-0@@ -9,6 +9,7 @@#include <linux/irq.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -72,6 +73,62 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = { };EXPORT_SYMBOL_NS_GPL (inv_icm42607p_hw_data,"IIO_ICM42607" ); +static int inv_icm42607_set_pwr_mgmt0 (struct inv_icm42607_state *st, +enum inv_icm42607_sensor_mode gyro, +enum inv_icm42607_sensor_mode accel, +bool temp,unsigned int *sleep_ms) +{ +enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode; +enum inv_icm42607_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 =FIELD_PREP (INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK , gyro); + val |=FIELD_PREP (INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK , 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;
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 106
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +5
-0+ + sleepval =0 ; +if (temp && !oldtemp) { +if (sleepval <INV_ICM42607_TEMP_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_TEMP_STARTUP_TIME_MS ;sleepval =
max(sleepval,)
or just assign it here if not later patches add stuff in between the assignment to 0 and here.
I'm going to assign it to 0 here (unless you think I should define it at the beginning as 0) and then tweak as needed. I think this code here can be further optimized, especially if we make the assumption that START and STOP time for each sensor is comparable (the datasheet doesn't say, so I'm going to go with yes since that greatly simplifies things).
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 109
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+ } +if (accel != oldaccel && oldaccel ==INV_ICM42607_SENSOR_MODE_OFF ) { +usleep_range (200 ,300 );
fsleep()+ add a comment on why we are sleeping in here.
Just going to delete these usleep_ranges since 1) I can't find them documented in the datasheet and 2) we sleep later on anyway if this condition is met.
Quoted 56 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 111
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0+if (sleepval <INV_ICM42607_ACCEL_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_ACCEL_STARTUP_TIME_MS ;sleepval = max(sleepval, INV...);drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 115
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0+ } +if (gyro != oldgyro) { +if (oldgyro ==INV_ICM42607_SENSOR_MODE_OFF ) { +usleep_range (200 ,300 );
fsleep()drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 117
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0+if (sleepval <INV_ICM42607_GYRO_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_GYRO_STARTUP_TIME_MS ;I'd use max for these as well.
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +12
-0+ }else if (gyro ==INV_ICM42607_SENSOR_MODE_OFF ) { +if (sleepval <INV_ICM42607_GYRO_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_GYRO_STARTUP_TIME_MS ; + } + } + +if (sleep_ms) + *sleep_ms = sleepval; +else if (sleepval) +msleep (sleepval); + +return 0 ;drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = {
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +8
-0+} +static int inv_icm42607_suspend (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); +Could you use
pm_runtime_force_suspend()?Quoted 18 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +18
-0+if (pm_runtime_suspended (dev)) +return 0 ; + + ret =inv_icm42607_set_pwr_mgmt0 (st,INV_ICM42607_SENSOR_MODE_OFF , +INV_ICM42607_SENSOR_MODE_OFF , + false,NULL ); +if (ret) +return ret; + +inv_icm42607_disable_vddio_reg (st); + +return 0 ; +} + +static int inv_icm42607_resume (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret;
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 336
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+ +guard (mutex)(&st->lock); +Given the bunch of stuff we've run into recently around these I'm getting more paranoid.
Similar to above, could you usepm_runtime_force_resume()You would need to gate stuff added later to not occur though if it wasn't runtime suspended.
This I'm having trouble understanding. If I use pm_force_runtime_resume() I'm assuming that either I got an error (in which case I'd return the error) or the device is runtime resumed after the call completes. If that's the case, wouldn't my suspend and resume steps just be pm_force_runtime_suspend/resume, and enabling the regulator (first for resume) or disabling the regulator (last for suspend) as needed?
Quoted 41 lines
Quoted 14 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +12
-0+if (pm_runtime_suspended (dev)) +return 0 ; + + ret =inv_icm42607_enable_vddio_reg (st); +if (ret) +return ret; + +/* Nothing else to restore at this time. */ + +return 0 ; +} +drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 379
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+static int inv_icm42607_runtime_suspend (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); + + ret =inv_icm42607_set_pwr_mgmt0 (st,INV_ICM42607_SENSOR_MODE_OFF , +INV_ICM42607_SENSOR_MODE_OFF , false, +NULL );Different alignment to above - aim for consistent choices on this.
Quoted 15 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +15
-0+if (ret) +return ret; + +inv_icm42607_disable_vddio_reg (st); + +return 0 ; +} + +static int inv_icm42607_runtime_resume (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); + +guard (mutex)(&st->lock); + +return inv_icm42607_enable_vddio_reg (st);
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 402
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +8
-0+} + +EXPORT_NS_GPL_DEV_PM_OPS(inv_icm42607_pm_ops, IIO_ICM42607) = { + SYSTEM_SLEEP_PM_OPS(inv_icm42607_suspend, inv_icm42607_resume) +RUNTIME_PM_OPS (inv_icm42607_runtime_suspend, + inv_icm42607_runtime_resume,NULL ) +}; +
Thank you,
Chris
Jonathan Cameron
maintainerRe: [PATCH V8 05/10] iio: imu: inv_icm42607: Add PM support for icm42607
Quoted 44 lines
Quoted 44 lines
Quoted 44 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +27
-0@@ -9,6 +9,7 @@#include <linux/irq.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -72,6 +73,62 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = { };EXPORT_SYMBOL_NS_GPL (inv_icm42607p_hw_data,"IIO_ICM42607" ); +static int inv_icm42607_set_pwr_mgmt0 (struct inv_icm42607_state *st, +enum inv_icm42607_sensor_mode gyro, +enum inv_icm42607_sensor_mode accel, +bool temp,unsigned int *sleep_ms) +{ +enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode; +enum inv_icm42607_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 =FIELD_PREP (INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK , gyro); + val |=FIELD_PREP (INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK , 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;
Quoted 8 lines
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 106
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +5
-0+ + sleepval =0 ; +if (temp && !oldtemp) { +if (sleepval <INV_ICM42607_TEMP_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_TEMP_STARTUP_TIME_MS ;sleepval =
max(sleepval,)
or just assign it here if not later patches add stuff in between the assignment to 0 and here.
Wow I write some garbage English sometimes (no excuse, it is my native language!)
Quoted 7 lines
I'm going to assign it to 0 here (unless you think I should define it at the beginning as 0) and then tweak as needed. I think this code here can be further optimized, especially if we make the assumption that START and STOP time for each sensor is comparable (the datasheet doesn't say, so I'm going to go with yes since that greatly simplifies things).
I'm a bit lost. Suggestion was just to do
sleepval = INV_ICM42607_TEMP_STARTUP_TIME_MS;
as we know it is 0. Probably not worth it though as ends up with fragile
code. Fine to keep it to what you have but use max() rather than if()
...
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0+static int inv_icm42607_resume (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret;Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 336
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+ +guard (mutex)(&st->lock); +Given the bunch of stuff we've run into recently around these I'm getting more paranoid.
Similar to above, could you usepm_runtime_force_resume()You would need to gate stuff added later to not occur though if it wasn't runtime suspended.
Quoted 7 lines
This I'm having trouble understanding. If I use
pm_force_runtime_resume()I'm assuming that either I got an error (in which case I'd return the error) or the device is runtime resumed after the call completes. If that's the case, wouldn't my suspend and resume steps just be pm_force_runtime_suspend/resume, and enabling the regulator (first for resume) or disabling the regulator (last for suspend) as needed?
If you call pm_runtime_force_resume() it will do the right thing wrt to runtime PM state prior to suspend. If it wasn't runtime suspended it will runtime resume - if it was it'll no do anything. It won't directly tell you which one it did though.
The extra stuff that you know can't be the case if runtime pm is on will need some sort of gating. However, looking again it may already be protected by more specific checks.
pm_runtime_force_resume();
if (st->fifo.on) { //I'd failed to look at what was added.
ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1,
INV_ICM42607_FIFO_CONFIG1_MODE);
if (ret)
return ret;
}That if (st->fifo.on) previously didn't get checked if we were runtime suspended because in fifo mode we never are. So I was thinking you'd need that check to be
if (!pm_runtime_suspended(dev) && st->fifo.on)
but the fifo.on check is sufficient by the same argument that if fifo.on is true we aren't in runtime suspend.
Basically I overthought it and didn't check what got added where the comment is in this patch.
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +11
-0+if (pm_runtime_suspended (dev)) +return 0 ; + + ret =inv_icm42607_enable_vddio_reg (st); +if (ret) +return ret; + +/* Nothing else to restore at this time. */ + +return 0 ; +}
Re: [PATCH V8 05/10] iio: imu: inv_icm42607: Add PM support for icm42607
Quoted 113 lines · Jonathan Cameron
Quoted 44 lines
Quoted 44 lines
Quoted 44 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +27
-0@@ -9,6 +9,7 @@#include <linux/irq.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -72,6 +73,62 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = { };EXPORT_SYMBOL_NS_GPL (inv_icm42607p_hw_data,"IIO_ICM42607" ); +static int inv_icm42607_set_pwr_mgmt0 (struct inv_icm42607_state *st, +enum inv_icm42607_sensor_mode gyro, +enum inv_icm42607_sensor_mode accel, +bool temp,unsigned int *sleep_ms) +{ +enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode; +enum inv_icm42607_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 =FIELD_PREP (INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK , gyro); + val |=FIELD_PREP (INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK , 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;Quoted 8 lines
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 106
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +5
-0+ + sleepval =0 ; +if (temp && !oldtemp) { +if (sleepval <INV_ICM42607_TEMP_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_TEMP_STARTUP_TIME_MS ;sleepval =
max(sleepval,)
or just assign it here if not later patches add stuff in between the assignment to 0 and here.Wow I write some garbage English sometimes (no excuse, it is my native language!)
Quoted 7 lines
I'm going to assign it to 0 here (unless you think I should define it at the beginning as 0) and then tweak as needed. I think this code here can be further optimized, especially if we make the assumption that START and STOP time for each sensor is comparable (the datasheet doesn't say, so I'm going to go with yes since that greatly simplifies things).
I'm a bit lost. Suggestion was just to do
sleepval = INV_ICM42607_TEMP_STARTUP_TIME_MS;as we know it is 0. Probably not worth it though as ends up with fragile
code. Fine to keep it to what you have but usemax()rather thanif()...
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0+static int inv_icm42607_resume (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret;Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 336
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+ +guard (mutex)(&st->lock); +Given the bunch of stuff we've run into recently around these I'm getting more paranoid.
Similar to above, could you usepm_runtime_force_resume()You would need to gate stuff added later to not occur though if it wasn't runtime suspended.Quoted 7 lines
This I'm having trouble understanding. If I use
pm_force_runtime_resume()I'm assuming that either I got an error (in which case I'd return the error) or the device is runtime resumed after the call completes. If that's the case, wouldn't my suspend and resume steps just be pm_force_runtime_suspend/resume, and enabling the regulator (first for resume) or disabling the regulator (last for suspend) as needed?If you call
pm_runtime_force_resume()it will do the right thing wrt to runtime PM state prior to suspend. If it wasn't runtime suspended it will runtime resume - if it was it'll no do anything. It won't directly tell you which one it did though.The extra stuff that you know can't be the case if runtime pm is on will need some sort of gating. However, looking again it may already be protected by more specific checks.
pm_runtime_force_resume(); if (st->fifo.on) { //I'd failed to look at what was added. ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, INV_ICM42607_FIFO_CONFIG1_MODE); if (ret) return ret; }That if (
st->fifo.on) previously didn't get checked if we were runtime suspended because in fifo mode we never are. So I was thinking you'd need that check to be
Quoted 6 lines
if (!pm_runtime_suspended(dev) && st->fifo.on)but the fifo.on check is sufficient by the same argument that if fifo.on is true we aren't in runtime suspend.
Basically I overthought it and didn't check what got added where the comment is in this patch.
I'm still lost here... are you saying the existing logic is sufficient or that we need to do something more (like force the runtime resume/suspend in different places).
Thank you again for all of your help, you've been amazing.
Chris
Quoted 17 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +11
-0+if (pm_runtime_suspended (dev)) +return 0 ; + + ret =inv_icm42607_enable_vddio_reg (st); +if (ret) +return ret; + +/* Nothing else to restore at this time. */ + +return 0 ; +}
Jonathan Cameron
maintainerRe: [PATCH V8 05/10] iio: imu: inv_icm42607: Add PM support for icm42607
Quoted 118 lines · On Fri, 22 May 2026 11:23:59 -0500 Chris Morgan <[email protected]> wrote:
Quoted 117 lines · Jonathan Cameron
Quoted 44 lines
Quoted 44 lines
Quoted 44 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +27
-0@@ -9,6 +9,7 @@#include <linux/irq.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/pm_runtime.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> @@ -72,6 +73,62 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = { };EXPORT_SYMBOL_NS_GPL (inv_icm42607p_hw_data,"IIO_ICM42607" ); +static int inv_icm42607_set_pwr_mgmt0 (struct inv_icm42607_state *st, +enum inv_icm42607_sensor_mode gyro, +enum inv_icm42607_sensor_mode accel, +bool temp,unsigned int *sleep_ms) +{ +enum inv_icm42607_sensor_mode oldgyro = st->conf.gyro.mode; +enum inv_icm42607_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 =FIELD_PREP (INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK , gyro); + val |=FIELD_PREP (INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK , 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;Quoted 8 lines
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 106
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +5
-0+ + sleepval =0 ; +if (temp && !oldtemp) { +if (sleepval <INV_ICM42607_TEMP_STARTUP_TIME_MS ) + sleepval =INV_ICM42607_TEMP_STARTUP_TIME_MS ;sleepval =
max(sleepval,)
or just assign it here if not later patches add stuff in between the assignment to 0 and here.Wow I write some garbage English sometimes (no excuse, it is my native language!)
Quoted 7 lines
I'm going to assign it to 0 here (unless you think I should define it at the beginning as 0) and then tweak as needed. I think this code here can be further optimized, especially if we make the assumption that START and STOP time for each sensor is comparable (the datasheet doesn't say, so I'm going to go with yes since that greatly simplifies things).
I'm a bit lost. Suggestion was just to do
sleepval = INV_ICM42607_TEMP_STARTUP_TIME_MS;as we know it is 0. Probably not worth it though as ends up with fragile
code. Fine to keep it to what you have but usemax()rather thanif()...
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0+static int inv_icm42607_resume (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret;Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 336
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+ +guard (mutex)(&st->lock); +Given the bunch of stuff we've run into recently around these I'm getting more paranoid.
Similar to above, could you usepm_runtime_force_resume()You would need to gate stuff added later to not occur though if it wasn't runtime suspended.Quoted 7 lines
This I'm having trouble understanding. If I use
pm_force_runtime_resume()I'm assuming that either I got an error (in which case I'd return the error) or the device is runtime resumed after the call completes. If that's the case, wouldn't my suspend and resume steps just be pm_force_runtime_suspend/resume, and enabling the regulator (first for resume) or disabling the regulator (last for suspend) as needed?If you call
pm_runtime_force_resume()it will do the right thing wrt to runtime PM state prior to suspend. If it wasn't runtime suspended it will runtime resume - if it was it'll no do anything. It won't directly tell you which one it did though.The extra stuff that you know can't be the case if runtime pm is on will need some sort of gating. However, looking again it may already be protected by more specific checks.
pm_runtime_force_resume(); if (st->fifo.on) { //I'd failed to look at what was added. ret = regmap_write(st->map, INV_ICM42607_REG_FIFO_CONFIG1, INV_ICM42607_FIFO_CONFIG1_MODE); if (ret) return ret; }That if (
st->fifo.on) previously didn't get checked if we were runtime suspended because in fifo mode we never are. So I was thinking you'd need that check to beif (!pm_runtime_suspended(dev) && st->fifo.on)but the fifo.on check is sufficient by the same argument that if fifo.on is true we aren't in runtime suspend.
Quoted 6 lines
Quoted 2 lines
Basically I overthought it and didn't check what got added where the comment is in this patch.
I'm still lost here... are you saying the existing logic is sufficient or that we need to do something more (like force the runtime resume/suspend in different places).
I'm saying you should call pm_runtime_force_resume() in the resume() callback and the equivalent in the suspend() callback + call anything extra that is done in those callbacks in appropriate order.
My original thought that some of the 'extra' stuff not covered by pm_runtime_force...() would need extra gating but I think what you have there is effectively the same via checks that happen to align with the runtime resume / suspend states.
Jonathan
Quoted 22 lines
Thank you again for all of your help, you've been amazing.
Chris
Quoted 17 lines
Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +11
-0+if (pm_runtime_suspended (dev)) +return 0 ; + + ret =inv_icm42607_enable_vddio_reg (st); +if (ret) +return ret; + +/* Nothing else to restore at this time. */ + +return 0 ; +}
PATCH v8 6/10 iio: imu: inv_icm42607: Add Buffer support for icm42607
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add all FIFO parsing and reading functions to support inv_icm42607 hardware.
--- drivers/iio/imu/inv_icm42607/Makefile | 1 + drivers/iio/imu/inv_icm42607/inv_icm42607.h | 26 + .../imu/inv_icm42607/inv_icm42607_buffer.c | 482 ++++++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.h | 93 ++++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 52 +- 5 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h
drivers/iio/imu/inv_icm42607/Makefile +1 -0
@@ -2,6 +2,7 @@ obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o inv-icm42607-y += inv_icm42607_core.o +inv-icm42607-y += inv_icm42607_buffer.o obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o inv-icm42607-i2c-y += inv_icm42607_i2c.o
drivers/iio/imu/inv_icm42607/inv_icm42607.h +26 -0
@@ -14,6 +14,10 @@#include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/iio/common/inv_sensors_timestamp.h> + +#include "inv_icm42607_buffer.h" +/* serial bus slew rates */ enum inv_icm42607_slew_rate {INV_ICM42607_SLEW_RATE_20_60NS ,
@@ -114,6 +118,10 @@ struct inv_icm42607_suspended {* @orientation: sensor chip orientation relative to main hardware. * @conf: chip sensors configurations. * @suspended: suspended sensors configuration. +* @indio_gyro: gyroscope IIO device. +* @indio_accel: accelerometer IIO device. +* @fifo: FIFO management structure. +* @buffer: data transfer buffer aligned for DMA. */ struct inv_icm42607_state {struct mutex lock;
@@ -125,6 +133,22 @@ struct inv_icm42607_state {struct iio_mount_matrix orientation;struct inv_icm42607_conf conf;struct inv_icm42607_suspended suspended; +struct iio_dev *indio_gyro; +struct iio_dev *indio_accel; +struct inv_icm42607_fifo fifo; +__be16 buffer[3 ]__aligned(IIO_DMA_MINALIGN) ; +}; + +/** +* struct inv_icm42607_sensor_state - sensor state variables +* @power_mode: sensor requested power mode (for common frequencies) +* @filter: sensor filter. +* @ts: timestamp module states. +*/ +struct inv_icm42607_sensor_state { +enum inv_icm42607_sensor_mode power_mode; +int filter; +struct inv_sensors_timestamp ts; };/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
@@ -356,6 +380,8 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;extern const struct inv_icm42607_hw inv_icm42607p_hw_data;extern const struct dev_pm_ops inv_icm42607_pm_ops; +u32 inv_icm42607_odr_to_period (enum inv_icm42607_odr odr); +int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw,inv_icm42607_bus_setup bus_setup);
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +482 -0
482 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +93 -0
93 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +51 -1
82 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V8 06/10] iio: imu: inv_icm42607: Add Buffer support for icm42607
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] inv_icm42607_buffer_set_fifo_en() writes an invalid state to the FIFO mode register when disabling…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] inv_icm42607_buffer_set_fifo_en() writes an invalid state to the FIFO mode register when disabling the last sensor, clobbering the bypass mode.
- [High] Unaligned memory accesses when dereferencing packed struct members trigger kernel panics on strict-alignment architectures.
- [Medium] Teardown state variables are not unconditionally cleared on error paths, causing permanent buffer desynchronization. --
commit 741f353925a2f661ebf37513ef1196056f86f563
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add Buffer support for icm42607
This commit adds FIFO parsing and reading functions to support the buffer in the inv_icm42607 driver.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +0
-0
[ ... ]
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +5
-0+struct inv_icm42607_fifo_1sensor_packet { +u8 header; +struct inv_icm42607_fifo_sensor_data data; +s8 temp; +} __packed;
[ ... ]
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +5
-0+ssize_t inv_icm42607_fifo_decode_packet (const void *packet,const void **accel, +const void **gyro,const int8_t **temp, +const void **timestamp) +{ +const struct inv_icm42607_fifo_1sensor_packet *pack1 = packet;
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 70
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +3
-0+/* accel only */ +if (header &INV_ICM42607_FIFO_HEADER_ACCEL ) { + *accel = &pack1->data;
Could this pointer assignment lead to an alignment fault on strict-alignment architectures?
Because struct inv_icm42607_fifo_1sensor_packet is marked __packed and starts with a u8, the data member sits at an odd byte offset. This unaligned address is assigned to accel, which is later passed to inv_icm42607_fifo_is_data_valid() where it expects a naturally aligned struct inv_icm42607_fifo_sensor_data pointer.
Dereferencing this pointer could trigger kernel panics on architectures that strictly enforce alignment.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +5
-0+ *gyro =NULL ; + *temp = &pack1->temp; + *timestamp =NULL ; +return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ; + }
[ ... ]
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +6
-0+int inv_icm42607_buffer_set_fifo_en (struct inv_icm42607_state *st, +unsigned int fifo_en) +{ +unsigned int val; +int ret; +
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 122
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+/* update FIFO EN bits for accel and gyro */ + val =0 ; +if (fifo_en &INV_ICM42607_SENSOR_GYRO ) + val |=INV_ICM42607_FIFO_CONFIG1_MODE ; +if (fifo_en &INV_ICM42607_SENSOR_ACCEL ) + val |=INV_ICM42607_FIFO_CONFIG1_MODE ; +if (fifo_en &INV_ICM42607_SENSOR_TEMP ) + val |=INV_ICM42607_FIFO_CONFIG1_MODE ; + + ret =regmap_write (st->map,INV_ICM42607_REG_FIFO_CONFIG1 , val);
Could this write an invalid state when disabling the last sensor?
If fifo_en is 0, val evaluates to 0 and is directly written to the FIFO mode register. However, the correct disabled state for this register appears to be INV_ICM42607_FIFO_CONFIG1_BYPASS.
Writing 0 might overwrite the bypass mode and leave the FIFO in an unspecified state. It also looks like INV_ICM42607_FIFO_CONFIG1_MODE is redundantly ORed multiple times for each active sensor.
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +8
-0+if (ret) +return ret; + + st->fifo.en = fifo_en; +inv_icm42607_buffer_update_fifo_period (st); + +return 0 ; +}
[ ... ]
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +7
-0+static int inv_icm42607_buffer_predisable (struct iio_dev *indio_dev) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +int ret; + +guard (mutex)(&st->lock); +
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 322
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+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;
Could returning early here leave the driver state permanently desynchronized?
If this or the subsequent operations fail, the function returns early and st->fifo.on is never reset to 0. Since the IIO core ignores teardown errors and considers the buffer disabled anyway, a subsequent call to inv_icm42607_buffer_postenable() will see st->fifo.on > 0, assume the hardware is already fully initialized, and skip programming the hardware.
This would leave the hardware permanently disabled while the software thinks it is streaming, leading to silent data loss.
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +6
-0+ +/* 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;
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Jonathan Cameron
maintainerRe: [PATCH V8 06/10] iio: imu: inv_icm42607: Add Buffer support for icm42607
In reply to Chris MorganQuoted 6 lines · On Mon, 18 May 2026 15:05:21 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add all FIFO parsing and reading functions to support
inv_icm42607hardware.Signed-off-by Chris Morgan <[email protected]>
https://sashiko.dev/#/patchset/20260518200526.458421-1-macroalpha82%40gmail.com
Is unhappy. I haven't checked closely though - might be wrong.
Quoted 27 lines
---
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +19
-0@@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Copyright (C) 2026 InvenSense, Inc. +*/ + +#include <linux/delay.h> +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/minmax.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +#include <linux/iio/common/inv_sensors_timestamp.h> + +#include "inv_icm42607.h" +#include "inv_icm42607_buffer.h" + +/* FIFO header: 1 byte */
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 29
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+#define INV_ICM42607_FIFO_HEADER_MSG BIT(7) +#define INV_ICM42607_FIFO_HEADER_ACCEL BIT(6) +#define INV_ICM42607_FIFO_HEADER_GYRO BIT(5) +#define INV_ICM42607_FIFO_HEADER_TMST_FSYNC GENMASK(3, 2) +#define INV_ICM42607_FIFO_HEADER_ODR_ACCEL BIT(1) +#define INV_ICM42607_FIFO_HEADER_ODR_GYRO BIT(0) + +struct inv_icm42607_fifo_1sensor_packet { +u8 header; +struct inv_icm42607_fifo_sensor_data data;
One of the things sashiko doesn't like is pointers to unaligned structures. I'm not sure what architectures we have that really don't like these still but it is correct that they can be a problem.
Ultimately you need to use unaligned accessors
Quoted 16 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +14
-0+s8 temp; +} __packed; + +struct inv_icm42607_fifo_2sensors_packet { +u8 header; +struct inv_icm42607_fifo_sensor_data accel; +struct inv_icm42607_fifo_sensor_data gyro; +s8 temp; +__be16 timestamp; +} __packed; +int inv_icm42607_buffer_set_fifo_en (struct inv_icm42607_state *st, +unsigned int fifo_en) +{ +unsigned int val;
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+int ret; + +/* update FIFO EN bits for accel and gyro */ + val =0 ; +if (fifo_en &INV_ICM42607_SENSOR_GYRO ) + val |=INV_ICM42607_FIFO_CONFIG1_MODE ; +if (fifo_en &INV_ICM42607_SENSOR_ACCEL ) + val |=INV_ICM42607_FIFO_CONFIG1_MODE ; +if (fifo_en &INV_ICM42607_SENSOR_TEMP ) + val |=INV_ICM42607_FIFO_CONFIG1_MODE ;
Odd to see these all set same bit like this. Why not something that will stop confusing sashiko (and me ;) because it explicitly sets teh value only once.
if (fifo_en & (INV_ICM42607_SENSOR_GYRO | INV_ICM42607_SENSOR_ACCEL | INV_ICM42607_SENSOR_TEMP)) val = INV_...
Quoted 65 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +64
-0+ + 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 ; +} + +/** +* inv_icm42607_buffer_update_watermark - update watermark FIFO threshold +* @st: driver internal state +* +* Returns 0 on success, a negative error code otherwise. +*/ +int inv_icm42607_buffer_update_watermark (struct inv_icm42607_state *st) +{ +const struct device *dev =regmap_get_device (st->map); +unsigned int wm_gyro, wm_accel, watermark; +u32 latency_gyro, latency_accel, latency; +u32 period_gyro, period_accel; +size_t packet_size, wm_size; +__le16 raw_wm; +bool restore; +int ret; + + packet_size =inv_icm42607_get_packet_size (st->fifo.en); + +/* compute sensors latency, depending on sensor watermark and odr */ + wm_gyro =inv_icm42607_wm_truncate (st->fifo.watermark.gyro, packet_size); + wm_accel =inv_icm42607_wm_truncate (st->fifo.watermark.accel, packet_size); +/* use us for odr to avoid overflow using 32 bits values */ + period_gyro =inv_icm42607_odr_to_period (st->conf.gyro.odr) /1000UL ; + period_accel =inv_icm42607_odr_to_period (st->conf.accel.odr) /1000UL ; + latency_gyro = period_gyro * wm_gyro; + latency_accel = period_accel * wm_accel; + +/* 0 value for watermark means that the sensor is turned off */ +if (wm_gyro ==0 && wm_accel ==0 ) +return 0 ; + +if (latency_gyro ==0 ) { + watermark = wm_accel; + st->fifo.watermark.eff_accel = wm_accel; + }else if (latency_accel ==0 ) { + watermark = wm_gyro; + st->fifo.watermark.eff_gyro = wm_gyro; + }else { +/* compute the smallest latency that is a multiple of both */ +if (latency_gyro <= latency_accel) + latency = latency_gyro - (latency_accel % latency_gyro); +else + latency = latency_accel - (latency_gyro % latency_accel); +/* all this works because periods are multiple of each others */ + watermark = latency /min (period_gyro, period_accel); + watermark =max (watermark,1 ); +/* update effective watermark */ + st->fifo.watermark.eff_gyro =max (latency / period_gyro,1 ); + st->fifo.watermark.eff_accel =max (latency / period_accel,1 ); + } + +/* changing FIFO watermark requires to turn off watermark interrupt */
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 218
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+ ret =regmap_update_bits_check (st->map,INV_ICM42607_REG_INT_SOURCE0 , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN , +0 , &restore); +if (ret) +return ret; + +/* compute watermark value in bytes */ + wm_size = watermark * packet_size; + raw_wm =INV_ICM42607_FIFO_WATERMARK_VAL (wm_size); +memcpy (st->buffer, &raw_wm,sizeof (raw_wm));
Shout a bit (comment) about this being le vs the be buffer.
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 226
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +8
-0+ ret =regmap_bulk_write (st->map,INV_ICM42607_REG_FIFO_CONFIG2 , + st->buffer,sizeof (raw_wm)); +if (ret) { +dev_err (dev,"Unable to change watermark value: %d\n" , ret); +if (restore) +regmap_update_bits (st->map,INV_ICM42607_REG_INT_SOURCE0 , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN );
regmap_set_bits()
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 234
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +8
-0+return ret; + } + +/* restore watermark interrupt */ +if (restore) { + ret =regmap_update_bits (st->map,INV_ICM42607_REG_INT_SOURCE0 , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN );
regmap_set_bits()
Quoted 25 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +23
-0+if (ret) +return ret; + } + +return 0 ; +} +int inv_icm42607_buffer_fifo_read (struct inv_icm42607_state *st, +unsigned int max) +{ +const void *accel, *gyro, *timestamp; +size_t i, max_count; +const s8 *temp; +ssize_t size; +int ret; + +guard (mutex)(&st->lock); + +/* reset all samples counters */ + st->fifo.count =0 ; + st->fifo.nb.gyro =0 ; + st->fifo.nb.accel =0 ; + st->fifo.nb.total =0 ; +
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 419
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+/* compute maximum FIFO read size */ +if (max ==0 ) + max_count =sizeof (st->fifo.data); +else + max_count =min ((max *inv_icm42607_get_packet_size (st->fifo.en)), +sizeof (st->fifo.data)); + +/* read FIFO count value */ + ret =regmap_bulk_read (st->map,INV_ICM42607_REG_FIFO_COUNTH , + st->buffer,sizeof (u8) *2 );
Given buffer is an array of __be16, use size of buffer[0] to say you want to read one value.
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 422
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +3
-0+if (ret) +return ret; + st->fifo.count =be16_to_cpup (st->buffer);
whilst it is the same thing we can use the easier to read
st->fifo.count = be16_to_cpu(st->buffer[0]);
again making it clear this is just using one __be16 from the array.
Quoted 91 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +32
-0+ +/* check and clamp FIFO count value */ +if (st->fifo.count ==0 ) +return 0 ; + + st->fifo.count =min (st->fifo.count, max_count); + +/* read all FIFO data in internal buffer */ + ret =regmap_noinc_read (st->map,INV_ICM42607_REG_FIFO_DATA , + st->fifo.data, st->fifo.count); +if (ret) +return ret; + +/* compute number of samples for each sensor */ +for (i =0 ; i < st->fifo.count; i += size) { + size =inv_icm42607_fifo_decode_packet (&st->fifo.data[i], + &accel, &gyro, &temp, ×tamp); +/* Make sure the size is at least 1 valid packet. */ +if (size <INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ) +break ; +/* Error if we are going to overflow the buffer. */ +if (i + size > st->fifo.count) +return -EIO ; +if (gyro !=NULL &&inv_icm42607_fifo_is_data_valid (gyro)) + st->fifo.nb.gyro++; +if (accel !=NULL &&inv_icm42607_fifo_is_data_valid (accel)) + st->fifo.nb.accel++; + st->fifo.nb.total++; + } + +return 0 ; +}drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +52
-0@@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* +* Copyright (C) 2026 InvenSense, Inc. +*/ + +#ifndef INV_ICM42607_BUFFER_H_ +#define INV_ICM42607_BUFFER_H_ + +#include <linux/bitops.h> + +struct inv_icm42607_state ; + +#define INV_ICM42607_SENSOR_GYRO BIT(0) +#define INV_ICM42607_SENSOR_ACCEL BIT(1) +#define INV_ICM42607_SENSOR_TEMP BIT(2) + +/** +* struct inv_icm42607_fifo - FIFO state variables +* @on: reference counter for FIFO on. +* @en: bits field of INV_ICM42607_SENSOR_* for FIFO EN bits. +* @period: FIFO internal period. +* @watermark: watermark configuration values for accel and gyro. +* @count: number of bytes in the FIFO data buffer. +* @nb: gyro, accel and total samples in the FIFO data buffer. +* @data: FIFO data buffer aligned for DMA (2kB + 32 bytes of read cache). +*/ +struct inv_icm42607_fifo { +unsigned int on; +unsigned int en; +u32 period; +struct { +unsigned int gyro; +unsigned int accel; +unsigned int eff_gyro; +unsigned int eff_accel; + } watermark; +size_t count; +struct { +size_t gyro; +size_t accel; +size_t total; + } nb; +u8 data[2080 ]__aligned(IIO_DMA_MINALIGN) ; +}; + +/* FIFO data packet */ +struct inv_icm42607_fifo_sensor_data { +__be16 x; +__be16 y; +__be16 z; +}; +
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h line 62
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +10
-0+#define INV_ICM42607_FIFO_DATA_INVALID -32768 + +static inline bool +inv_icm42607_fifo_is_data_valid (const struct inv_icm42607_fifo_sensor_data *s) +{ +s16 x, y, z; + + x =be16_to_cpu (s->x); + y =be16_to_cpu (s->y); + z =be16_to_cpu (s->z);
The input structure is unaligned and I think so are these so you need get_unaligned_be16()
Quoted 44 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +31
-0+ +if (x ==INV_ICM42607_FIFO_DATA_INVALID && + y ==INV_ICM42607_FIFO_DATA_INVALID && + z ==INV_ICM42607_FIFO_DATA_INVALID ) +return false; + + return true; +} + +ssize_t inv_icm42607_fifo_decode_packet (const void *packet,const void **accel, +const void **gyro,const s8 **temp, +const void **timestamp); + +extern const struct iio_buffer_setup_ops inv_icm42607_buffer_ops; + +int inv_icm42607_buffer_init (struct inv_icm42607_state *st); + +void inv_icm42607_buffer_update_fifo_period (struct inv_icm42607_state *st); + +int inv_icm42607_buffer_set_fifo_en (struct inv_icm42607_state *st, +unsigned int fifo_en); + +int inv_icm42607_buffer_update_watermark (struct inv_icm42607_state *st); + +int inv_icm42607_buffer_fifo_read (struct inv_icm42607_state *st, +unsigned int max); + +int inv_icm42607_buffer_hwfifo_flush (struct inv_icm42607_state *st, +unsigned int count); + +#endif drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +1
-0@@ -15,6 +15,7 @@#include <linux/regulator/consumer.h> #include "inv_icm42607.h" +#include "inv_icm42607_buffer.h" static bool inv_icm42607_is_volatile_reg (struct device *dev,unsigned int reg) {
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 80
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0@@ -73,6 +74,38 @@ const struct inv_icm42607_hw inv_icm42607p_hw_data = { };EXPORT_SYMBOL_NS_GPL (inv_icm42607p_hw_data,"IIO_ICM42607" ); +u32 inv_icm42607_odr_to_period (enum inv_icm42607_odr odr) +{ +static const u32 odr_periods[INV_ICM42607_ODR_NB ] = { +/* 1600Hz */
No need for comment as it's now obvious
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c const struct inv_icm42607_hw inv_icm42607p_hw_data = { · line 82
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0+ [INV_ICM42607_ODR_1600HZ] = 625000, +/* 800Hz */
Do [] = assignment for all of them and drop all the comments as they will be unneeded.
Quoted 27 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +26
-0+1250000 , +/* 400Hz */ +2500000 , +/* 200Hz */ +5000000 , +/* 100 Hz */ +10000000 , +/* 50Hz */ +20000000 , +/* 25Hz */ +40000000 , +/* 12.5Hz */ +80000000 , +/* 6.25Hz */ +160000000 , +/* 3.125Hz */ +320000000 , +/* 1.5625Hz */ +640000000 , + }; + + odr =clamp (odr,INV_ICM42607_ODR_1600HZ ,INV_ICM42607_ODR_1_5625HZ_LP ); + +return odr_periods[odr]; +} +
PATCH v8 7/10 iio: imu: inv_icm42607: Add Temp Support in icm42607
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add functions for reading temperature sensor data.
--- drivers/iio/imu/inv_icm42607/Makefile | 1 + drivers/iio/imu/inv_icm42607/inv_icm42607.h | 3 + .../iio/imu/inv_icm42607/inv_icm42607_core.c | 18 +++++ .../iio/imu/inv_icm42607/inv_icm42607_temp.c | 80 +++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_temp.h | 33 ++++++++ 5 files changed, 135 insertions(+) create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h
drivers/iio/imu/inv_icm42607/Makefile +1 -0
@@ -3,6 +3,7 @@ obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o inv-icm42607-y += inv_icm42607_core.o inv-icm42607-y += inv_icm42607_buffer.o +inv-icm42607-y += inv_icm42607_temp.o obj-$(CONFIG_INV_ICM42607_I2C) += inv-icm42607-i2c.o inv-icm42607-i2c-y += inv_icm42607_i2c.o
drivers/iio/imu/inv_icm42607/inv_icm42607.h +3 -0
@@ -382,6 +382,9 @@ extern const struct dev_pm_ops inv_icm42607_pm_ops;u32 inv_icm42607_odr_to_period (enum inv_icm42607_odr odr); +int inv_icm42607_set_temp_conf (struct inv_icm42607_state *st,bool enable, +unsigned int *sleep_ms); +int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw,inv_icm42607_bus_setup bus_setup);
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +18 -0
@@ -162,6 +162,24 @@ static int inv_icm42607_set_pwr_mgmt0(struct inv_icm42607_state *st,return 0 ; } +int inv_icm42607_set_temp_conf (struct inv_icm42607_state *st,bool enable, +unsigned int *sleep_ms) +{ +unsigned int val; +int ret; + + val =FIELD_PREP (INV_ICM42607_TEMP_CONFIG0_FILTER_MASK , +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); +} +static int inv_icm42607_set_conf (struct inv_icm42607_state *st,const struct inv_icm42607_conf *conf) {
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +80 -0
80 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.h new file +33 -0
@@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* +* Copyright (C) 2026 InvenSense, Inc. +*/ + +#ifndef INV_ICM42607_TEMP_H_ +#define INV_ICM42607_TEMP_H_ + +#include <linux/bitops.h> + +struct iio_dev ; +struct iio_chan_spec ; + +#define INV_ICM42607_TEMP_CHAN (_index) \ +{ \ + .type = IIO_TEMP, \ + .info_mask_separate = \ + BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + }, \ +} + +int inv_icm42607_temp_read_raw (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +int *val,int *val2,long mask); + +#endif
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V8 07/10] iio: imu: inv_icm42607: Add Temp Support in icm42607
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] The temperature sensor is left enabled indefinitely after a single read, causing a power leak…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The temperature sensor is left enabled indefinitely after a single read, causing a power leak and preventing low-power modes.
- [Medium] The true Runtime PM error code is incorrectly masked and replaced with a hardcoded -ENXIO.
--
commit 454b81f6136c888691f5c12d16c333a82da009f2
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add Temp Support in icm42607
This commit adds functions for reading temperature sensor data in the inv_icm42607 driver.
[ ... ]
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +0
-0@@ -0,0 +1,80 @@
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c line 23
Quoted 9 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +9
-0+static int inv_icm42607_temp_read (struct inv_icm42607_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 ;
Since PM_RUNTIME_ACQUIRE_ERR() evaluates to the actual integer error code returned by the underlying runtime PM call, does returning a hardcoded -ENXIO here mask the true cause of the PM failure from userspace?
Could this propagate the actual error code instead?
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +8
-0+ +guard (mutex)(&st->lock); + + ret =inv_icm42607_set_temp_conf (st, true,NULL ); +if (ret) +return ret; + + raw = &st->buffer[0 ];
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c line 41
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +10
-0+ ret =regmap_bulk_read (st->map,INV_ICM42607_REG_TEMP_DATA1 , raw,sizeof (*raw)); +if (ret) +return ret; + + *temp =be16_to_cpup (raw); +if (*temp ==INV_ICM42607_DATA_INVALID ) +return -EINVAL ; + +return 0 ; +}
Is the temperature sensor left enabled indefinitely after a single read?
The sensor is explicitly powered on by calling inv_icm42607_set_temp_conf() with enable set to true, but it doesn't appear to be turned off before returning.
If another channel like the accelerometer is actively streaming, the device will not power down due to runtime PM autosuspend. Because st->conf.temp_en remains true, it appears this would actively prevent the accelerometer from entering its low-power RC oscillator clock mode, which requires the temperature sensor to be disabled.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
PATCH v8 8/10 iio: imu: inv_icm42607: Add Accelerometer for icm42607
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add icm42607 accelerometer sensor for icm42607.
--- drivers/iio/imu/inv_icm42607/Makefile | 1 + drivers/iio/imu/inv_icm42607/inv_icm42607.h | 28 + .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 587 ++++++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.c | 74 ++- .../imu/inv_icm42607/inv_icm42607_buffer.h | 4 +- .../iio/imu/inv_icm42607/inv_icm42607_core.c | 72 +++ 6 files changed, 762 insertions(+), 4 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
drivers/iio/imu/inv_icm42607/Makefile +1 -0
@@ -2,6 +2,7 @@ obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o inv-icm42607-y += inv_icm42607_core.o +inv-icm42607-y += inv_icm42607_accel.o inv-icm42607-y += inv_icm42607_buffer.o inv-icm42607-y += inv_icm42607_temp.o
drivers/iio/imu/inv_icm42607/inv_icm42607.h +28 -0
@@ -82,12 +82,24 @@ enum inv_icm42607_filter_bw { INV_ICM42607_FILTER_BW_16HZ, }; +enum inv_icm42607_filter_avg { +/* 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 +/* values 7 and 8 also correspond to 64x. */ +}; +struct inv_icm42607_sensor_conf {int mode;int fs;int odr;int filter; }; +#define INV_ICM42607_SENSOR_CONF_INIT { -1, -1, -1, -1 }struct inv_icm42607_conf {struct inv_icm42607_sensor_conf gyro;
@@ -120,6 +132,7 @@ struct inv_icm42607_suspended {* @suspended: suspended sensors configuration. * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. +* @timestamp: interrupt timestamps. * @fifo: FIFO management structure. * @buffer: data transfer buffer aligned for DMA. */
@@ -135,6 +148,9 @@ struct inv_icm42607_state {struct inv_icm42607_suspended suspended;struct iio_dev *indio_gyro;struct iio_dev *indio_accel; +struct { +s64 accel; + } timestamp;struct inv_icm42607_fifo fifo;__be16 buffer[3 ]__aligned(IIO_DMA_MINALIGN) ; };
@@ -380,12 +396,24 @@ extern const struct inv_icm42607_hw inv_icm42607_hw_data;extern const struct inv_icm42607_hw inv_icm42607p_hw_data;extern const struct dev_pm_ops inv_icm42607_pm_ops; +const struct iio_mount_matrix * +inv_icm42607_get_mount_matrix (struct iio_dev *indio_dev, +const struct iio_chan_spec *chan); +u32 inv_icm42607_odr_to_period (enum inv_icm42607_odr odr); +int inv_icm42607_set_accel_conf (struct inv_icm42607_state *st, +struct inv_icm42607_sensor_conf *conf, +unsigned int *sleep_ms); +int inv_icm42607_set_temp_conf (struct inv_icm42607_state *st,bool enable,unsigned int *sleep_ms);int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw,inv_icm42607_bus_setup bus_setup); +struct iio_dev *inv_icm42607_accel_init (struct inv_icm42607_state *st); + +int inv_icm42607_accel_parse_fifo (struct iio_dev *indio_dev); +#endif
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +587 -0
587 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +71 -3
129 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h +3 -1
@@ -71,7 +71,7 @@ inv_icm42607_fifo_is_data_valid(const struct inv_icm42607_fifo_sensor_data *s)ssize_t inv_icm42607_fifo_decode_packet (const void *packet,const void **accel,const void **gyro,const s8 **temp, -const void **timestamp); +const void **timestamp,unsigned int *odr);extern const struct iio_buffer_setup_ops inv_icm42607_buffer_ops;
@@ -87,6 +87,8 @@ int inv_icm42607_buffer_update_watermark(struct inv_icm42607_state *st);int inv_icm42607_buffer_fifo_read (struct inv_icm42607_state *st,unsigned int max); +int inv_icm42607_buffer_fifo_parse (struct inv_icm42607_state *st); +int inv_icm42607_buffer_hwfifo_flush (struct inv_icm42607_state *st,unsigned int count);
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +72 -0
109 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V8 08/10] iio: imu: inv_icm42607: Add Accelerometer for icm42607
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: - [High] Data race on shared hardware FIFO state resulting in data loss and duplication. - [High] Hardware…
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Data race on shared hardware FIFO state resulting in data loss and duplication.
- [High] Hardware interrupt is never requested, rendering FIFO watermark interrupts unhandled.
- [Medium] Uninitialized array padding exposed to userspace as valid available sampling frequencies.
- [Medium] Incorrect system wakeup configuration for the logical IIO device.
- [Low] Semantic mismatch using Low-Power filter enum while the sensor is placed in Low-Noise mode.
- [Low] Lockless reads of shared configuration state in sysfs read handlers.
--
commit 084a1e35ff43644b9bd6bf8af6b8015a9b6bcef4
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add Accelerometer for icm42607
Add icm42607 accelerometer sensor for icm42607.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c line 280
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +7
-0+static int inv_icm42607_accel_read_odr (struct inv_icm42607_state *st, +int *val,int *val2) +{ +unsigned int odr; +unsigned int i; + + odr = st->conf.accel.odr;
Is it safe to read st->conf.accel.odr here without holding st->lock?
Since sysfs reads and writes for IIO_CHAN_INFO_SAMP_FREQ are not synchronized by the direct mode lock, could this race with a concurrent write mutating st->conf?
[ ... ]
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +5
-0+static int inv_icm42607_accel_read_avail (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +const int **vals, +int *type,int *length,long mask) +{
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c line 391
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +5
-0+case IIO_CHAN_INFO_SAMP_FREQ : + *vals = (const int *)inv_icm42607_accel_odr; + *type =IIO_VAL_INT_PLUS_MICRO ; + *length =ARRAY_SIZE (inv_icm42607_accel_odr) *2 ; +return IIO_AVAIL_LIST ;
Since inv_icm42607_accel_odr uses designated initializers starting at index 5, elements 0 through 4 are implicitly zero-initialized.
Will returning the entire array size here expose these uninitialized elements as valid 0 Hz sampling frequencies to userspace?
[ ... ]
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +2
-0+struct iio_dev *inv_icm42607_accel_init (struct inv_icm42607_state *st) +{
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c line 506
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +2
-0+ accel_st->power_mode =INV_ICM42607_SENSOR_MODE_LOW_NOISE ; + accel_st->filter =INV_ICM42607_FILTER_AVG_16X ;
This isn't a bug, but FILTER_AVG values are intended for low-power mode averaging. Since the sensor is set to INV_ICM42607_SENSOR_MODE_LOW_NOISE, inv_icm42607_set_accel_conf() will apply this value to the bandwidth filter mask instead.
Is it intentional to use an averaging enum to configure a bandwidth register?
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c line 531
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +2
-0+/* accel events are wakeup capable */ + ret =devm_device_init_wakeup (&indio_dev->dev);
Should this target the physical hardware device (regmap_get_device(st->map)) instead of the logical IIO device?
The PM subsystem relies on the physical device that owns the IRQ line to arm the wakeup interrupt during system suspend. Additionally, inv_icm42607_suspend() unconditionally sets INV_ICM42607_SENSOR_MODE_OFF.
Will this prevent hardware wake-on-motion events from occurring?
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +0
-0
[ ... ]
Quoted 18 lines
int inv_icm42607_buffer_hwfifo_flush(struct
inv_icm42607_state*st,drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +9
-1unsigned int count) { +struct inv_icm42607_sensor_state *accel_st =iio_priv (st->indio_accel); +struct inv_sensors_timestamp *ts; +s64 accel_ts;int ret; + accel_ts =iio_get_time_ns (st->indio_accel); ret =inv_icm42607_buffer_fifo_read (st, count); +if (ret) +return ret; -return ret; +if (st->fifo.nb.total ==0 ) +return 0 ; +
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st, · line 532
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +9
-0+if (st->fifo.nb.accel >0 ) { + ts = &accel_st->ts; +inv_sensors_timestamp_interrupt (ts, st->fifo.nb.accel, accel_ts); + ret =inv_icm42607_accel_parse_fifo (st->indio_accel); +if (ret) +return ret; + } + +return 0 ; }
Since both inv_icm42607_buffer_fifo_read() and inv_icm42607_accel_parse_fifo() acquire and release st->lock internally, the mutex is dropped between reading the hardware FIFO and parsing it.
If another sysfs hwfifo_flush executes concurrently for the gyroscope device, could it overwrite st->fifo.data and reset st->fifo.nb while the lock is dropped?
If so, this might cause the resumed thread to parse overwritten data with stale counters, potentially leading to data loss or corrupted timestamps.
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 444
Quoted 11 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +5
-0@@ -379,6 +435,11 @@ int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hwpm_runtime_set_autosuspend_delay (dev,INV_ICM42607_SUSPEND_DELAY_MS );pm_runtime_use_autosuspend (dev); +/* Initialize IIO device for Accel */ + st->indio_accel =inv_icm42607_accel_init (st); +if (IS_ERR (st->indio_accel)) +return PTR_ERR (st->indio_accel); +return 0 ; }
The driver configures hardware watermark interrupts and retrieves the INT1 irq line via fwnode_irq_get_byname() during probe, but I don't see a call to devm_request_threaded_irq() being added.
Does the lack of an interrupt handler prevent the driver from automatically draining the FIFO and leave the newly added inv_icm42607_buffer_fifo_parse() routine unhandled?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
Jonathan Cameron
maintainerRe: [PATCH V8 08/10] iio: imu: inv_icm42607: Add Accelerometer for icm42607
In reply to Chris MorganQuoted 5 lines · On Mon, 18 May 2026 15:05:23 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add icm42607 accelerometer sensor for icm42607.
Signed-off-by Chris Morgan <[email protected]>
https://sashiko.dev/#/patchset/20260518200526.458421-1-macroalpha82%40gmail.com
More feedback. Some of it looks valid. I haven't looked at all of them.
A few other bits and some comments on one or two of the sashiko ones that stood out to me.
Thanks,
Jonathan
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +0
-0@@ -82,12 +82,24 @@ enum inv_icm42607_filter_bw { INV_ICM42607_FILTER_BW_16HZ,
drivers/iio/imu/inv_icm42607/inv_icm42607.h enum inv_icm42607_filter_bw { · line 92
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +8
-0}; +enum inv_icm42607_filter_avg { +/* 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
trailing comma should be there.
Quoted 19 lines
drivers/iio/imu/inv_icm42607/inv_icm42607.h +3
-0+/* values 7 and 8 also correspond to 64x. */ +}; +drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +8
-0@@ -0,0 +1,587 @@ +static int inv_icm42607_accel_read_sensor (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +s16 *val) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +struct inv_icm42607_sensor_state *accel_st =iio_priv (indio_dev); +struct device *dev =regmap_get_device (st->map); +struct inv_icm42607_sensor_conf conf =INV_ICM42607_SENSOR_CONF_INIT ;
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c line 173
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +10
-0+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 ;
I didn't notice this until now, but you don't have anything using chan->address. This is what would typically go in there. If you need multiple registers that would normally be an index into an array of per channel structures used to look up any register.
Not that important but would move this 'code' into 'data' which would be nice.
Quoted 45 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +44
-0+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 = &st->buffer[0 ]; + ret =regmap_bulk_read (st->map, reg, data,sizeof (*data)); +if (ret) +return ret; + + *val =be16_to_cpup (data); +if (*val ==INV_ICM42607_DATA_INVALID ) +return -EINVAL ; + +return 0 ; +} +} + +static int inv_icm42607_accel_read_avail (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +const int **vals, +int *type,int *length,long mask) +{ +if (chan->type !=IIO_ACCEL )
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +10
-0+return -EINVAL ; + +switch (mask) { +case IIO_CHAN_INFO_SCALE : + *vals = (const int *)inv_icm42607_accel_scale_nano; + *type =IIO_VAL_INT_PLUS_NANO ; + *length =ARRAY_SIZE (inv_icm42607_accel_scale_nano) *2 ; +return IIO_AVAIL_LIST ; +case IIO_CHAN_INFO_SAMP_FREQ : + *vals = (const int *)inv_icm42607_accel_odr;
Sashiko is correctly pointing out that this is going to print a bunch of leading 0s as the array is only useful from 5 onwards. Start there rather than at the beginning.
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c line 531
Quoted 13 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +11
-0+ *type =IIO_VAL_INT_PLUS_MICRO ; + *length =ARRAY_SIZE (inv_icm42607_accel_odr) *2 ; +return IIO_AVAIL_LIST ; +default : +return -EINVAL ; + } +} +struct iio_dev *inv_icm42607_accel_init (struct inv_icm42607_state *st) +{ +/* accel events are wakeup capable */ + ret =devm_device_init_wakeup (&indio_dev->dev);
Sashiko points out correctly that should probably be on the physical bus device rather than this one. Mind you I think for now you ripped that out anyway so don't set it at all.
Quoted 9 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +9
-0+if (ret) +return ERR_PTR (ret); + + ret =devm_iio_device_register (dev, indio_dev); +if (ret) +return ERR_PTR (ret); + +return indio_dev; +}
PATCH v8 9/10 iio: imu: inv_icm42607: Add Gyroscope to icm42607
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add gyroscope functions to the icm42607 driver.
--- drivers/iio/imu/inv_icm42607/Makefile | 1 + drivers/iio/imu/inv_icm42607/inv_icm42607.h | 9 + .../imu/inv_icm42607/inv_icm42607_buffer.c | 27 +- .../iio/imu/inv_icm42607/inv_icm42607_core.c | 55 +- .../iio/imu/inv_icm42607/inv_icm42607_gyro.c | 552 ++++++++++++++++++ 5 files changed, 640 insertions(+), 4 deletions(-) create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c
drivers/iio/imu/inv_icm42607/Makefile +1 -0
@@ -2,6 +2,7 @@ obj-$(CONFIG_INV_ICM42607) += inv-icm42607.o inv-icm42607-y += inv_icm42607_core.o +inv-icm42607-y += inv_icm42607_gyro.o inv-icm42607-y += inv_icm42607_accel.o inv-icm42607-y += inv_icm42607_buffer.o inv-icm42607-y += inv_icm42607_temp.o
drivers/iio/imu/inv_icm42607/inv_icm42607.h +9 -0
@@ -149,6 +149,7 @@ struct inv_icm42607_state {struct iio_dev *indio_gyro;struct iio_dev *indio_accel;struct { +s64 gyro;s64 accel; } timestamp;struct inv_icm42607_fifo fifo;
@@ -406,12 +407,20 @@ int inv_icm42607_set_accel_conf(struct inv_icm42607_state *st,struct inv_icm42607_sensor_conf *conf, unsigned int *sleep_ms); +int inv_icm42607_set_gyro_conf (struct inv_icm42607_state *st, +struct inv_icm42607_sensor_conf *conf, +unsigned int *sleep_ms); +int inv_icm42607_set_temp_conf (struct inv_icm42607_state *st,bool enable,unsigned int *sleep_ms);int inv_icm42607_core_probe (struct regmap *regmap,const struct inv_icm42607_hw *hw,inv_icm42607_bus_setup bus_setup); +struct iio_dev *inv_icm42607_gyro_init (struct inv_icm42607_state *st); + +int inv_icm42607_gyro_parse_fifo (struct iio_dev *indio_dev); +struct iio_dev *inv_icm42607_accel_init (struct inv_icm42607_state *st);int inv_icm42607_accel_parse_fifo (struct iio_dev *indio_dev);
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +25 -2
@@ -388,7 +388,9 @@ static int inv_icm42607_buffer_postdisable(struct iio_dev *indio_dev) goto out_unlock; conf.mode =INV_ICM42607_SENSOR_MODE_OFF ; -if (sensor !=INV_ICM42607_SENSOR_GYRO ) +if (sensor ==INV_ICM42607_SENSOR_GYRO ) + ret =inv_icm42607_set_gyro_conf (st, &conf, &sleep_sensor); +else ret =inv_icm42607_set_accel_conf (st, &conf, &sleep_sensor);if (ret) goto out_unlock;
@@ -483,6 +485,7 @@ int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st,int inv_icm42607_buffer_fifo_parse (struct inv_icm42607_state *st) { +struct inv_icm42607_sensor_state *gyro_st =iio_priv (st->indio_gyro);struct inv_icm42607_sensor_state *accel_st =iio_priv (st->indio_accel);struct inv_sensors_timestamp *ts;int ret;
@@ -490,6 +493,16 @@ int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)if (st->fifo.nb.total ==0 )return 0 ; +/* handle gyroscope timestamp and FIFO data parsing */ +if (st->fifo.nb.gyro >0 ) { + ts = &gyro_st->ts; +inv_sensors_timestamp_interrupt (ts, st->fifo.watermark.eff_gyro, + st->timestamp.gyro); + ret =inv_icm42607_gyro_parse_fifo (st->indio_gyro); +if (ret) +return ret; + } +/* handle accelerometer timestamp and FIFO data parsing */ if (st->fifo.nb.accel >0 ) { ts = &accel_st->ts;
@@ -506,12 +519,14 @@ int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)int inv_icm42607_buffer_hwfifo_flush (struct inv_icm42607_state *st,unsigned int count) { +struct inv_icm42607_sensor_state *gyro_st =iio_priv (st->indio_gyro);struct inv_icm42607_sensor_state *accel_st =iio_priv (st->indio_accel);struct inv_sensors_timestamp *ts; -s64 accel_ts; +s64 gyro_ts, accel_ts;int ret; accel_ts =iio_get_time_ns (st->indio_accel); + gyro_ts =iio_get_time_ns (st->indio_gyro); ret =inv_icm42607_buffer_fifo_read (st, count);if (ret)
@@ -520,6 +535,14 @@ int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st,if (st->fifo.nb.total ==0 )return 0 ; +if (st->fifo.nb.gyro >0 ) { + ts = &gyro_st->ts; +inv_sensors_timestamp_interrupt (ts, st->fifo.nb.gyro, gyro_ts); + ret =inv_icm42607_gyro_parse_fifo (st->indio_gyro); +if (ret) +return ret; + } +if (st->fifo.nb.accel >0 ) { ts = &accel_st->ts;inv_sensors_timestamp_interrupt (ts, st->fifo.nb.accel, accel_ts);
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +53 -2
91 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +552 -0
552 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V8 09/10] iio: imu: inv_icm42607: Add Gyroscope to icm42607
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: - [High] Probe race condition leads to NULL pointer dereference on `st->indio_gyro`. - [High] Data race and…
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] Probe race condition leads to NULL pointer dereference on st->indio_gyro.
- [High] Data race and TOCTOU vulnerability in hwfifo_flush causes data duplication and timestamp corruption.
- [High] Incorrect devres registration order causes Use-After-Free during teardown.
- [Medium] The available sampling frequencies sysfs attribute exposes uninitialized memory (zeros).
- [Medium] Software timestamp state becomes permanently inconsistent if hardware configuration fails.
- [Medium] Gyroscope is left powered on indefinitely after a single raw read.
--
commit db77d2b5f802169a721fb840e81fd3f9add01065
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add Gyroscope to icm42607
Add gyroscope functions to the icm42607 driver.
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +0
-0
[ ... ]
Quoted 17 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +3
-1@@ -506,12 +519,14 @@ int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st)int inv_icm42607_buffer_hwfifo_flush (struct inv_icm42607_state *st,unsigned int count) { +struct inv_icm42607_sensor_state *gyro_st =iio_priv (st->indio_gyro);struct inv_icm42607_sensor_state *accel_st =iio_priv (st->indio_accel);struct inv_sensors_timestamp *ts; -s64 accel_ts; +s64 gyro_ts, accel_ts;int ret; accel_ts =iio_get_time_ns (st->indio_accel); + gyro_ts =iio_get_time_ns (st->indio_gyro); ret =inv_icm42607_buffer_fifo_read (st, count);if (ret)
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st, · line 544
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +7
-0@@ -520,6 +535,14 @@ int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st,if (st->fifo.nb.total ==0 )return 0 ; +if (st->fifo.nb.gyro >0 ) { + ts = &gyro_st->ts; +inv_sensors_timestamp_interrupt (ts, st->fifo.nb.gyro, gyro_ts); + ret =inv_icm42607_gyro_parse_fifo (st->indio_gyro); +if (ret) +return ret; + }
Since inv_icm42607_buffer_fifo_read() drops st->lock before returning, could this result in a data race?
Concurrent calls from sysfs could overwrite the shared st->fifo.data and state between the lock release and the subsequent lock acquisition inside inv_icm42607_gyro_parse_fifo(), potentially causing duplicated data and corrupted timestamp state.
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hw · line 489
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0@@ -440,6 +483,11 @@ int inv_icm42607_core_probe(struct regmap *regmap, const struct inv_icm42607_hwif (IS_ERR (st->indio_accel))return PTR_ERR (st->indio_accel); +/* Initialize IIO device for Gyro */ + st->indio_gyro =inv_icm42607_gyro_init (st); +if (IS_ERR (st->indio_gyro)) +return PTR_ERR (st->indio_gyro);
If a user or udev interacts with the accelerometer sysfs interface (like triggering hwfifo_flush) immediately after it is registered but before st->indio_gyro is initialized, will this cause a NULL pointer dereference when inv_icm42607_buffer_hwfifo_flush() unconditionally accesses st->indio_gyro?
Additionally, does allocating the IIO devices after inv_icm42607_buffer_init() introduce a use-after-free risk during teardown?
Since devres uses LIFO ordering, the IIO devices will be freed before the hardware interrupt handler is removed. If an interrupt fires during removal, the handler might access the freed st->indio_gyro and st->indio_accel.
[ ... ]
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +0
-0
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +4
-0+static int inv_icm42607_gyro_read_sensor (struct iio_dev *indio_dev, +struct iio_chan_spec const *chan, +s16 *val) +{
[ ... ]
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +8
-0+/* enable gyro sensor */ + conf.mode = gyro_st->power_mode; + ret =inv_icm42607_set_gyro_conf (st, &conf,NULL ); +if (ret) +return ret; + +/* read gyro register data */ + data = &st->buffer[0 ];
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 183
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +10
-0+ ret =regmap_bulk_read (st->map, reg, data,sizeof (*data)); +if (ret) +return ret; + + *val =be16_to_cpup (data); +if (*val ==INV_ICM42607_DATA_INVALID ) +return -EINVAL ; + +return 0 ; +}
Does this leave the gyroscope powered on indefinitely after a raw read?
It doesn't appear to be turned off again before returning, meaning the driver will maintain the ON state even after resuming from runtime PM.
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 242
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +10
-0+static const int inv_icm42607_gyro_odr[][2 ] = { + [INV_ICM42607_ODR_12_5HZ ] = {12 ,500000 }, + [INV_ICM42607_ODR_25HZ ] = {25 ,0 }, + [INV_ICM42607_ODR_50HZ ] = {50 ,0 }, + [INV_ICM42607_ODR_100HZ ] = {100 ,0 }, + [INV_ICM42607_ODR_200HZ ] = {200 ,0 }, + [INV_ICM42607_ODR_400HZ ] = {400 ,0 }, + [INV_ICM42607_ODR_800HZ ] = {800 ,0 }, + [INV_ICM42607_ODR_1600HZ ] = {1600 ,0 }, +};
Could this initialization expose zeros to userspace?
Since the first index (INV_ICM42607_ODR_12_5HZ) evaluates to a non-zero value, the leading elements in this array will be implicitly zero-initialized. When returned via inv_icm42607_gyro_read_avail(), those zeros might break the IIO sysfs API contract.
[ ... ]
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +3
-0+static int inv_icm42607_gyro_write_odr (struct iio_dev *indio_dev, +int val,int val2) +{
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 299
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +8
-0+ 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;
If inv_icm42607_set_gyro_conf() fails here, does the software timestamp state become permanently inconsistent?
It seems ts is updated before the I2C/SPI write, and there is no rollback of the timestamp configuration on failure.
[ ... ]
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
PATCH v8 10/10 arm64: dts: rockchip: Add icm42607p IMU for RG-DS
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add the Invensense ICM42607P IMU for the Anbernic RG-DS. Mount-matrix was tested with iio-sensor-proxy and reports correct orientation.
--- .../dts/rockchip/rk3568-anbernic-rg-ds.dts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/rockchip/rk3568-anbernic-rg-ds.dts +19 -1
@@ -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 =
Signature · 1 line
2.43.0