Add Invensense ICM42607
Subsystems (4)
v9 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.
Changes Since V8:
- Added back IRQ dropped accidentally when dropping wake on movement patches.
- Dropped "Reviewed-By" tag on patch 2 because of substantial changes made to devicetree binding documentation.
- Additional small fixes as suggested.
Chris Morgan (11):
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 IRQ 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 | 14 + .../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 | 436 +++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 589 +++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.c | 574 +++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.h | 95 +++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 693 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_gyro.c | 559 ++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 95 +++ .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 107 +++ .../iio/imu/inv_icm42607/inv_icm42607_temp.c | 81 ++ .../iio/imu/inv_icm42607/inv_icm42607_temp.h | 33 + 16 files changed, 3341 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 v9 1/11 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 v9 2/11 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, however unlike the icm42600 driver we require a interrupt-names property be present.
--- .../bindings/iio/imu/invensense,icm42600.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml +12 -0
@@ -30,6 +30,8 @@ properties: - invensense,icm42600 - invensense,icm42602 - invensense,icm42605 + - invensense,icm42607 + - invensense,icm42607p - invensense,icm42622 - invensense,icm42631 - invensense,icm42686
@@ -71,6 +73,16 @@ required: allOf: - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + contains: + enum: + - invensense,icm42607 + - invensense,icm42607p + then: + required: + - interrupt-names unevaluatedProperties: false
Signature · 1 line
2.43.0
Re: [PATCH V9 02/11] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 5 lines · Chris Morgan
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.
Implement feedback from v3. Subject is still incorrect.
Quoted 4 lines
This device is functionally very similar to the icm42600 series with a very different register layout, however unlike the icm42600 driver we require a interrupt-names property be present.
Why do we require it? Who needs it?
Best regards,
Krzysztof
Re: [PATCH V9 02/11] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 9 lines · Krzysztof Kozlowski
Quoted 5 lines · Chris Morgan
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.
Implement feedback from v3. Subject is still incorrect.
I'm sorry, that was dropped due to an oversight. I'll correct it.
Quoted 7 lines
Quoted 4 lines
This device is functionally very similar to the icm42600 series with a very different register layout, however unlike the icm42600 driver we require a interrupt-names property be present.
Why do we require it? Who needs it?
The driver this was based off of, the icm42600 driver, has a fallback to select the 1st available interrupt in the event of the named interrupt not existing. I was told not to do that here so the named interrupt is a requirement for the icm42607.
Quoted 3 lines
Best regards,
Krzysztof
Thank you,
Chris
Re: [PATCH V9 02/11] dt-bindings: iio: imu: icm42600: Add icm42607 binding
Quoted 18 lines · Chris Morgan
Quoted 9 lines · Krzysztof Kozlowski
Quoted 5 lines · Chris Morgan
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.
Implement feedback from v3. Subject is still incorrect.
I'm sorry, that was dropped due to an oversight. I'll correct it.
Quoted 5 lines
Quoted 4 lines
This device is functionally very similar to the icm42600 series with a very different register layout, however unlike the icm42600 driver we require a interrupt-names property be present.
Quoted 5 lines
Quoted 2 lines
Why do we require it? Who needs it?
The driver this was based off of, the icm42600 driver, has a fallback to select the 1st available interrupt in the event of the named
So some other driver? That's not relevant here if you do not use that.
Quoted 2 lines
interrupt not existing. I was told not to do that here so the named interrupt is a requirement for the icm42607.
So icm42607 driver needs it? Then write it explicitly.
Best regards,
Krzysztof
Jonathan Cameron
maintainerRe: [PATCH V9 02/11] dt-bindings: iio: imu: icm42600: Add icm42607 binding
In reply to Chris MorganQuoted 18 lines · On Sun, 31 May 2026 20:44:03 -0500 Chris Morgan <[email protected]> wrote:
Quoted 9 lines · Krzysztof Kozlowski
Quoted 5 lines · Chris Morgan
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.
Implement feedback from v3. Subject is still incorrect.
I'm sorry, that was dropped due to an oversight. I'll correct it.
Quoted 5 lines
Quoted 4 lines
This device is functionally very similar to the icm42600 series with a very different register layout, however unlike the icm42600 driver we require a interrupt-names property be present.
Quoted 7 lines
Quoted 2 lines
Why do we require it? Who needs it?
The driver this was based off of, the icm42600 driver, has a fallback to select the 1st available interrupt in the event of the named interrupt not existing. I was told not to do that here so the named interrupt is a requirement for the icm42607.
A bit more background on this. I think it went as follows.
When that other driver originally went in we didn't pick up on their being multiple interrupt lines. Hence once that came up because someone had a board that only connected the other pin we had to 'guess' which one was the default (I'm sure we asked people :)
I'll noted that we had at least one case in the past (can't remember if it was this part) where the assumed default was not the first one :( We've even had package variants (which we don't normally use different compatibles for) where only INT2 actually had a pin.
Hence, since then we've been more careful with these devices. Given there is nothing special with one interrupt rather than the other with a mux on each that lets us route all interrupts signals to each pin, my strong preference is we don't make assumptions and always require the firmeware to say which one it is.
Jonathan
Quoted 7 lines
Quoted 4 lines
Best regards,
KrzysztofThank you,
Chris
PATCH v9 3/11 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 | 336 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 206 +++++++++++ 2 files changed, 542 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 +336 -0
@@ -0,0 +1,336 @@ +/* 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 , +INV_ICM42607_FILTER_BW_NB +}; + +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; +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); + +#endif
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +206 -0
206 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V9 03/11] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Using regmap_write() instead of regmap_update_bits() in configuration functions unintentionally…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Using regmap_write() instead of regmap_update_bits() in configuration functions unintentionally clobbers reserved or unhandled register fields.
- [Medium] Strict requirement for 'INT1' named interrupt breaks ACPI support and simple Device Trees.
- [Low] regcache_sync() is a no-op because regcache_mark_dirty() is not called after the hardware soft reset.
--
commit fb241e98a0e4c74d0ee1e8a5eb96fc324eaf8bee
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
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.
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_set_conf (struct inv_icm42607_state *st, +const struct inv_icm42607_conf *conf) +{
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 55
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +7
-0+ val =FIELD_PREP (INV_ICM42607_GYRO_CONFIG1_FILTER_MASK , conf->gyro.filter); + ret =regmap_write (st->map,INV_ICM42607_REG_GYRO_CONFIG1 , val); +if (ret) +return ret; + + val =FIELD_PREP (INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK , conf->accel.filter); + ret =regmap_write (st->map,INV_ICM42607_REG_ACCEL_CONFIG1 , val);
[Severity: High]
Does this regmap_write() unintentionally clobber the averaging configuration bits (INV_ICM42607_ACCEL_CONFIG1_AVG_MASK)?
By writing the entire 8-bit register, any bits outside of the filter mask are cleared to zero. This clobbers the averaging configuration (bits 6:4), discarding the hardware default. Should this use regmap_update_bits() instead to safely modify only the filter bits?
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +7
-0+if (ret) +return ret; + + st->conf = *conf; + +return 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 102
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +10
-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 *10000 ); +if (ret) +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);
[Severity: Low]
Is this regcache_sync() a no-op?
It is called immediately after a software reset, but regcache_sync() returns immediately if the map's cache_dirty flag is false. Since regcache_mark_dirty() was never called after the hardware reset, the cache is still considered clean.
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +4
-0+if (ret) +return ret; + + ret =bus_setup (st);
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 155
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +12
-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" );
[Severity: Medium]
Will this strict requirement for an "INT1" named interrupt break probing on systems with ACPI or simple single-interrupt Device Trees?
When an interrupt is provided without an "interrupt-names" property, fwnode_irq_get_byname() fails. Would it be more compatible to fall back to fwnode_irq_get(dev_fwnode(dev), 0) or use the irq provided by the I2C/SPI client core before unconditionally aborting the probe?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Jonathan Cameron
maintainerRe: [PATCH V9 03/11] iio: imu: inv_icm42607: Add inv_icm42607 Core Driver
In reply to Chris MorganQuoted 5 lines · On Fri, 29 May 2026 22:17:30 -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.
https://sashiko.dev/#/patchset/20260530031739.109063-1-macroalpha82%40gmail.com
Again has some feedback. I've commented on them below to say whether I agree or not. Also a few other minor things inline.
Quoted 44 lines
Signed-off-by Chris Morgan <[email protected]>--- drivers/iio/imu/inv_icm42607/inv_icm42607.h | 336 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 206 +++++++++++ 2 files changed, 542 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_core.c new file +28
-0+static int inv_icm42607_set_conf (struct inv_icm42607_state *st, +const struct inv_icm42607_conf *conf) +{ +unsigned int val; +int ret; + + val =FIELD_PREP (INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK , conf->gyro.mode); + val |=FIELD_PREP (INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK , conf->accel.mode); +/* +* No temperature enable reg in datasheet, but BSP driver selected RC +* oscillator clock in LP mode when temperature was disabled. +*/ +if (!conf->temp_en) + val |=INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL ; + ret =regmap_write (st->map,INV_ICM42607_REG_PWR_MGMT0 , val); +if (ret) +return ret; + + val =FIELD_PREP (INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK , conf->gyro.fs); + val |=FIELD_PREP (INV_ICM42607_GYRO_CONFIG0_ODR_MASK , conf->gyro.odr); + ret =regmap_write (st->map,INV_ICM42607_REG_GYRO_CONFIG0 , val); +if (ret) +return ret; + + val =FIELD_PREP (INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK , conf->accel.fs); + val |=FIELD_PREP (INV_ICM42607_ACCEL_CONFIG0_ODR_MASK , conf->accel.odr); + ret =regmap_write (st->map,INV_ICM42607_REG_ACCEL_CONFIG0 , val); +if (ret)
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 56
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +10
-0+return ret; + + val =FIELD_PREP (INV_ICM42607_GYRO_CONFIG1_FILTER_MASK , conf->gyro.filter); + ret =regmap_write (st->map,INV_ICM42607_REG_GYRO_CONFIG1 , val); +if (ret) +return ret; + + val =FIELD_PREP (INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK , conf->accel.filter); + ret =regmap_write (st->map,INV_ICM42607_REG_ACCEL_CONFIG1 , val); +if (ret)
Sashiko points out that this is overwriting whatever is the INV_ICM42607_ACCEL_CONFIG1_AVG_MASK field. That isn't set at all yet, which is fine but I'd be tempted to make it clear what intent is here. Either explicitly set it to 0 as
val |= FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, 0);
or use regmap_update_bits as sashiko suggests.
Quoted 36 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +36
-0+return ret; + + st->conf = *conf; + +return 0 ; +} + +/** +* 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) +{ +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,"Unknown whoami %#02x expected %#02x (%s)\n" , + 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; + +fsleep (INV_ICM42607_RESET_TIME_MS *1000 ); +
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 102
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +10
-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 *10000 ); +if (ret) +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);
I haven't checked sashiko's feedback on this but it seems plausible as there is a check in regcache_sync on whether the cache is dirty and no obvious path for it to get to that state here.
Quoted 23 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +22
-0+if (ret) +return ret; + + 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); +} +int inv_icm42607_core_probe(struct regmap *regmap, + const struct inv_icm42607_hw *hw,
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 155
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" );
Sashiko comments on this and is correct that this only works on device tree with interrupt-names. Which is intentional!
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c line 161
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +6
-0+ + st =devm_kzalloc (dev,sizeof (*st),GFP_KERNEL ); +if (!st) +return -ENOMEM ; + +dev_set_drvdata (dev, st);
Really small thing. Is this used yet? I think this should be in a later patch. Probably patch 5.
Quoted 45 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c new file +45
-0+ + ret =devm_mutex_init (dev, &st->lock); +if (ret) +return ret; + + st->hw = hw; + st->map = regmap; + st->irq = irq; + + ret =iio_read_mount_matrix (dev, &st->orientation); +if (ret) +return dev_err_probe (dev, ret, +"failed to retrieve mounting matrix %d\n" , ret); + + ret =devm_regulator_get_enable (dev,"vdd" ); +if (ret) +return dev_err_probe (dev, ret, +"Failed to get vdd regulator\n" ); + + st->vddio_supply =devm_regulator_get (dev,"vddio" ); +if (IS_ERR (st->vddio_supply)) +return dev_err_probe (dev,PTR_ERR (st->vddio_supply), +"Failed to get vddio regulator\n" ); + + ret =inv_icm42607_enable_vddio_reg (st); +if (ret) +return ret; + + ret =devm_add_action_or_reset (dev, inv_icm42607_disable_vddio_reg, st); +if (ret) +return ret; + +/* Setup chip registers (includes WHOAMI check, reset check, bus setup) */ + ret =inv_icm42607_setup (st, bus_setup); +if (ret) +return ret; + +return 0 ; +} +EXPORT_SYMBOL_NS_GPL (inv_icm42607_core_probe,"IIO_ICM42607" ); + +MODULE_AUTHOR ("InvenSense, Inc." ); +MODULE_DESCRIPTION ("InvenSense ICM-42607x device driver" ); +MODULE_LICENSE ("GPL" ); +MODULE_IMPORT_NS ("IIO_INV_SENSORS_TIMESTAMP" );
PATCH v9 4/11 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 | 16 +++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 57 ++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 94 ++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 106 ++++++++++++++++++ 8 files changed, 315 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 +16 -0
@@ -13,6 +13,22 @@#include <linux/regmap.h> #include <linux/regulator/consumer.h> +/* +* Serial bus slew rates. Rates are expressed as range between the two +* values with the midpoint as the typical rate. For the final value of +* 2ns, 2ns is considered the max value with no expressed minimum or +* typical value. +*/ +enum inv_icm42607_slew_rate { +INV_ICM42607_SLEW_RATE_20_60NS , +INV_ICM42607_SLEW_RATE_12_36NS , +INV_ICM42607_SLEW_RATE_6_19NS , +INV_ICM42607_SLEW_RATE_4_14NS , +INV_ICM42607_SLEW_RATE_2_8NS , +INV_ICM42607_SLEW_RATE_2NS , +INV_ICM42607_SLEW_RATE_NB +}; +enum inv_icm42607_sensor_mode {INV_ICM42607_SENSOR_MODE_OFF ,INV_ICM42607_SENSOR_MODE_STANDBY ,
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +57 -0
63 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c new file +94 -0
94 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_spi.c new file +106 -0
106 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V9 04/11] 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: - [Medium] Missing power-up delay after enabling the `vdd` regulator and before obtaining/enabling the…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing power-up delay after enabling the vdd regulator and before obtaining/enabling the vddio regulator. --
commit f54ebd503e69aebf3524a2526c6611126af82da8
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 includes the necessary Kconfig and Makefile additions to allow building the module.
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); +}
[Severity: Medium]
Does inv_icm42607_core_probe() need a power-up stabilization delay after enabling the vdd regulator?
Looking at inv_icm42607_core_probe() in inv_icm42607_core.c, the vdd and vddio regulators are enabled sequentially without an intervening delay:
ret = devm_regulator_get_enable(dev, "vdd"); if (ret) return dev_err_probe(dev, ret, "Failed to get vdd regulator\n"); st->vddio_supply = devm_regulator_get(dev, "vddio"); if (IS_ERR(st->vddio_supply)) return dev_err_probe(dev, PTR_ERR(st->vddio_supply), "Failed to get vddio regulator\n"); ret = inv_icm42607_enable_vddio_reg(st);
Other sensors in this family, such as the icm42600 and icm45600, typically require a delay before vddio can be applied. Could omitting this delay cause hardware initialization failures or latch-up on platforms where vddio ramps up before vdd is fully stable?
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Jonathan Cameron
maintainerRe: [PATCH V9 04/11] iio: imu: inv_icm42607: Add I2C and SPI For icm42607
In reply to Chris MorganQuoted 6 lines · On Fri, 29 May 2026 22:17:31 -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.
Sashiko suggested power sequencing timing might apply between vdd and vddio. I took a quick look and didn't spot it on the datasheet. Perhaps they've figured out how not to have that burden on the platforms using their chips!
Quoted 1 line
Signed-off-by Chris Morgan <[email protected]>
LGTM
PATCH v9 5/11 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 | 10 ++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 144 ++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_i2c.c | 1 + .../iio/imu/inv_icm42607/inv_icm42607_spi.c | 1 + 4 files changed, 156 insertions(+)
drivers/iio/imu/inv_icm42607/inv_icm42607.h +10 -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>
@@ -109,6 +110,7 @@ struct inv_icm42607_hw {* @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.
@@ -118,6 +120,7 @@ struct inv_icm42607_state {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;
@@ -339,11 +342,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,
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +144 -0
185 lines not on this page · raw message
drivers/iio/imu/inv_icm42607/inv_icm42607_i2c.c +1 -0
@@ -82,6 +82,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
@@ -94,6 +94,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
[email protected]
AI reviewRe: [PATCH V9 05/11] iio: imu: inv_icm42607: Add PM support for icm42607
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] System suspend and resume callbacks will self-deadlock due to recursive acquisition of a…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] System suspend and resume callbacks will self-deadlock due to recursive acquisition of a non-recursive mutex via pm_runtime_force_suspend().
- [High] Early returns in system sleep callbacks bypass pm_runtime_force_resume, leaving runtime PM permanently disabled.
- [Low] System suspend and resume callbacks redundantly duplicate runtime PM operations.
--
commit f323b806ac9a0c8479d99408f838cb77ab5868ae
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add PM support for icm42607
Add power management support for the ICM42607 device driver.
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, · line 333
Quoted 11 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +11
-0+static int inv_icm42607_suspend (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); + +if (pm_runtime_suspended (dev)) +return 0 ; + + ret =pm_runtime_force_suspend (dev);
[Severity: High]
Does this code self-deadlock when system suspend is triggered?
inv_icm42607_suspend() acquires st->lock via guard(), then calls pm_runtime_force_suspend(). If the device is active, this synchronously invokes inv_icm42607_runtime_suspend() which attempts to acquire the same non-recursive st->lock:
inv_icm42607_suspend()
guard(mutex)(&st->lock);
pm_runtime_force_suspend()
inv_icm42607_runtime_suspend()
guard(mutex)(&st->lock);Does the same deadlock pattern apply to inv_icm42607_resume() and inv_icm42607_runtime_resume()?
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, · line 343
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+if (ret) +return ret; + + 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);
[Severity: Low]
Are these manual hardware shutdown operations redundant?
pm_runtime_force_suspend() invokes inv_icm42607_runtime_suspend() which already performs these exact same sensor power-down and regulator disable operations.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +5
-0+ +return 0 ; +} + +static int inv_icm42607_resume (struct device *dev)
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, · line 358
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); + +if (pm_runtime_suspended (dev)) +return 0 ; + + ret =pm_runtime_force_resume (dev);
[Severity: High]
Does this early return leave runtime PM permanently disabled for the device?
If the device was active before system suspend, pm_runtime_force_suspend() suspends it, updates its status to RPM_SUSPENDED, and calls pm_runtime_disable().
During system resume, the pm_runtime_suspended() check above evaluates to true, causing the function to return early. This bypasses the pm_runtime_force_resume() call, so its internal call to pm_runtime_enable() is never executed.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Jonathan Cameron
maintainerRe: [PATCH V9 05/11] iio: imu: inv_icm42607: Add PM support for icm42607
In reply to Chris MorganQuoted 5 lines · On Fri, 29 May 2026 22:17:32 -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,
https://sashiko.dev/#/patchset/20260530031739.109063-1-macroalpha82%40gmail.com
Points out a deadlock. Suggests maybe you need a few more test cases! More generally I think you've misunderstood how force_suspend is used.
Quoted 6 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, · line 331
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +9
-0+static int inv_icm42607_suspend (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); + +if (pm_runtime_suspended (dev)) +return 0 ;
Force suspend will deal with this for everything in there. I'm a little confused on why runtime suspend effects disabing vddio_reg.
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0+ + ret =pm_runtime_force_suspend (dev);
You'll need to do this without holding the lock.
Also take a much closer look at what it does.
(sashiko points out why what you have here doesn't make sense).
Quoted 22 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +21
-0+if (ret) +return ret; + + 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_runtime_suspend (struct device *dev) +{ +struct inv_icm42607_state *st =dev_get_drvdata (dev); +int ret; + +guard (mutex)(&st->lock); +
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, · line 387
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-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 ; +}
I cropped the resume cases but they have the same problems..
PATCH v9 6/11 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 | 483 ++++++++++++++++++ .../imu/inv_icm42607/inv_icm42607_buffer.h | 93 ++++ .../iio/imu/inv_icm42607/inv_icm42607_core.c | 52 +- 5 files changed, 654 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. Rates are expressed as range between the two * values with the midpoint as the typical rate. For the final value of
@@ -114,6 +118,10 @@ struct inv_icm42607_hw {* @irq: chip irq, required to enable/disable and set wakeup * @orientation: sensor chip orientation relative to main hardware. * @conf: chip sensors configurations. +* @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;
@@ -124,6 +132,22 @@ struct inv_icm42607_state {int irq;struct iio_mount_matrix orientation;struct inv_icm42607_conf conf; +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 */
@@ -355,6 +379,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 +483 -0
483 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 V9 06/11] iio: imu: inv_icm42607: Add Buffer support for icm42607
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
New issues:
- [High] Regmap write is executed after the hardware power has already been disabled, causing bus timeouts or crashes.
- [High] Missing __packed attribute on struct inv_icm42607_fifo_sensor_data causes an unaligned memory access fault on strict architectures.
- [High] st->fifo.count read from the hardware is not rounded down to a multiple of packet_size before reading from the hardware FIFO, permanently desynchronizing the FIFO stream if a partial packet is present.
- [Medium] get_unaligned(&packet) is misused to cast a pointer, failing to perform an unaligned read of the actual struct fields.
Pre-existing issues:
- [Critical] System suspend and resume callbacks inherently deadlock against their runtime PM equivalents due to recursive locking of the same non-recursive mutex. --
commit b02d906e23fd74f9655bad46fd7b83ee46cc34c9
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add Buffer support for icm42607
Add all FIFO parsing and reading functions to support inv_icm42607 hardware.
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h line 51
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +6
-0+/* FIFO data packet */ +struct inv_icm42607_fifo_sensor_data { +__be16 x; +__be16 y; +__be16 z; +};
[Severity: High]
Does this struct need a __packed attribute?
Because this struct is embedded inside the __packed packets at odd byte offsets (like inv_icm42607_fifo_1sensor_packet), leaving it unpacked means the compiler assumes normal 2-byte alignment for its fields.
When these fields are later accessed in inv_icm42607_fifo_is_data_valid() via be16_to_cpu(), could this trigger a fatal alignment fault on architectures lacking hardware support for unaligned accesses?
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +2
-0+ +#define INV_ICM42607_FIFO_DATA_INVALID -32768
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 47
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +6
-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 =get_unaligned (&packet); +const struct inv_icm42607_fifo_2sensors_packet *pack2 =get_unaligned (&packet);
[Severity: Medium]
Are these get_unaligned() calls working as intended?
By taking the address of the pointer argument (&packet), get_unaligned() simply reads the pointer value off the stack itself. It does not mark the resulting pointer for safe unaligned access of the actual struct fields in the data buffer.
Is there a better way to safely cast these pointers?
Quoted 1 line
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +1
-0+u8 header = *((const u8 *)packet);
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 433
Quoted 9 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +9
-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);
[Severity: High]
Does st->fifo.count need to be rounded down to a multiple of the packet size before reading from the hardware FIFO?
If a read races with the hardware writing a new packet, the reported count might include a partial packet. If this unrounded count is passed directly to regmap_noinc_read(), those partial bytes are permanently popped from the hardware FIFO.
While the decode loop will safely exit when returning -EIO and discarding the partial bytes, won't the next interrupt resume reading from the halfway point of that packet?
Could this permanently desynchronize the stream by causing the decode function to interpret random data bytes as headers?
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +2
-0+if (ret) +return ret;
[ ... ]
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
Quoted 12 lines
@@ ... @@
static intinv_icm42607_suspend(struct device *dev){drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0struct inv_icm42607_state *st =dev_get_drvdata (dev);int ret;guard (mutex)(&st->lock);if (pm_runtime_suspended (dev))return 0 ; ret =pm_runtime_force_suspend (dev);
[Severity: Critical]
This is a pre-existing issue, but can this system suspend callback deadlock against its runtime PM equivalent?
In inv_icm42607_suspend(), the driver locks the main state mutex via guard(mutex)(&st->lock). While holding this lock, it calls pm_runtime_force_suspend(dev).
If the device is not already suspended, the PM core synchronously executes the device's runtime suspend callback, inv_icm42607_runtime_suspend(), which immediately attempts to acquire the exact same st->lock via its own guard(mutex)(&st->lock).
Because Linux kernel mutexes are not recursive, does this result in a guaranteed deadlock on every system suspend transition where the device was active?
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_suspend(struct device *dev) · line 377
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0if (ret)return ret; +if (st->fifo.on) { + ret =regmap_write (st->map,INV_ICM42607_REG_FIFO_CONFIG1 , +INV_ICM42607_FIFO_CONFIG1_BYPASS );
[Severity: High]
Can this regmap_write() timeout or crash the bus by accessing a powered-off device?
The pm_runtime_force_suspend() call immediately preceding this block delegates to the driver's runtime suspend callback, which actively powers down the device by turning off pwr_mgmt0 and disabling the vddio regulator.
When this new regmap_write() executes, the I/O power to the chip has already been severed.
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +4
-0+if (ret) +return ret; + } + ret =inv_icm42607_set_pwr_mgmt0 (st,INV_ICM42607_SENSOR_MODE_OFF ,INV_ICM42607_SENSOR_MODE_OFF , false,NULL );
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=6
Jonathan Cameron
maintainerRe: [PATCH V9 06/11] iio: imu: inv_icm42607: Add Buffer support for icm42607
In reply to Chris MorganQuoted 6 lines · On Fri, 29 May 2026 22:17:33 -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]>
A few things inline.
J
Quoted 32 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +26
-0@@ -0,0 +1,483 @@ +// 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/unaligned.h> + +#include <linux/iio/common/inv_sensors_timestamp.h> + +#include "inv_icm42607.h" +#include "inv_icm42607_buffer.h" + +/* FIFO header: 1 byte */ +#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)
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 36
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+ +struct inv_icm42607_fifo_1sensor_packet { +u8 header; +struct inv_icm42607_fifo_sensor_data data; +s8 temp; +} __packed; + +struct inv_icm42607_fifo_2sensors_packet { +u8 header; +struct inv_icm42607_fifo_sensor_data accel;
Good example of the need for the inner structures to be packed
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 47
Quoted 11 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +11
-0+struct inv_icm42607_fifo_sensor_data gyro; +s8 temp; +__be16 timestamp; +} __packed; + +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 =get_unaligned (&packet); +const struct inv_icm42607_fifo_2sensors_packet *pack2 =get_unaligned (&packet);
Hmm. Sashiko points out you are messing around with pointers here and it's not those but what the point to that we need to worry about alignment for.
You could memcpy that data into local structures.
Quoted 104 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +103
-0+u8 header = *((const u8 *)packet); + +/* FIFO empty */ +if (header &INV_ICM42607_FIFO_HEADER_MSG ) { + *accel =NULL ; + *gyro =NULL ; + *temp =NULL ; + *timestamp =NULL ; +return 0 ; + } + +/* accel + gyro */ +if ((header &INV_ICM42607_FIFO_HEADER_ACCEL ) && + (header &INV_ICM42607_FIFO_HEADER_GYRO )) { + *accel = &pack2->accel; + *gyro = &pack2->gyro; + *temp = &pack2->temp; + *timestamp = &pack2->timestamp; +return INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE ; + } + +/* accel only */ +if (header &INV_ICM42607_FIFO_HEADER_ACCEL ) { + *accel = &pack1->data; + *gyro =NULL ; + *temp = &pack1->temp; + *timestamp =NULL ; +return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ; + } + +/* gyro only */ +if (header &INV_ICM42607_FIFO_HEADER_GYRO ) { + *accel =NULL ; + *gyro = &pack1->data; + *temp = &pack1->temp; + *timestamp =NULL ; +return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ; + } + +/* invalid packet if here */ +return -EINVAL ; +} +/** +* 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 */ + 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;
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 230
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+ raw_wm =INV_ICM42607_FIFO_WATERMARK_VAL (wm_size); +memcpy (st->buffer, &raw_wm,sizeof (raw_wm)); + 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 );
set_bits.
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 238
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 );
set_bits
Quoted 28 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +27
-0+if (ret) +return ret; + } + +return 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); + +if (st->fifo.on >1 ) { + st->fifo.on--; +return 0 ; + } + +/* Set FIFO to 0 since iio core ignores teardown errors. */ + st->fifo.on =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;
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 339
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-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; + +/* disable FIFO threshold interrupt */ + ret =regmap_update_bits (st->map,INV_ICM42607_REG_INT_SOURCE0 , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN ,0 );
regmap_clear_bits()
Quoted 25 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +25
-0+if (ret) +return ret; + +return 0 ; +} + +static int inv_icm42607_buffer_postdisable (struct iio_dev *indio_dev) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +struct device *dev =regmap_get_device (st->map); +unsigned int sensor; +unsigned int *watermark; +int ret; + +if (indio_dev == st->indio_gyro) { + sensor =INV_ICM42607_SENSOR_GYRO ; + watermark = &st->fifo.watermark.gyro; + }else if (indio_dev == st->indio_accel) { + sensor =INV_ICM42607_SENSOR_ACCEL ; + watermark = &st->fifo.watermark.accel; + }else { +return -EINVAL ; + } + +mutex_lock (&st->lock);
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 374
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+ +/* +* FIFO enabled at update scan mode for accel or gyro, and +* disabled here. +*/ + ret =inv_icm42607_buffer_set_fifo_en (st, st->fifo.en & ~sensor); +if (ret) + goto out_unlock; + + *watermark =0 ;
Add a comment on why this needs to be set to 0. Normally that only matters at all if the fifo is on, so I guess something unusual here?
Quoted 32 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +31
-0+ ret =inv_icm42607_buffer_update_watermark (st); +if (ret) + goto out_unlock; + +out_unlock: +mutex_unlock (&st->lock); + +pm_runtime_put_autosuspend (dev); + +return ret; +} +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 ; + +/* compute maximum FIFO read size */ +if (max ==0 ) + max_count =sizeof (st->fifo.data);
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 423
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+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 ); +if (ret) +return ret; + st->fifo.count =be16_to_cpup (st->buffer);
Might be ok to assume this is always a multiple of the scan size, but maybe sanity check it to keep sashiko happy and remove that assumption of atomic update.
Quoted 38 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 +0
-0
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h line 51
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +7
-0+ +/* FIFO data packet */ +struct inv_icm42607_fifo_sensor_data { +__be16 x; +__be16 y; +__be16 z; +};
Sashiko is probably correct that this should be packed.
Makes not difference here but it's not aligned in the places it's embedded in other structs and the compiler seeing this will assume it is aligned.
Quoted 19 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +19
-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); + +if (x ==INV_ICM42607_FIFO_DATA_INVALID && + y ==INV_ICM42607_FIFO_DATA_INVALID && + z ==INV_ICM42607_FIFO_DATA_INVALID ) +return false; + +return true; +}
Re: [PATCH V9 06/11] iio: imu: inv_icm42607: Add Buffer support for icm42607
Quoted 48 lines · Jonathan Cameron
Quoted 6 lines · On Fri, 29 May 2026 22:17:33 -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]>A few things inline.
J
Quoted 35 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +29
-0@@ -0,0 +1,483 @@ +// 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/unaligned.h> + +#include <linux/iio/common/inv_sensors_timestamp.h> + +#include "inv_icm42607.h" +#include "inv_icm42607_buffer.h" + +/* FIFO header: 1 byte */ +#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;
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 36
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +7
-0+struct inv_icm42607_fifo_sensor_data data; +s8 temp; +} __packed; + +struct inv_icm42607_fifo_2sensors_packet { +u8 header; +struct inv_icm42607_fifo_sensor_data accel;Good example of the need for the inner structures to be packed
Are you saying I should set the inv_icm42607_fifo_sensor_data to be __packed? I think I was told in a previous patch not to do that, but I can add it back.
Quoted 16 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 47
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +11
-0+struct inv_icm42607_fifo_sensor_data gyro; +s8 temp; +__be16 timestamp; +} __packed; + +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 =get_unaligned (&packet); +const struct inv_icm42607_fifo_2sensors_packet *pack2 =get_unaligned (&packet);Hmm. Sashiko points out you are messing around with pointers here and it's not those but what the point to that we need to worry about alignment for.
You could memcpy that data into local structures.
I still suck at pointers, sorry. What exactly would you recommend here? memcpy the packet value into an allocated inv_icm42607_fifo_1sensor_packet or inv_icm42607_fifo_2sensors_packet?
Quoted 201 lines
Quoted 106 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +103
-0+u8 header = *((const u8 *)packet); + +/* FIFO empty */ +if (header &INV_ICM42607_FIFO_HEADER_MSG ) { + *accel =NULL ; + *gyro =NULL ; + *temp =NULL ; + *timestamp =NULL ; +return 0 ; + } + +/* accel + gyro */ +if ((header &INV_ICM42607_FIFO_HEADER_ACCEL ) && + (header &INV_ICM42607_FIFO_HEADER_GYRO )) { + *accel = &pack2->accel; + *gyro = &pack2->gyro; + *temp = &pack2->temp; + *timestamp = &pack2->timestamp; +return INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE ; + } + +/* accel only */ +if (header &INV_ICM42607_FIFO_HEADER_ACCEL ) { + *accel = &pack1->data; + *gyro =NULL ; + *temp = &pack1->temp; + *timestamp =NULL ; +return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ; + } + +/* gyro only */ +if (header &INV_ICM42607_FIFO_HEADER_GYRO ) { + *accel =NULL ; + *gyro = &pack1->data; + *temp = &pack1->temp; + *timestamp =NULL ; +return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ; + } + +/* invalid packet if here */ +return -EINVAL ; +} +/** +* 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 */ + 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;drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 230
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+ raw_wm =INV_ICM42607_FIFO_WATERMARK_VAL (wm_size); +memcpy (st->buffer, &raw_wm,sizeof (raw_wm)); + 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 );
set_bits.drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 238
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 );
set_bitsQuoted 28 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +27
-0+if (ret) +return ret; + } + +return 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); + +if (st->fifo.on >1 ) { + st->fifo.on--; +return 0 ; + } + +/* Set FIFO to 0 since iio core ignores teardown errors. */ + st->fifo.on =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;drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 339
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-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; + +/* disable FIFO threshold interrupt */ + ret =regmap_update_bits (st->map,INV_ICM42607_REG_INT_SOURCE0 , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN ,0 );
regmap_clear_bits()Quoted 30 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +30
-0+if (ret) +return ret; + +return 0 ; +} + +static int inv_icm42607_buffer_postdisable (struct iio_dev *indio_dev) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +struct device *dev =regmap_get_device (st->map); +unsigned int sensor; +unsigned int *watermark; +int ret; + +if (indio_dev == st->indio_gyro) { + sensor =INV_ICM42607_SENSOR_GYRO ; + watermark = &st->fifo.watermark.gyro; + }else if (indio_dev == st->indio_accel) { + sensor =INV_ICM42607_SENSOR_ACCEL ; + watermark = &st->fifo.watermark.accel; + }else { +return -EINVAL ; + } + +mutex_lock (&st->lock); + +/* +* FIFO enabled at update scan mode for accel or gyro, and +* disabled here. +*/
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 374
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +5
-0+ ret =inv_icm42607_buffer_set_fifo_en (st, st->fifo.en & ~sensor); +if (ret) + goto out_unlock; + + *watermark =0 ;Add a comment on why this needs to be set to 0. Normally that only matters at all if the fifo is on, so I guess something unusual here?
I think it's just resetting the watermark to 0 when shutting down, not 100% sure though.
Quoted 88 lines
Quoted 34 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +31
-0+ ret =inv_icm42607_buffer_update_watermark (st); +if (ret) + goto out_unlock; + +out_unlock: +mutex_unlock (&st->lock); + +pm_runtime_put_autosuspend (dev); + +return ret; +} +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 ; + +/* compute maximum FIFO read size */ +if (max ==0 ) + max_count =sizeof (st->fifo.data);drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 423
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+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 ); +if (ret) +return ret; + st->fifo.count =be16_to_cpup (st->buffer);Might be ok to assume this is always a multiple of the scan size, but maybe sanity check it to keep sashiko happy and remove that assumption of atomic update.
Quoted 38 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 +0
-0
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h line 51
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +7
-0+ +/* FIFO data packet */ +struct inv_icm42607_fifo_sensor_data { +__be16 x; +__be16 y; +__be16 z; +};Sashiko is probably correct that this should be packed.
Makes not difference here but it's not aligned in the places it's embedded in other structs and the compiler seeing this will assume it is aligned.
So I should pack this instead of doing the "get_unaligned()" call? Thank you.
Quoted 20 lines
Quoted 19 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +19
-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); + +if (x ==INV_ICM42607_FIFO_DATA_INVALID && + y ==INV_ICM42607_FIFO_DATA_INVALID && + z ==INV_ICM42607_FIFO_DATA_INVALID ) +return false; + +return true; +}
Jonathan Cameron
maintainerRe: [PATCH V9 06/11] iio: imu: inv_icm42607: Add Buffer support for icm42607
Quoted 58 lines · On Mon, 1 Jun 2026 08:50:02 -0500 Chris Morgan <[email protected]> wrote:
Quoted 48 lines · Jonathan Cameron
Quoted 6 lines · On Fri, 29 May 2026 22:17:33 -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]>A few things inline.
J
Quoted 35 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +29
-0@@ -0,0 +1,483 @@ +// 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/unaligned.h> + +#include <linux/iio/common/inv_sensors_timestamp.h> + +#include "inv_icm42607.h" +#include "inv_icm42607_buffer.h" + +/* FIFO header: 1 byte */ +#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;Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 36
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +7
-0+struct inv_icm42607_fifo_sensor_data data; +s8 temp; +} __packed; + +struct inv_icm42607_fifo_2sensors_packet { +u8 header; +struct inv_icm42607_fifo_sensor_data accel;Good example of the need for the inner structures to be packed
Quoted 3 lines
Are you saying I should set the
inv_icm42607_fifo_sensor_datato be__packed? I think I was told in a previous patch not to do that, but I can add it back.
My understanding is that it is necessary. Just add a comment on why next to the structure. Otherwise typically the compiler assumes they are aligned and doesn't work around that. Alternatively just use an array of u8 and get_unaligned() to extract the values. (read on - on I suspect this is the better path forwards)
Quoted 18 lines
Quoted 17 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 47
Quoted 13 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +11
-0+struct inv_icm42607_fifo_sensor_data gyro; +s8 temp; +__be16 timestamp; +} __packed; + +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 =get_unaligned (&packet); +const struct inv_icm42607_fifo_2sensors_packet *pack2 =get_unaligned (&packet);Hmm. Sashiko points out you are messing around with pointers here and it's not those but what the point to that we need to worry about alignment for.
You could memcpy that data into local structures.
Quoted 3 lines
I still suck at pointers, sorry. What exactly would you recommend here? memcpy the packet value into an allocated
inv_icm42607_fifo_1sensor_packetorinv_icm42607_fifo_2sensors_packet?
yes. Copy it. though given the result has unaligned internal elements so it doesn't really help much. I'm thinking simpler to just treat it as a byte stream and access each element directly.
Quoted 315 lines
Quoted 202 lines
Quoted 107 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +103
-0+u8 header = *((const u8 *)packet); + +/* FIFO empty */ +if (header &INV_ICM42607_FIFO_HEADER_MSG ) { + *accel =NULL ; + *gyro =NULL ; + *temp =NULL ; + *timestamp =NULL ; +return 0 ; + } + +/* accel + gyro */ +if ((header &INV_ICM42607_FIFO_HEADER_ACCEL ) && + (header &INV_ICM42607_FIFO_HEADER_GYRO )) { + *accel = &pack2->accel; + *gyro = &pack2->gyro; + *temp = &pack2->temp; + *timestamp = &pack2->timestamp; +return INV_ICM42607_FIFO_2SENSORS_PACKET_SIZE ; + } + +/* accel only */ +if (header &INV_ICM42607_FIFO_HEADER_ACCEL ) { + *accel = &pack1->data; + *gyro =NULL ; + *temp = &pack1->temp; + *timestamp =NULL ; +return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ; + } + +/* gyro only */ +if (header &INV_ICM42607_FIFO_HEADER_GYRO ) { + *accel =NULL ; + *gyro = &pack1->data; + *temp = &pack1->temp; + *timestamp =NULL ; +return INV_ICM42607_FIFO_1SENSOR_PACKET_SIZE ; + } + +/* invalid packet if here */ +return -EINVAL ; +} +/** +* 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 */ + 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;drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 230
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+ raw_wm =INV_ICM42607_FIFO_WATERMARK_VAL (wm_size); +memcpy (st->buffer, &raw_wm,sizeof (raw_wm)); + 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 );
set_bits.drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 238
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 );
set_bitsQuoted 28 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +27
-0+if (ret) +return ret; + } + +return 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); + +if (st->fifo.on >1 ) { + st->fifo.on--; +return 0 ; + } + +/* Set FIFO to 0 since iio core ignores teardown errors. */ + st->fifo.on =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;drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 339
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-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; + +/* disable FIFO threshold interrupt */ + ret =regmap_update_bits (st->map,INV_ICM42607_REG_INT_SOURCE0 , +INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN ,0 );
regmap_clear_bits()Quoted 30 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +30
-0+if (ret) +return ret; + +return 0 ; +} + +static int inv_icm42607_buffer_postdisable (struct iio_dev *indio_dev) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +struct device *dev =regmap_get_device (st->map); +unsigned int sensor; +unsigned int *watermark; +int ret; + +if (indio_dev == st->indio_gyro) { + sensor =INV_ICM42607_SENSOR_GYRO ; + watermark = &st->fifo.watermark.gyro; + }else if (indio_dev == st->indio_accel) { + sensor =INV_ICM42607_SENSOR_ACCEL ; + watermark = &st->fifo.watermark.accel; + }else { +return -EINVAL ; + } + +mutex_lock (&st->lock); + +/* +* FIFO enabled at update scan mode for accel or gyro, and +* disabled here. +*/ Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 374
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +5
-0+ ret =inv_icm42607_buffer_set_fifo_en (st, st->fifo.en & ~sensor); +if (ret) + goto out_unlock; + + *watermark =0 ;Add a comment on why this needs to be set to 0. Normally that only matters at all if the fifo is on, so I guess something unusual here?
I think it's just resetting the watermark to 0 when shutting down, not 100% sure though.
Quoted 88 lines
Quoted 34 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +31
-0+ ret =inv_icm42607_buffer_update_watermark (st); +if (ret) + goto out_unlock; + +out_unlock: +mutex_unlock (&st->lock); + +pm_runtime_put_autosuspend (dev); + +return ret; +} +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 ; + +/* compute maximum FIFO read size */ +if (max ==0 ) + max_count =sizeof (st->fifo.data);drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c line 423
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c new file +10
-0+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 ); +if (ret) +return ret; + st->fifo.count =be16_to_cpup (st->buffer);Might be ok to assume this is always a multiple of the scan size, but maybe sanity check it to keep sashiko happy and remove that assumption of atomic update.
Quoted 38 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 +0
-0Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h line 51
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.h new file +7
-0+ +/* FIFO data packet */ +struct inv_icm42607_fifo_sensor_data { +__be16 x; +__be16 y; +__be16 z; +};Sashiko is probably correct that this should be packed.
Makes not difference here but it's not aligned in the places it's embedded in other structs and the compiler seeing this will assume it is aligned.
Quoted 1 line
So I should pack this instead of doing the "
get_unaligned()" call?
This whole thing feels like a loosing battle. Just rip the structures out and use defines for the offsets.
Quoted 1 line
Thank you.
PATCH v9 7/11 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 | 81 +++++++++++++++++++ .../iio/imu/inv_icm42607/inv_icm42607_temp.h | 33 ++++++++ 5 files changed, 136 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
@@ -381,6 +381,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
@@ -152,6 +152,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 +81 -0
81 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 V9 07/11] iio: imu: inv_icm42607: Add Temp Support in icm42607
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] State leak: the temperature sensor is explicitly enabled during a raw read but never disabled…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] State leak: the temperature sensor is explicitly enabled during a raw read but never disabled, leaking power if another sensor prevents PM autosuspend. --
commit 4a85771a51be0771ebdaf1ebc5a28b4564534883
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add Temp Support in icm42607
This commit adds functions for reading temperature sensor data to the inv_icm42607 driver.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +0
-0
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +4
-0+static int inv_icm42607_temp_read (struct inv_icm42607_state *st,s16 *temp) +{ +struct device *dev =regmap_get_device (st->map); +__be16 *raw;
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c line 28
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +10
-0+int ret; + +PM_RUNTIME_ACQUIRE_AUTOSUSPEND (dev, pm); + ret =PM_RUNTIME_ACQUIRE_ERR (&pm); +if (ret) +return ret; + +guard (mutex)(&st->lock); + + ret =inv_icm42607_set_temp_conf (st, true,NULL );
[Severity: Medium]
Will this leak the temperature sensor power state?
The temperature sensor is explicitly enabled here for a raw read, but it doesn't appear to be disabled or restored to its previous state before returning.
If another sensor on the same chip (like the accelerometer or gyroscope) is actively streaming and holding a runtime PM reference, autosuspend will be blocked. Does this mean st->conf.temp_en will remain true indefinitely, preventing the accelerometer from using its low-power RC oscillator clock?
Quoted 14 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_temp.c new file +14
-0+if (ret) +return ret; + + raw = &st->buffer[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 ; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=7
PATCH v9 8/11 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 | 36 ++ .../iio/imu/inv_icm42607/inv_icm42607_accel.c | 589 ++++++++++++++++++ .../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, 772 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 +36 -0
@@ -89,12 +89,24 @@ enum inv_icm42607_filter_bw {INV_ICM42607_FILTER_BW_NB }; +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;
@@ -108,6 +120,12 @@ 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.
@@ -118,8 +136,10 @@ struct inv_icm42607_hw {* @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. * @indio_gyro: gyroscope IIO device. * @indio_accel: accelerometer IIO device. +* @timestamp: interrupt timestamps. * @fifo: FIFO management structure. * @buffer: data transfer buffer aligned for DMA. */
@@ -132,8 +152,12 @@ struct inv_icm42607_state {int irq;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 { +s64 accel; + } timestamp;struct inv_icm42607_fifo fifo;__be16 buffer[3 ]__aligned(IIO_DMA_MINALIGN) ; };
@@ -379,8 +403,16 @@ 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);
@@ -388,4 +420,8 @@ 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 +589 -0
589 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 V9 08/11] iio: imu: inv_icm42607: Add Accelerometer for icm42607
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] Concurrency bug and data race in FIFO flush and parsing sequence due to split locking. - [High]…
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Concurrency bug and data race in FIFO flush and parsing sequence due to split locking.
- [High] Self-deadlock in system PM sleep callbacks due to recursive mutex acquisition.
- [High] Unaligned memory access exception caused by casting a misaligned packed structure member. --
commit 60c8a604221a1456a1b6206c583d1e17204ce235
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
[ ... ]
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +2
-0+int inv_icm42607_accel_parse_fifo (struct iio_dev *indio_dev) +{
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +4
-0+/* parse all fifo packets */ +for (i =0 , no =0 ; i < st->fifo.count; i += size, ++no) { + size =inv_icm42607_fifo_decode_packet (&st->fifo.data[i], + &accel, &gyro, &temp, ×tamp, &odr);
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c line 572
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +10
-0+/* quit if error or FIFO is empty */ +if (size <=0 ) +return size; + +/* If the packet size could cause us to overflow, return. */ +if (i + size > st->fifo.count) +return -EIO ; + +/* skip packet if no accel data or data is invalid */ +if (accel ==NULL || !inv_icm42607_fifo_is_data_valid (accel))
[Severity: High]
Will this cause an unaligned memory access trap on architectures with strict alignment requirements?
The accel pointer is populated by inv_icm42607_fifo_decode_packet() which returns the address of pack1->data. Because pack1 is a packed structure with a 1-byte header, the pack1->data pointer sits at an odd address.
When inv_icm42607_fifo_is_data_valid() casts this misaligned pointer to a non-packed structure and accesses 16-bit members via be16_to_cpu(), it could trigger a hardware fault.
Quoted 1 line
drivers/iio/imu/inv_icm42607/inv_icm42607_accel.c new file +1
-0+continue ;
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +0
-0
[ ... ]
Quoted 11 lines
int inv_icm42607_buffer_hwfifo_flush(struct
inv_icm42607_state*st,drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +5
-0unsigned 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);
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_fifo_read(struct inv_icm42607_state *st, · line 526
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +8
-1+if (ret) +return ret; -return ret; +if (st->fifo.nb.total ==0 ) +return 0 ; + +if (st->fifo.nb.accel >0 ) { + ts = &accel_st->ts; +inv_sensors_timestamp_interrupt (ts, st->fifo.nb.accel, accel_ts);
[Severity: High]
Is it safe to access st->fifo.nb and update the timestamp locklessly here?
The preceding call to inv_icm42607_buffer_fifo_read() acquires and then releases st->lock via a scoped guard before returning. Because the lock is dropped, a concurrent sysfs hwfifo_flush or IRQ handler could interleave here and overwrite st->fifo.data and st->fifo.nb before they are parsed, leading to a data race and corrupted timestamp calculations.
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +6
-0+ ret =inv_icm42607_accel_parse_fifo (st->indio_accel); +if (ret) +return ret; + } + +return 0 ; }
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_suspend(struct device *dev) · line 450
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0@@ -383,6 +444,8 @@ static int inv_icm42607_suspend(struct device *dev)guard (mutex)(&st->lock); + st->suspended.accel = st->conf.accel.mode; + st->suspended.temp = st->conf.temp_en;if (pm_runtime_suspended (dev))return 0 ;
[Severity: High]
Could this lead to a self-deadlock?
We acquire st->lock via the scoped guard at the top of inv_icm42607_suspend(). Shortly after this snippet, the function calls pm_runtime_force_suspend() which synchronously executes the driver's runtime PM suspend callback.
If the runtime suspend callback also attempts to acquire st->lock, it will deadlock since the mutex is not recursive. The same locking structure is present in inv_icm42607_resume() with pm_runtime_force_resume().
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=8
PATCH v9 9/11 iio: imu: inv_icm42607: Add IRQ for icm42607
In reply to Chris MorganFrom: Chris Morgan <[email protected]>
Add IRQ support for the icm42607 driver.
--- .../iio/imu/inv_icm42607/inv_icm42607_core.c | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-)
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +96 -1
@@ -331,6 +331,91 @@ static int inv_icm42607_setup(struct inv_icm42607_state *st,return inv_icm42607_set_conf (st, st->hw->conf); } +static irqreturn_t inv_icm42607_irq_timestamp (int irq,void *_data) +{ +struct inv_icm42607_state *st = _data; + + st->timestamp.accel =iio_get_time_ns (st->indio_accel); + +return IRQ_WAKE_THREAD ; +} + +static irqreturn_t inv_icm42607_irq_handler (int irq,void *_data) +{ +struct inv_icm42607_state *st = _data; +struct device *dev =regmap_get_device (st->map); +unsigned int status; +int ret; + +mutex_lock (&st->lock); + + ret =regmap_read (st->map,INV_ICM42607_REG_INT_STATUS , &status); +if (ret) { +dev_err (dev,"Interrut status read error %d\n" , ret); + goto out_unlock; + } + +if (status &INV_ICM42607_INT_STATUS_FIFO_FULL ) +dev_warn (dev,"FIFO full data lost!\n" ); + +if (status &INV_ICM42607_INT_STATUS_FIFO_THS ) { +mutex_unlock (&st->lock); + ret =inv_icm42607_buffer_fifo_read (st,0 ); +if (ret) { +dev_err (dev,"FIFO read error %d\n" , ret); + goto out_unlock; + } + +mutex_lock (&st->lock); + ret =inv_icm42607_buffer_fifo_parse (st); +if (ret) +dev_err (dev,"FIFO parsing error %d\n" , ret); + } + +out_unlock: +mutex_unlock (&st->lock); +return IRQ_HANDLED ; +} + +static int inv_icm42607_irq_init (struct inv_icm42607_state *st,int irq, +int irq_type,bool open_drain) +{ +struct device *dev =regmap_get_device (st->map); +unsigned int val =0 ; +int ret; + +switch (irq_type) { +case IRQF_TRIGGER_RISING : +case IRQF_TRIGGER_HIGH : + val =INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH ; +break ; +default : + val =INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW ; +break ; + } + +switch (irq_type) { +case IRQF_TRIGGER_LOW : +case IRQF_TRIGGER_HIGH : + val |=INV_ICM42607_INT_CONFIG_INT1_LATCHED ; +break ; +default : +break ; + } + +if (!open_drain) + val |=INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL ; + + ret =regmap_write (st->map,INV_ICM42607_REG_INT_CONFIG , val); +if (ret) +return ret; + + irq_type |=IRQF_ONESHOT ; +return devm_request_threaded_irq (dev, irq, inv_icm42607_irq_timestamp, + inv_icm42607_irq_handler, irq_type, + st->hw->name, st); +} +static int inv_icm42607_enable_vddio_reg (struct inv_icm42607_state *st) {int ret;
@@ -367,13 +452,18 @@ int inv_icm42607_core_probe(struct regmap *regmap, {struct device *dev =regmap_get_device (regmap);struct inv_icm42607_state *st; -int irq; +int irq, irq_type; +bool open_drain;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" ); + irq_type =irq_get_trigger_type (irq); + + open_drain =device_property_read_bool (dev,"drive-open-drain" ); + st =devm_kzalloc (dev,sizeof (*st),GFP_KERNEL );if (!st)return -ENOMEM ;
@@ -433,6 +523,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,if (IS_ERR (st->indio_accel))return PTR_ERR (st->indio_accel); +/* Initialize interrupt handling */ + ret =inv_icm42607_irq_init (st, irq, irq_type, open_drain); +if (ret) +return ret; +return 0 ; }EXPORT_SYMBOL_NS_GPL (inv_icm42607_core_probe,"IIO_ICM42607" );
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V9 09/11] iio: imu: inv_icm42607: Add IRQ for icm42607
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] Double unlock of `st->lock` on the error path in `inv_icm42607_irq_handler()`. - [High] The…
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Double unlock of st->lock on the error path in inv_icm42607_irq_handler().
- [High] The threaded interrupt handler will deadlock on the success path due to recursive locking of st->lock.
- [High] The shared st->fifo state is accessed and modified without adequate lock protection across the read-and-parse transaction.
- [Medium] Premature exposure of the IIO device to userspace before IRQ initialization is complete.
--
commit a6721434d04928fac24f103459562cfa31a2c977
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add IRQ for icm42607
Add IRQ support for the icm42607 driver.
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0
[ ... ]
Quoted 1 line
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0@@ -331,6 +331,91 @@ static int inv_icm42607_setup(struct inv_icm42607_state *st,
[ ... ]
Quoted 14 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +14
-0+static irqreturn_t inv_icm42607_irq_handler (int irq,void *_data) +{ +struct inv_icm42607_state *st = _data; +struct device *dev =regmap_get_device (st->map); +unsigned int status; +int ret; + +mutex_lock (&st->lock); + + ret =regmap_read (st->map,INV_ICM42607_REG_INT_STATUS , &status); +if (ret) { +dev_err (dev,"Interrut status read error %d\n" , ret); + goto out_unlock; + }
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_setup(struct inv_icm42607_state *st, · line 366
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+ +if (status &INV_ICM42607_INT_STATUS_FIFO_FULL ) +dev_warn (dev,"FIFO full data lost!\n" ); + +if (status &INV_ICM42607_INT_STATUS_FIFO_THS ) { +mutex_unlock (&st->lock); + ret =inv_icm42607_buffer_fifo_read (st,0 ); +if (ret) { +dev_err (dev,"FIFO read error %d\n" , ret); + goto out_unlock;
[Severity: High]
If inv_icm42607_buffer_fifo_read() fails here, the code jumps to out_unlock while st->lock is already unlocked. Will this cause a double unlock of the mutex at the out_unlock label?
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_setup(struct inv_icm42607_state *st, · line 350
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+ } + +mutex_lock (&st->lock);
[Severity: High]
Will dropping the lock between the read and parse operations expose a race window?
If a concurrent call to inv_icm42607_buffer_hwfifo_flush() interleaves during this unlocked window, it could issue another read and overwrite the contents of st->fifo.data and the sample counts. When the interrupt handler regains the lock and calls inv_icm42607_buffer_fifo_parse(), it might parse the overwritten data instead of the data it originally read.
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_setup(struct inv_icm42607_state *st, · line 370
Quoted 1 line
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +1
-0+ ret =inv_icm42607_buffer_fifo_parse (st);
[Severity: High]
Can this cause a deadlock on the success path?
inv_icm42607_buffer_fifo_parse() eventually delegates to inv_icm42607_accel_parse_fifo(), which uses guard(mutex)(&st->lock) to acquire the exact same lock. Since the lock is already acquired here, won't this result in recursive locking?
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_setup(struct inv_icm42607_state *st, · line 376
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +6
-0+if (ret) +dev_err (dev,"FIFO parsing error %d\n" , ret); + } + +out_unlock: +mutex_unlock (&st->lock);
[Severity: High]
As mentioned above, if we jump here after failing inv_icm42607_buffer_fifo_read(), the lock is already unlocked, causing a double unlock error.
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0+return IRQ_HANDLED ; +}
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, · line 527
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0@@ -433,6 +523,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,if (IS_ERR (st->indio_accel))return PTR_ERR (st->indio_accel); +/* Initialize interrupt handling */ + ret =inv_icm42607_irq_init (st, irq, irq_type, open_drain);
[Severity: Medium]
Is it safe to initialize the interrupt handling after registering the IIO device?
inv_icm42607_accel_init() registers the device, exposing it to userspace. If userspace opens the device and attempts to interact with it before the interrupt is configured, or if inv_icm42607_irq_init() fails causing devres cleanup, could this lead to issues with an actively exposed device?
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+if (ret) +return ret; +return 0 ; }
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
Jonathan Cameron
maintainerRe: [PATCH V9 09/11] iio: imu: inv_icm42607: Add IRQ for icm42607
In reply to Chris MorganQuoted 3 lines · On Fri, 29 May 2026 22:17:36 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add IRQ support for the icm42607 driver.
Note I'm only calling out a few things sashiko commented on. Make sure you verify any others are fixed or false positives.
https://sashiko.dev/#/patchset/20260530031739.109063-1-macroalpha82%40gmail.com
I didn't have anything non sashiko related to add to this patch.
Quoted 26 lines
Signed-off-by Chris Morgan <[email protected]>--- .../iio/imu/inv_icm42607/inv_icm42607_core.c | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-)drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +15
-0+ +static irqreturn_t inv_icm42607_irq_handler (int irq,void *_data) +{ +struct inv_icm42607_state *st = _data; +struct device *dev =regmap_get_device (st->map); +unsigned int status; +int ret; + +mutex_lock (&st->lock); + + ret =regmap_read (st->map,INV_ICM42607_REG_INT_STATUS , &status); +if (ret) { +dev_err (dev,"Interrut status read error %d\n" , ret); + goto out_unlock; + }
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_setup(struct inv_icm42607_state *st, · line 366
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +10
-0+ +if (status &INV_ICM42607_INT_STATUS_FIFO_FULL ) +dev_warn (dev,"FIFO full data lost!\n" ); + +if (status &INV_ICM42607_INT_STATUS_FIFO_THS ) { +mutex_unlock (&st->lock); + ret =inv_icm42607_buffer_fifo_read (st,0 ); +if (ret) { +dev_err (dev,"FIFO read error %d\n" , ret); + goto out_unlock;
Sashiko caught this one.
Lock isn't held. This dance is horrible though. Normally we avoid this by having an unlocked variant of the inner function __inv_icm42607_buffer_fifo_read() and a locked wrapper without the underscores. Or push the lock out of there in general and add a __must_hold() marking so we can detect any paths that don't have the lock.
Quoted 38 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +19
-1+ } + +mutex_lock (&st->lock); + ret =inv_icm42607_buffer_fifo_parse (st); +if (ret) +dev_err (dev,"FIFO parsing error %d\n" , ret); + } + +out_unlock: +mutex_unlock (&st->lock); +return IRQ_HANDLED ; +} +static int inv_icm42607_enable_vddio_reg (struct inv_icm42607_state *st) {int ret;@@ -367,13 +452,18 @@ int inv_icm42607_core_probe(struct regmap *regmap, {struct device *dev =regmap_get_device (regmap);struct inv_icm42607_state *st; -int irq; +int irq, irq_type; +bool open_drain;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" ); + irq_type =irq_get_trigger_type (irq); + + open_drain =device_property_read_bool (dev,"drive-open-drain" ); + st =devm_kzalloc (dev,sizeof (*st),GFP_KERNEL );if (!st)return -ENOMEM ;
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c int inv_icm42607_core_probe(struct regmap *regmap, · line 527
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +2
-0@@ -433,6 +523,11 @@ int inv_icm42607_core_probe(struct regmap *regmap,if (IS_ERR (st->indio_accel))return PTR_ERR (st->indio_accel); +/* Initialize interrupt handling */ + ret =inv_icm42607_irq_init (st, irq, irq_type, open_drain);
Sashiko asks some stuff about ordering wrt to this call. It is relatively unusual to register an irq after the driver is exposed to userspace. Tends to lead to potentially silly races. Can we move it before device registration and rely on presence checks to handle any interrupts that we see before those iio devices are registered?
Quoted 6 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +3
-0+if (ret) +return ret; +return 0 ; }EXPORT_SYMBOL_NS_GPL (inv_icm42607_core_probe,"IIO_ICM42607" );
PATCH v9 10/11 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 | 559 ++++++++++++++++++ 5 files changed, 647 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
@@ -156,6 +156,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;
@@ -413,6 +414,10 @@ 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);
@@ -420,6 +425,10 @@ 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
@@ -389,7 +389,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;
@@ -484,6 +486,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;
@@ -491,6 +494,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;
@@ -507,12 +520,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)
@@ -521,6 +536,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 +559 -0
559 lines not on this page · raw message
Signature · 1 line
2.43.0
[email protected]
AI reviewRe: [PATCH V9 10/11] iio: imu: inv_icm42607: Add Gyroscope to icm42607
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
New issues:
- [Critical] Deadlock in inv_icm42607_gyro_parse_fifo due to recursive mutex acquisition.
- [High] Unconditional dereference of uninitialized st->indio_gyro in inv_icm42607_buffer_hwfifo_flush causes kernel panic during probe.
- [Medium] Gyroscope sensor is left powered on indefinitely after a raw read if the accelerometer buffer is active.
Pre-existing issues:
- [Critical] System suspend and resume callbacks cause a recursive deadlock.
- [High] Double unlock of st->lock in the inv_icm42607_irq_handler error path.
- [High] Data race and unprotected state access during inv_icm42607_buffer_hwfifo_flush exposes software FIFO state to concurrent mutation.
- [High] Unaligned memory access inside inv_icm42607_fifo_is_data_valid causes potential panics on architectures requiring strict alignment. --
commit 337cdabfeb961b7efc61cd16db6efc362ac8652d
Author: Chris Morgan <[email protected]>
iio: imu: inv_icm42607: Add Gyroscope to icm42607
Add gyroscope functions to the icm42607 driver.
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st, · line 530
Quoted 13 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +3
-1@@ -507,12 +520,14 @@ int inv_icm42607_buffer_hwfifo_flush(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);
[Severity: High]
Does this unconditionally dereference an uninitialized pointer during probe?
If a fast userspace process writes to the hwfifo_flush attribute of the accelerometer device after it is registered but before st->indio_gyro is initialized in inv_icm42607_core_probe(), inv_icm42607_buffer_hwfifo_flush() will be triggered. This would cause a kernel panic when calling iio_priv(st->indio_gyro) and iio_get_time_ns(st->indio_gyro) with a NULL pointer.
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_hwfifo_flush(struct inv_icm42607_state *st, · line 539
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +1
-0ret =inv_icm42607_buffer_fifo_read (st, count);if (ret)@@ -521,6 +536,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 ) {
[Severity: High]
This is a pre-existing issue, but does this function expose the software FIFO state to concurrent mutation?
inv_icm42607_buffer_fifo_read() acquires and drops st->lock internally while populating st->fifo. After it returns, inv_icm42607_buffer_hwfifo_flush() accesses st->fifo.nb.gyro and st->fifo.nb.accel without any lock held.
If a concurrent IRQ or concurrent flush occurs in the unguarded window between the return of fifo_read and the re-acquisition of the lock in inv_icm42607_gyro_parse_fifo(), the global st->fifo.data and counters could be overwritten, causing the parser to process corrupted or out-of-bounds data.
Quoted 3 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +0
-0
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c static int inv_icm42607_suspend(struct device *dev) · line 593
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c +1
-0@@ -539,6 +587,7 @@ static int inv_icm42607_suspend(struct device *dev)guard (mutex)(&st->lock); + st->suspended.gyro = st->conf.gyro.mode; st->suspended.accel = st->conf.accel.mode; st->suspended.temp = st->conf.temp_en;if (pm_runtime_suspended (dev))
[Severity: Critical]
This is a pre-existing issue, but does this cause a recursive locking deadlock during system suspend?
inv_icm42607_suspend() acquires the driver lock via guard(mutex)(&st->lock). It then explicitly calls pm_runtime_force_suspend(), which is routed by the PM core to the driver's runtime suspend callback, inv_icm42607_runtime_suspend().
The runtime suspend callback attempts to acquire the exact same lock using guard(mutex)(&st->lock). Since kernel mutexes are not recursive, this will cause an immediate deadlock. The exact same recursive deadlock occurs between inv_icm42607_resume() and pm_runtime_force_resume().
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +0
-0
[ ... ]
Quoted 11 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +11
-0+static int inv_icm42607_gyro_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 *gyro_st =iio_priv (indio_dev); +struct device *dev =regmap_get_device (st->map); +struct inv_icm42607_sensor_conf conf =INV_ICM42607_SENSOR_CONF_INIT ; +unsigned int reg; +__be16 *data; +int ret;
[ ... ]
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 169
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +10
-0+PM_RUNTIME_ACQUIRE_AUTOSUSPEND (dev, pm); + ret =PM_RUNTIME_ACQUIRE_ERR (&pm); +if (ret) +return ret; + +guard (mutex)(&st->lock); + +/* enable gyro sensor */ + conf.mode = gyro_st->power_mode; + ret =inv_icm42607_set_gyro_conf (st, &conf,NULL );
[Severity: Medium]
Is the gyroscope sensor left powered on indefinitely after a raw read if the accelerometer buffer is active?
The gyroscope is explicitly powered on here via inv_icm42607_set_gyro_conf(), and the function relies on the PM autosuspend callback to power it back off when dropping the runtime PM reference. However, if the accelerometer buffer is concurrently active, the overall runtime PM usage count remains greater than 0. As a result, the device will not autosuspend, and the gyroscope sensor is never turned back off, wasting power indefinitely until the accelerometer buffer is disabled.
[ ... ]
Quoted 4 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +4
-0+int inv_icm42607_gyro_parse_fifo (struct iio_dev *indio_dev) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +struct inv_icm42607_sensor_state *gyro_st =iio_priv (indio_dev);
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 527
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +10
-0+struct inv_sensors_timestamp *ts = &gyro_st->ts; +ssize_t i, size; +unsigned int no; +const void *accel, *gyro, *timestamp; +const s8 *temp; +unsigned int odr; +s64 ts_val; +struct inv_icm42607_gyro_buffer buffer = { }; + +guard (mutex)(&st->lock);
[Severity: Critical]
Could this result in a recursive mutex deadlock?
When a hardware FIFO interrupt fires, inv_icm42607_irq_handler() acquires the driver lock via mutex_lock(&st->lock). It then calls inv_icm42607_buffer_fifo_parse(), which delegates to this newly added inv_icm42607_gyro_parse_fifo() function.
Because this function explicitly attempts to acquire the exact same lock using guard(mutex)(&st->lock), and kernel mutexes are not recursive, this will cause an immediate self-deadlock in the threaded IRQ handler, hanging the device.
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +5
-0+ +/* parse all fifo packets */ +for (i =0 , no =0 ; i < st->fifo.count; i += size, ++no) { + size =inv_icm42607_fifo_decode_packet (&st->fifo.data[i], + &accel, &gyro, &temp, ×tamp, &odr);
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 542
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +10
-0+/* quit if error or FIFO is empty */ +if (size <=0 ) +return size; + +/* If the packet size could cause us to overflow, return. */ +if (i + size > st->fifo.count) +return -EIO ; + +/* skip packet if no gyro data or data is invalid */ +if (gyro ==NULL || !inv_icm42607_fifo_is_data_valid (gyro))
[Severity: High]
This is a pre-existing issue, but does this cause an unaligned memory access panic on architectures requiring strict alignment?
inv_icm42607_fifo_decode_packet() assigns an unaligned pointer (&pack1->data, located at offset 1 of inv_icm42607_fifo_1sensor_packet) to the gyro variable.
When inv_icm42607_fifo_is_data_valid() takes this pointer, it casts it to struct inv_icm42607_fifo_sensor_data * and directly dereferences it using be16_to_cpu(s->x). Since struct inv_icm42607_fifo_sensor_data is not marked __packed, the compiler assumes the pointer is 16-bit aligned.
Emitting a 16-bit read instruction against an odd memory address will cause a hardware alignment fault on architectures that do not support unaligned accesses.
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 543
Quoted 1 line
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +1
-0+continue ;
[Severity: High]
This is a pre-existing issue, but is there a double unlock of st->lock in the error path of inv_icm42607_irq_handler()?
If the FIFO_THS interrupt fires, the driver explicitly unlocks st->lock before calling inv_icm42607_buffer_fifo_read():
drivers/iio/imu/inv_icm42607/inv_icm42607_core.c:inv_icm42607_irq_handler()
mutex_unlock(&st->lock);
ret = inv_icm42607_buffer_fifo_read(st, 0);
if (ret) {
dev_err(dev, "FIFO read error %d\n", ret);
goto out_unlock;
}If the read returns an error, it jumps to out_unlock, which unconditionally executes mutex_unlock(&st->lock). Since the lock was already released and never re-acquired, this unlocks an already unlocked mutex.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=10
Jonathan Cameron
maintainerRe: [PATCH V9 10/11] iio: imu: inv_icm42607: Add Gyroscope to icm42607
In reply to Chris MorganQuoted 5 lines · On Fri, 29 May 2026 22:17:37 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add gyroscope functions to the icm42607 driver.
Signed-off-by Chris Morgan <[email protected]>
Hi Chris,
Various things inline.
Thanks,
Jonathan
Quoted 31 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +11
-0int 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;@@ -491,6 +494,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;@@ -507,12 +520,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)
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st) · line 530
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +3
-1{ +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);
Sashiko calls out correctly that there is a race with devices finishing coming up that might be hit here. Probably need some sort of presence check and locking to be sure those are both valid.
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +0
-0ret =inv_icm42607_buffer_fifo_read (st, count);if (ret)drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +0
-0
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 52
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +4
-0+ +static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = { +IIO_MOUNT_MATRIX (IIO_SHARED_BY_ALL , inv_icm42607_get_mount_matrix), + { },
No comma. Check for any other commas after terminating entries like this one.
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +6
-0+}; + +int inv_icm42607_gyro_parse_fifo (struct iio_dev *indio_dev) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +struct inv_icm42607_sensor_state *gyro_st =iio_priv (indio_dev);
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 527
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +10
-0+struct inv_sensors_timestamp *ts = &gyro_st->ts; +ssize_t i, size; +unsigned int no; +const void *accel, *gyro, *timestamp; +const s8 *temp; +unsigned int odr; +s64 ts_val; +struct inv_icm42607_gyro_buffer buffer = { }; + +guard (mutex)(&st->lock);
Sashiko thinks there is a deadlock here as this lock will already be held. Report looks correct to me + same bug in the accelerometer case.
I'm surprised you didn't see them in testing as deadlocks tend to be obvious!
Quoted 32 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +32
-0+ +/* parse all fifo packets */ +for (i =0 , no =0 ; i < st->fifo.count; i += size, ++no) { + size =inv_icm42607_fifo_decode_packet (&st->fifo.data[i], + &accel, &gyro, &temp, ×tamp, &odr); +/* quit if error or FIFO is empty */ +if (size <=0 ) +return size; + +/* If the packet size could cause us to overflow, return. */ +if (i + size > st->fifo.count) +return -EIO ; + +/* skip packet if no gyro data or data is invalid */ +if (gyro ==NULL || !inv_icm42607_fifo_is_data_valid (gyro)) +continue ; + +/* update odr */ +if (odr &INV_ICM42607_SENSOR_GYRO ) +inv_sensors_timestamp_apply_odr (ts, st->fifo.period, + st->fifo.nb.total, no); + +memcpy (&buffer.gyro, gyro,sizeof (buffer.gyro)); +/* convert 8 bits FIFO temperature in high resolution format */ + buffer.temp = temp ? (*temp *64 ) :0 ; + ts_val =inv_sensors_timestamp_pop (ts); +iio_push_to_buffers_with_ts (indio_dev, &buffer, +sizeof (buffer), ts_val); + } + +return 0 ; +}
Re: [PATCH V9 10/11] iio: imu: inv_icm42607: Add Gyroscope to icm42607
Quoted 55 lines · Jonathan Cameron
Quoted 5 lines · On Fri, 29 May 2026 22:17:37 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add gyroscope functions to the icm42607 driver.
Signed-off-by Chris Morgan <[email protected]>Hi Chris,
Various things inline.Thanks,
Jonathan
Quoted 39 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +13
-1int 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;@@ -491,6 +494,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;@@ -507,12 +520,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;
Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st) · line 530
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +1
-0accel_ts =iio_get_time_ns (st->indio_accel); + gyro_ts =iio_get_time_ns (st->indio_gyro);Sashiko calls out correctly that there is a race with devices finishing coming up that might be hit here. Probably need some sort of presence check and locking to be sure those are both valid.
While I'm not sure how to fix this exactly, I think (attempting to) test deadlocks I found a bigger issue... I don't think my interrupt line is hooked up at all...
Assuming I should be getting interrupts when enabling the buffer (and also assuming I can do that with sysfs) I'm not getting any calls to the IRQ routine.
Would you know a better way to test the hardware buffers? Thus far my tests for data correctness involved either monitor-sensor -a or reading the values directly from sysfs.
Assuming I am in fact working with a device with no interrupt line, I can just modify this to remove the hardware buffer stuff and the IRQ stuff and work with an even more simplified driver. Probably going to miss the 7.2 merge window at this time, but still...
Quoted 39 lines
Quoted 12 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +0
-0ret =inv_icm42607_buffer_fifo_read (st, count);if (ret)drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +0
-0drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 52
Quoted 5 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +4
-0+ +static const struct iio_chan_spec_ext_info inv_icm42607_gyro_ext_infos[] = { +IIO_MOUNT_MATRIX (IIO_SHARED_BY_ALL , inv_icm42607_get_mount_matrix), + { },No comma. Check for any other commas after terminating entries like this one.
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +6
-0+}; + +int inv_icm42607_gyro_parse_fifo (struct iio_dev *indio_dev) +{ +struct inv_icm42607_state *st =iio_device_get_drvdata (indio_dev); +struct inv_icm42607_sensor_state *gyro_st =iio_priv (indio_dev);drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 527
Quoted 10 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +10
-0+struct inv_sensors_timestamp *ts = &gyro_st->ts; +ssize_t i, size; +unsigned int no; +const void *accel, *gyro, *timestamp; +const s8 *temp; +unsigned int odr; +s64 ts_val; +struct inv_icm42607_gyro_buffer buffer = { }; + +guard (mutex)(&st->lock);Sashiko thinks there is a deadlock here as this lock will already be held. Report looks correct to me + same bug in the accelerometer case.
Quoted 2 lines
I'm surprised you didn't see them in testing as deadlocks tend to be obvious!
Yeah... about that... turns out my IRQ wasn't firing correctly so I was never hitting this path. I suspect the line isn't even hooked up!
Quoted 25 lines
Quoted 25 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +24
-0+ +/* parse all fifo packets */ +for (i =0 , no =0 ; i < st->fifo.count; i += size, ++no) { + size =inv_icm42607_fifo_decode_packet (&st->fifo.data[i], + &accel, &gyro, &temp, ×tamp, &odr); +/* quit if error or FIFO is empty */ +if (size <=0 ) +return size; + +/* If the packet size could cause us to overflow, return. */ +if (i + size > st->fifo.count) +return -EIO ; + +/* skip packet if no gyro data or data is invalid */ +if (gyro ==NULL || !inv_icm42607_fifo_is_data_valid (gyro)) +continue ; + +/* update odr */ +if (odr &INV_ICM42607_SENSOR_GYRO ) +inv_sensors_timestamp_apply_odr (ts, st->fifo.period, + st->fifo.nb.total, no); + +memcpy (&buffer.gyro, gyro,sizeof (buffer.gyro)); +/* convert 8 bits FIFO temperature in high resolution format */
Quoted 9 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c line 559
Quoted 8 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_gyro.c new file +8
-0+ buffer.temp = temp ? (*temp *64 ) :0 ; + ts_val =inv_sensors_timestamp_pop (ts); +iio_push_to_buffers_with_ts (indio_dev, &buffer, +sizeof (buffer), ts_val); + } + +return 0 ; +}
Thank you again for all your help.
Jonathan Cameron
maintainerRe: [PATCH V9 10/11] iio: imu: inv_icm42607: Add Gyroscope to icm42607
Quoted 64 lines · On Mon, 1 Jun 2026 09:37:56 -0500 Chris Morgan <[email protected]> wrote:
Quoted 55 lines · Jonathan Cameron
Quoted 5 lines · On Fri, 29 May 2026 22:17:37 -0500 Chris Morgan <[email protected]> wrote:
From: Chris Morgan <[email protected]>
Add gyroscope functions to the icm42607 driver.
Signed-off-by Chris Morgan <[email protected]>Hi Chris,
Various things inline.Thanks,
Jonathan
Quoted 39 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +13
-1int 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;@@ -491,6 +494,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;@@ -507,12 +520,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;Quoted 7 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c int inv_icm42607_buffer_fifo_parse(struct inv_icm42607_state *st) · line 530
Quoted 2 lines
drivers/iio/imu/inv_icm42607/inv_icm42607_buffer.c +1
-0accel_ts =iio_get_time_ns (st->indio_accel); + gyro_ts =iio_get_time_ns (st->indio_gyro);Sashiko calls out correctly that there is a race with devices finishing coming up that might be hit here. Probably need some sort of presence check and locking to be sure those are both valid.
Quoted 3 lines
While I'm not sure how to fix this exactly, I think (attempting to) test deadlocks I found a bigger issue... I don't think my interrupt line is hooked up at all...
ouch. Wouldn't be the first time a given device has saved on pins to the extent of not wiring any interrupts.
Quoted 8 lines
Assuming I should be getting interrupts when enabling the buffer (and also assuming I can do that with sysfs) I'm not getting any calls to the IRQ routine.
Would you know a better way to test the hardware buffers? Thus far my tests for data correctness involved either
monitor-sensor -aor reading the values directly from sysfs.
There is a basic buffer example in the kernel tree under tools/iio that should work for this. iio_generic_buffer
Quoted 5 lines
Assuming I am in fact working with a device with no interrupt line, I can just modify this to remove the hardware buffer stuff and the IRQ stuff and work with an even more simplified driver. Probably going to miss the 7.2 merge window at this time, but still...
Indeed an option to do this as a temporary step. If we get other users hopefully someone has the interrupt line wired!
Jonathan
PATCH v9 11/11 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