[PATCH V3 2/9] iio: imu: inv_icm42607: Add Core for inv_icm42607 Driver
Chris Morgan
macroalpha82 at gmail.com
Mon Mar 30 12:58:46 PDT 2026
From: Chris Morgan <macromorgan at hotmail.com>
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.
Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
---
drivers/iio/imu/inv_icm42607/inv_icm42607.h | 424 ++++++++++++++++++
.../iio/imu/inv_icm42607/inv_icm42607_core.c | 300 +++++++++++++
2 files changed, 724 insertions(+)
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607.h
create mode 100644 drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607.h b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
new file mode 100644
index 000000000000..609188c40ffc
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607.h
@@ -0,0 +1,424 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#ifndef INV_ICM42607_H_
+#define INV_ICM42607_H_
+
+#include <linux/bitops.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/common/inv_sensors_timestamp.h>
+
+enum inv_icm42607_chip {
+ INV_CHIP_INVALID,
+ INV_CHIP_ICM42607P,
+ INV_CHIP_ICM42607,
+ INV_CHIP_NB,
+};
+
+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 {
+ /* Low-Noise mode sensor data filter */
+ INV_ICM42607_FILTER_BYPASS,
+ INV_ICM42607_FILTER_BW_180HZ,
+ INV_ICM42607_FILTER_BW_121HZ,
+ INV_ICM42607_FILTER_BW_73HZ,
+ INV_ICM42607_FILTER_BW_53HZ,
+ INV_ICM42607_FILTER_BW_34HZ,
+ INV_ICM42607_FILTER_BW_25HZ,
+ INV_ICM42607_FILTER_BW_16HZ,
+
+ /* Low-Power mode sensor data filter (averaging) */
+ INV_ICM42607_FILTER_AVG_2X = 0,
+ INV_ICM42607_FILTER_AVG_4X,
+ INV_ICM42607_FILTER_AVG_8X,
+ INV_ICM42607_FILTER_AVG_16X,
+ INV_ICM42607_FILTER_AVG_32X,
+ INV_ICM42607_FILTER_AVG_64X,
+};
+
+struct inv_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;
+ struct inv_icm42607_sensor_conf accel;
+ bool temp_en;
+};
+
+struct inv_icm42607_suspended {
+ enum inv_icm42607_sensor_mode gyro;
+ enum inv_icm42607_sensor_mode accel;
+ bool temp;
+};
+
+struct inv_icm42607_apex {
+ unsigned int on;
+ struct {
+ u64 value;
+ bool enable;
+ } wom;
+};
+
+/**
+ * struct inv_icm42607_state - driver state variables
+ * @lock: lock for serializing multiple registers access.
+ * @chip: chip identifier.
+ * @name: chip name.
+ * @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.
+ * @suspended: suspended sensors configuration.
+ * @indio_gyro: gyroscope IIO device.
+ * @indio_accel: accelerometer IIO device.
+ * @timestamp: interrupt timestamps.
+ * @apex: APEX (Advanced Pedometer and Event detection) management
+ * @buffer: data transfer buffer aligned for DMA.
+ */
+struct inv_icm42607_state {
+ struct mutex lock;
+ enum inv_icm42607_chip chip;
+ const char *name;
+ struct regmap *map;
+ struct regulator *vddio_supply;
+ 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 gyro;
+ s64 accel;
+ } timestamp;
+ struct inv_icm42607_apex apex;
+ u8 buffer[3] __aligned(IIO_DMA_MINALIGN);
+};
+
+/**
+ * struct inv_icm42607_sensor_state - sensor state variables
+ * @scales: table of scales.
+ * @scales_len: length (nb of items) of the scales table.
+ * @power_mode: sensor requested power mode (for common frequencies)
+ * @filter: sensor filter.
+ * @ts: timestamp module states.
+ */
+struct inv_icm42607_sensor_state {
+ const int *scales;
+ size_t scales_len;
+ enum inv_icm42607_sensor_mode power_mode;
+ enum inv_icm42607_filter filter;
+ struct inv_sensors_timestamp ts;
+};
+
+/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
+
+/* Register Map for User Bank 0 */
+#define INV_ICM42607_REG_DEVICE_CONFIG 0x01
+#define INV_ICM42607_DEVICE_CONFIG_SPI_AP_4WIRE BIT(2)
+#define INV_ICM42607_DEVICE_CONFIG_SPI_MODE BIT(0)
+
+#define INV_ICM42607_REG_SIGNAL_PATH_RESET 0x02
+#define INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET BIT(4)
+#define INV_ICM42607_SIGNAL_PATH_RESET_FIFO_FLUSH BIT(2)
+
+#define INV_ICM42607_REG_DRIVE_CONFIG1 0x03
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_DDR(_rate) \
+ FIELD_PREP(INV_ICM42607_DRIVE_CONFIG1_I3C_DDR_MASK, (_rate))
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK GENMASK(2, 0)
+#define INV_ICM42607_DRIVE_CONFIG1_I3C_SDR(_rate) \
+ FIELD_PREP(INV_ICM42607_DRIVE_CONFIG1_I3C_SDR_MASK, (_rate))
+
+#define INV_ICM42607_REG_DRIVE_CONFIG2 0x04
+#define INV_ICM42607_DRIVE_CONFIG2_I2C_MASK GENMASK(5, 3)
+#define INV_ICM42607_DRIVE_CONFIG2_I2C(_rate) \
+ FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_I2C_MASK, (_rate))
+#define INV_ICM42607_DRIVE_CONFIG2_ALL_MASK GENMASK(2, 0)
+#define INV_ICM42607_DRIVE_CONFIG2_ALL(_rate) \
+ FIELD_PREP(INV_ICM42607_DRIVE_CONFIG2_ALL_MASK, (_rate))
+
+#define INV_ICM42607_REG_DRIVE_CONFIG3 0x05
+#define INV_ICM42607_DRIVE_CONFIG3_SPI_MASK GENMASK(2, 0)
+#define INV_ICM42607_DRIVE_CONFIG3_SPI(_rate) \
+ FIELD_PREP(INV_ICM42607_DRIVE_CONFIG3_SPI_MASK, (_rate))
+
+#define INV_ICM42607_REG_INT_CONFIG 0x06
+#define INV_ICM42607_INT_CONFIG_INT2_LATCHED BIT(5)
+#define INV_ICM42607_INT_CONFIG_INT2_PUSH_PULL BIT(4)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_HIGH BIT(3)
+#define INV_ICM42607_INT_CONFIG_INT2_ACTIVE_LOW 0x00
+#define INV_ICM42607_INT_CONFIG_INT1_LATCHED BIT(2)
+#define INV_ICM42607_INT_CONFIG_INT1_PUSH_PULL BIT(1)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_HIGH BIT(0)
+#define INV_ICM42607_INT_CONFIG_INT1_ACTIVE_LOW 0x00
+
+/* all sensor data are 16 bits (2 registers wide) in big-endian */
+#define INV_ICM42607_REG_TEMP_DATA1 0x09
+#define INV_ICM42607_REG_TEMP_DATA0 0x0A
+#define INV_ICM42607_REG_ACCEL_DATA_X1 0x0B
+#define INV_ICM42607_REG_ACCEL_DATA_X0 0x0C
+#define INV_ICM42607_REG_ACCEL_DATA_Y1 0x0D
+#define INV_ICM42607_REG_ACCEL_DATA_Y0 0x0E
+#define INV_ICM42607_REG_ACCEL_DATA_Z1 0x0F
+#define INV_ICM42607_REG_ACCEL_DATA_Z0 0x10
+#define INV_ICM42607_REG_GYRO_DATA_X1 0x11
+#define INV_ICM42607_REG_GYRO_DATA_X0 0x12
+#define INV_ICM42607_REG_GYRO_DATA_Y1 0x13
+#define INV_ICM42607_REG_GYRO_DATA_Y0 0x14
+#define INV_ICM42607_REG_GYRO_DATA_Z1 0x15
+#define INV_ICM42607_REG_GYRO_DATA_Z0 0x16
+#define INV_ICM42607_DATA_INVALID -32768
+
+#define INV_ICM42607_REG_TMST_FSYNCH 0x17
+#define INV_ICM42607_REG_TMST_FSYNCL 0x18
+
+/* APEX Data Registers */
+#define INV_ICM42607_REG_APEX_DATA0 0x31
+#define INV_ICM42607_REG_APEX_DATA1 0x32
+#define INV_ICM42607_REG_APEX_DATA2 0x33
+#define INV_ICM42607_REG_APEX_DATA3 0x34
+#define INV_ICM42607_REG_APEX_DATA4 0x1D
+#define INV_ICM42607_REG_APEX_DATA5 0x1E
+
+#define INV_ICM42607_REG_PWR_MGMT0 0x1F
+#define INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL BIT(7)
+#define INV_ICM42607_PWR_MGMT0_IDLE BIT(4)
+#define INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK GENMASK(3, 2)
+#define INV_ICM42607_PWR_MGMT0_GYRO(_mode) \
+ FIELD_PREP(INV_ICM42607_PWR_MGMT0_GYRO_MODE_MASK, (_mode))
+#define INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK GENMASK(1, 0)
+#define INV_ICM42607_PWR_MGMT0_ACCEL(_mode) \
+ FIELD_PREP(INV_ICM42607_PWR_MGMT0_ACCEL_MODE_MASK, (_mode))
+
+#define INV_ICM42607_REG_GYRO_CONFIG0 0x20
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_GYRO_CONFIG0_FS_SEL(_fs) \
+ FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_FS_SEL_MASK, (_fs))
+#define INV_ICM42607_GYRO_CONFIG0_ODR_MASK GENMASK(3, 0)
+#define INV_ICM42607_GYRO_CONFIG0_ODR(_odr) \
+ FIELD_PREP(INV_ICM42607_GYRO_CONFIG0_ODR_MASK, (_odr))
+
+#define INV_ICM42607_REG_ACCEL_CONFIG0 0x21
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK GENMASK(6, 5)
+#define INV_ICM42607_ACCEL_CONFIG0_FS_SEL(_fs) \
+ FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_FS_SEL_MASK, (_fs))
+#define INV_ICM42607_ACCEL_CONFIG0_ODR_MASK GENMASK(3, 0)
+#define INV_ICM42607_ACCEL_CONFIG0_ODR(_odr) \
+ FIELD_PREP(INV_ICM42607_ACCEL_CONFIG0_ODR_MASK, (_odr))
+
+#define INV_ICM42607_REG_TEMP_CONFIG0 0x22
+#define INV_ICM42607_TEMP_CONFIG0_FILTER_MASK GENMASK(6, 4)
+#define INV_ICM42607_TEMP_CONFIG0_FILTER(_filter) \
+ FIELD_PREP(INV_ICM42607_TEMP_CONFIG0_FILTER_MASK, (_filter))
+
+#define INV_ICM42607_REG_GYRO_CONFIG1 0x23
+#define INV_ICM42607_GYRO_CONFIG1_FILTER_MASK GENMASK(2, 0)
+#define INV_ICM42607_GYRO_CONFIG1_FILTER(_filter) \
+ FIELD_PREP(INV_ICM42607_GYRO_CONFIG1_FILTER_MASK, (_filter))
+
+#define INV_ICM42607_REG_ACCEL_CONFIG1 0x24
+#define INV_ICM42607_ACCEL_CONFIG1_AVG_MASK GENMASK(6, 4)
+#define INV_ICM42607_ACCEL_CONFIG1_AVG(_avg) \
+ FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_AVG_MASK, (_avg))
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK GENMASK(2, 0)
+#define INV_ICM42607_ACCEL_CONFIG1_FILTER(_filter) \
+ FIELD_PREP(INV_ICM42607_ACCEL_CONFIG1_FILTER_MASK, (_filter))
+
+#define INV_ICM42607_REG_APEX_CONFIG0 0x25
+#define INV_ICM42607_APEX_CONFIG0_DMP_POWER_SAVE_EN BIT(3)
+#define INV_ICM42607_APEX_CONFIG0_DMP_INIT_EN BIT(2)
+#define INV_ICM42607_APEX_CONFIG0_DMP_MEM_RESET_EN BIT(0)
+
+#define INV_ICM42607_REG_APEX_CONFIG1 0x26
+#define INV_ICM42607_APEX_CONFIG1_SMD_ENABLE BIT(6)
+#define INV_ICM42607_APEX_CONFIG1_FF_ENABLE BIT(5)
+#define INV_ICM42607_APEX_CONFIG1_TILT_ENABLE BIT(4)
+#define INV_ICM42607_APEX_CONFIG1_PED_ENABLE BIT(3)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK GENMASK(1, 0)
+#define INV_ICM42607_APEX_CONFIG1_DMP_ODR(_odr) \
+ FIELD_PREP(INV_ICM42607_APEX_CONFIG1_DMP_ODR_MASK, (_odr))
+
+#define INV_ICM42607_REG_WOM_CONFIG 0x27
+#define INV_ICM42607_WOM_CONFIG_INT_DUR_MASK GENMASK(4, 3)
+#define INV_ICM42607_WOM_CONFIG_INT_DUR(_dur) \
+ FIELD_PREP(INV_ICM42607_WOM_CONFIG_INT_DUR_MASK, (_dur))
+#define INV_ICM42607_WOM_CONFIG_INT_MODE BIT(2)
+#define INV_ICM42607_WOM_CONFIG_MODE BIT(1)
+#define INV_ICM42607_WOM_CONFIG_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG1 0x28
+#define INV_ICM42607_FIFO_CONFIG1_MODE BIT(1)
+#define INV_ICM42607_FIFO_CONFIG1_BYPASS BIT(0)
+
+#define INV_ICM42607_REG_FIFO_CONFIG2 0x29
+#define INV_ICM42607_REG_FIFO_CONFIG3 0x2A
+#define INV_ICM42607_FIFO_WATERMARK_VAL(_wm) \
+ cpu_to_le16((_wm) & GENMASK(11, 0))
+/* FIFO is 2048 bytes, let 12 samples for reading latency */
+#define INV_ICM42607_FIFO_WATERMARK_MAX (2048 - 12 * 16)
+
+#define INV_ICM42607_REG_INT_SOURCE0 0x2B
+#define INV_ICM42607_INT_SOURCE0_ST_INT1_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE0_FSYNC_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE0_PLL_RDY_INT1_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE0_RESET_DONE_INT1_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE0_DRDY_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE0_FIFO_THS_INT1_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE0_FIFO_FULL_INT1_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE0_AGC_RDY_INT1_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE1 0x2C
+#define INV_ICM42607_INT_SOURCE1_I3C_ERROR_INT1_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE1_SMD_INT1_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE1_WOM_INT1_EN GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_SOURCE3 0x2D
+#define INV_ICM42607_INT_SOURCE3_ST_INT2_EN BIT(7)
+#define INV_ICM42607_INT_SOURCE3_FSYNC_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE3_PLL_RDY_INT2_EN BIT(5)
+#define INV_ICM42607_INT_SOURCE3_RESET_DONE_INT2_EN BIT(4)
+#define INV_ICM42607_INT_SOURCE3_DRDY_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE3_FIFO_THS_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE3_FIFO_FULL_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE3_AGC_RDY_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_INT_SOURCE4 0x2E
+#define INV_ICM42607_INT_SOURCE4_I3C_ERROR_INT2_EN BIT(6)
+#define INV_ICM42607_INT_SOURCE4_SMD_INT2_EN BIT(3)
+#define INV_ICM42607_INT_SOURCE4_WOM_Z_INT2_EN BIT(2)
+#define INV_ICM42607_INT_SOURCE4_WOM_Y_INT2_EN BIT(1)
+#define INV_ICM42607_INT_SOURCE4_WOM_X_INT2_EN BIT(0)
+
+#define INV_ICM42607_REG_FIFO_LOST_PKT0 0x2F
+#define INV_ICM42607_REG_FIFO_LOST_PKT1 0x30
+
+#define INV_ICM42607_REG_INTF_CONFIG0 0x35
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_FORMAT BIT(6)
+#define INV_ICM42607_INTF_CONFIG0_FIFO_COUNT_ENDIAN BIT(5)
+#define INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN BIT(4)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_SPI_DIS \
+ FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
+#define INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_I2C_DIS \
+ FIELD_PREP(INV_ICM42607_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
+
+#define INV_ICM42607_REG_INTF_CONFIG1 0x36
+#define INV_ICM42607_INTF_CONFIG1_I3C_SDR_EN BIT(3)
+#define INV_ICM42607_INTF_CONFIG1_I3C_DDR_EN BIT(2)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK GENMASK(1, 0)
+#define INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL \
+ FIELD_PREP(INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK, 1)
+
+#define INV_ICM42607_REG_INT_STATUS_DRDY 0x39
+#define INV_ICM42607_INT_STATUS_DRDY_DATA_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS 0x3A
+#define INV_ICM42607_INT_STATUS_ST BIT(7)
+#define INV_ICM42607_INT_STATUS_FSYNC BIT(6)
+#define INV_ICM42607_INT_STATUS_PLL_RDY BIT(5)
+#define INV_ICM42607_INT_STATUS_RESET_DONE BIT(4)
+#define INV_ICM42607_INT_STATUS_FIFO_THS BIT(2)
+#define INV_ICM42607_INT_STATUS_FIFO_FULL BIT(1)
+#define INV_ICM42607_INT_STATUS_AGC_RDY BIT(0)
+
+#define INV_ICM42607_REG_INT_STATUS2 0x3B
+#define INV_ICM42607_INT_STATUS2_SMD BIT(3)
+#define INV_ICM42607_INT_STATUS2_WOM_INT GENMASK(2, 0)
+
+#define INV_ICM42607_REG_INT_STATUS3 0x3C
+#define INV_ICM42607_INT_STATUS3_STEP_DET BIT(5)
+#define INV_ICM42607_INT_STATUS3_STEP_CNT_OVF BIT(4)
+#define INV_ICM42607_INT_STATUS3_TILT_DET BIT(3)
+#define INV_ICM42607_INT_STATUS3_FF_DET BIT(2)
+
+/*
+ * FIFO access registers
+ * FIFO count is 16 bits (2 registers) big-endian
+ * FIFO data is a continuous read register to read FIFO content
+ */
+#define INV_ICM42607_REG_FIFO_COUNTH 0x3D
+#define INV_ICM42607_REG_FIFO_COUNTL 0x3E
+#define INV_ICM42607_REG_FIFO_DATA 0x3F
+
+#define INV_ICM42607_REG_ACCEL_WOM_X_THR 0x4b
+#define INV_ICM42607_REG_ACCEL_WOM_Y_THR 0x4c
+#define INV_ICM42607_REG_ACCEL_WOM_Z_THR 0x4d
+
+#define INV_ICM42607_REG_WHOAMI 0x75
+#define INV_ICM42607P_WHOAMI 0x60
+#define INV_ICM42607_WHOAMI 0x67
+
+/* Sleep times required by the driver */
+#define INV_ICM42607_POWER_UP_TIME_MS 100
+#define INV_ICM42607_RESET_TIME_MS 1
+#define INV_ICM42607_ACCEL_STARTUP_TIME_MS 20
+#define INV_ICM42607_GYRO_STARTUP_TIME_MS 60
+#define INV_ICM42607_GYRO_STOP_TIME_MS 150
+#define INV_ICM42607_TEMP_STARTUP_TIME_MS 14
+#define INV_ICM42607_SUSPEND_DELAY_MS 2000
+
+typedef int (*inv_icm42607_bus_setup)(struct inv_icm42607_state *);
+
+u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr);
+
+int inv_icm42607_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval);
+
+int inv_icm42607_core_probe(struct regmap *regmap, int chip,
+ inv_icm42607_bus_setup bus_setup);
+
+#endif
diff --git a/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
new file mode 100644
index 000000000000..6b7078387568
--- /dev/null
+++ b/drivers/iio/imu/inv_icm42607/inv_icm42607_core.c
@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 InvenSense, Inc.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+
+#include "inv_icm42607.h"
+
+struct inv_icm42607_hw {
+ uint8_t whoami;
+ const char *name;
+ const struct inv_icm42607_conf *conf;
+};
+
+/* chip initial default configuration */
+static const struct inv_icm42607_conf inv_icm42607_default_conf = {
+ .gyro = {
+ .mode = INV_ICM42607_SENSOR_MODE_OFF,
+ .fs = INV_ICM42607_GYRO_FS_1000DPS,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+ .accel = {
+ .mode = INV_ICM42607_SENSOR_MODE_OFF,
+ .fs = INV_ICM42607_ACCEL_FS_4G,
+ .odr = INV_ICM42607_ODR_100HZ,
+ .filter = INV_ICM42607_FILTER_BW_25HZ,
+ },
+ .temp_en = false,
+};
+
+static const struct inv_icm42607_hw inv_icm42607_hw[INV_CHIP_NB] = {
+ [INV_CHIP_ICM42607] = {
+ .whoami = INV_ICM42607_WHOAMI,
+ .name = "icm42607",
+ .conf = &inv_icm42607_default_conf,
+ },
+ [INV_CHIP_ICM42607P] = {
+ .whoami = INV_ICM42607P_WHOAMI,
+ .name = "icm42607p",
+ .conf = &inv_icm42607_default_conf,
+ },
+};
+
+u32 inv_icm42607_odr_to_period(enum inv_icm42607_odr odr)
+{
+ static u32 odr_periods[INV_ICM42607_ODR_NB] = {
+ /* Reserved values */
+ 0, 0, 0, 0, 0,
+ /* 1600Hz */
+ 625000,
+ /* 800Hz */
+ 1250000,
+ /* 400Hz */
+ 2500000,
+ /* 200Hz */
+ 5000000,
+ /* 100 Hz */
+ 10000000,
+ /* 50Hz */
+ 20000000,
+ /* 25Hz */
+ 40000000,
+ /* 12.5Hz */
+ 80000000,
+ /* 6.25Hz */
+ 160000000,
+ /* 3.125Hz */
+ 320000000,
+ /* 1.5625Hz */
+ 640000000,
+ };
+
+ return odr_periods[odr];
+}
+
+int inv_icm42607_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct inv_icm42607_state *st = iio_device_get_drvdata(indio_dev);
+
+ guard(mutex)(&st->lock);
+
+ if (readval)
+ return regmap_read(st->map, reg, readval);
+
+ return regmap_write(st->map, reg, writeval);
+}
+
+static int inv_icm42607_set_conf(struct inv_icm42607_state *st,
+ const struct inv_icm42607_conf *conf)
+{
+ unsigned int val;
+ int ret;
+
+ val = INV_ICM42607_PWR_MGMT0_GYRO(conf->gyro.mode) |
+ INV_ICM42607_PWR_MGMT0_ACCEL(conf->accel.mode);
+ /*
+ * No temperature enable reg in datasheet, but BSP driver
+ * selected RC oscillator clock in LP mode when temperature
+ * was disabled.
+ */
+ if (!conf->temp_en)
+ val |= INV_ICM42607_PWR_MGMT0_ACCEL_LP_CLK_SEL;
+ ret = regmap_write(st->map, INV_ICM42607_REG_PWR_MGMT0, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_GYRO_CONFIG0_FS_SEL(conf->gyro.fs) |
+ INV_ICM42607_GYRO_CONFIG0_ODR(conf->gyro.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_ACCEL_CONFIG0_FS_SEL(conf->accel.fs) |
+ INV_ICM42607_ACCEL_CONFIG0_ODR(conf->accel.odr);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG0, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_GYRO_CONFIG1_FILTER(conf->gyro.filter);
+ ret = regmap_write(st->map, INV_ICM42607_REG_GYRO_CONFIG1, val);
+ if (ret)
+ return ret;
+
+ val = INV_ICM42607_ACCEL_CONFIG1_FILTER(conf->accel.filter);
+ ret = regmap_write(st->map, INV_ICM42607_REG_ACCEL_CONFIG1, val);
+ if (ret)
+ return ret;
+
+ 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 inv_icm42607_hw *hw = &inv_icm42607_hw[st->chip];
+ const struct device *dev = regmap_get_device(st->map);
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_WHOAMI, &val);
+ if (ret)
+ return ret;
+
+ if (val != hw->whoami)
+ dev_warn_probe(dev, -ENODEV,
+ "invalid whoami %#02x expected %#02x (%s)\n",
+ val, hw->whoami, hw->name);
+
+ st->name = hw->name;
+
+ ret = regmap_write(st->map, INV_ICM42607_REG_SIGNAL_PATH_RESET,
+ INV_ICM42607_SIGNAL_PATH_RESET_SOFT_RESET);
+ if (ret)
+ return ret;
+ msleep(INV_ICM42607_RESET_TIME_MS);
+
+ ret = regmap_read(st->map, INV_ICM42607_REG_INT_STATUS, &val);
+ if (ret)
+ return ret;
+ if (!(val & INV_ICM42607_INT_STATUS_RESET_DONE))
+ return dev_err_probe(dev, -ENODEV,
+ "reset error, reset done bit not set\n");
+
+ ret = bus_setup(st);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG0,
+ INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN,
+ INV_ICM42607_INTF_CONFIG0_SENSOR_DATA_ENDIAN);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->map, INV_ICM42607_REG_INTF_CONFIG1,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_MASK,
+ INV_ICM42607_INTF_CONFIG1_CLKSEL_PLL);
+ if (ret)
+ return ret;
+
+ return inv_icm42607_set_conf(st, hw->conf);
+}
+
+static int inv_icm42607_enable_vddio_reg(struct inv_icm42607_state *st)
+{
+ int ret;
+
+ ret = regulator_enable(st->vddio_supply);
+ if (ret)
+ return ret;
+
+ usleep_range(3000, 4000);
+
+ return 0;
+}
+
+static void inv_icm42607_disable_vddio_reg(void *_data)
+{
+ struct inv_icm42607_state *st = _data;
+
+ regulator_disable(st->vddio_supply);
+}
+
+int inv_icm42607_core_probe(struct regmap *regmap, int chip,
+ inv_icm42607_bus_setup bus_setup)
+{
+ struct device *dev = regmap_get_device(regmap);
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+ struct inv_icm42607_state *st;
+ int irq, irq_type;
+ bool open_drain;
+ int ret;
+
+ if (chip < INV_CHIP_INVALID || chip >= INV_CHIP_NB)
+ dev_warn_probe(dev, -ENODEV,
+ "Invalid chip = %d\n", chip);
+
+ /* get INT1 only supported interrupt or fallback to first interrupt */
+ irq = fwnode_irq_get_byname(fwnode, "INT1");
+ if (irq < 0 && irq != -EPROBE_DEFER) {
+ dev_info(dev, "no INT1 interrupt defined, fallback to first interrupt\n");
+ irq = fwnode_irq_get(fwnode, 0);
+ }
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "error missing INT1 interrupt\n");
+
+ irq_type = irq_get_trigger_type(irq);
+ if (!irq_type)
+ irq_type = IRQF_TRIGGER_FALLING;
+
+ open_drain = device_property_read_bool(dev, "drive-open-drain");
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, st);
+ mutex_init(&st->lock);
+ st->chip = chip;
+ st->map = regmap;
+ st->irq = irq;
+
+ ret = iio_read_mount_matrix(dev, &st->orientation);
+ if (ret) {
+ dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to get vdd regulator\n");
+
+ msleep(INV_ICM42607_POWER_UP_TIME_MS);
+
+ st->vddio_supply = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(st->vddio_supply))
+ return PTR_ERR(st->vddio_supply);
+
+ ret = inv_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);
+
+ return ret;
+}
+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");
--
2.43.0
More information about the Linux-rockchip
mailing list