Re: [PATCH 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver

From: Jonathan Cameron
Date: Thu May 21 2020 - 13:48:12 EST


On Mon, 18 May 2020 14:14:26 +0000
Jean-Baptiste Maneyrol <JManeyrol@xxxxxxxxxxxxxx> wrote:

> Hi Jonathan,
>
> thanks for the feedbacks, I'm sorry but I will not be able to have a correct email formatting to respond you inline.
>
> No problem with all the comments. For iio_device_get_drvdata, it would make more sense to use a const struct iio_dev * as argument. I am obliged to do the pointer conversion since iio_get_mount_matrix requires the use of a const struct iio_dev *.

Absolutely. My argument was that we should change
iio_device_get_drvdata to take a const struct iio_dev * as well.
Seems logical. dev_get_drvdata takes a const device * and
that's all that is being called inside there.

That change can happen in parallel to this set so no problem
if you would rather leave it alone for now.

Jonathan



>
> For resume/suspend, I will add commentaries to explain what it is really doing and for which purpose. Sensor states save and restore will remain in this patch, since it makes more sense to have it as a core functionnality, as much as gyro/accel turn on/off.
>
> Thanks.
> JB
>
>
> From: linux-iio-owner@xxxxxxxxxxxxxxx <linux-iio-owner@xxxxxxxxxxxxxxx> on behalf of Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx>
>
> Sent: Friday, May 8, 2020 15:28
>
> To: Jean-Baptiste Maneyrol <JManeyrol@xxxxxxxxxxxxxx>
>
> Cc: jic23@xxxxxxxxxx <jic23@xxxxxxxxxx>; robh+dt@xxxxxxxxxx <robh+dt@xxxxxxxxxx>; robh@xxxxxxxxxx <robh@xxxxxxxxxx>; mchehab+huawei@xxxxxxxxxx <mchehab+huawei@xxxxxxxxxx>; davem@xxxxxxxxxxxxx <davem@xxxxxxxxxxxxx>; gregkh@xxxxxxxxxxxxxxxxxxx <gregkh@xxxxxxxxxxxxxxxxxxx>;
> linux-iio@xxxxxxxxxxxxxxx <linux-iio@xxxxxxxxxxxxxxx>; devicetree@xxxxxxxxxxxxxxx <devicetree@xxxxxxxxxxxxxxx>; linux-kernel@xxxxxxxxxxxxxxx <linux-kernel@xxxxxxxxxxxxxxx>
>
> Subject: Re: [PATCH 01/12] iio: imu: inv_icm42600: add core of new inv_icm42600 driver
>
> Â
>
>
> ÂCAUTION: This email originated from outside of the organization. Please make sure the sender is who they say they are and do not click links or open attachments unless you recognize the sender and know the content is safe.
>
>
>
> On Thu, 7 May 2020 16:42:11 +0200
>
> Jean-Baptiste Maneyrol <jmaneyrol@xxxxxxxxxxxxxx> wrote:
>
>
>
> > Core component of a new driver for InvenSense ICM-426xx devices.
>
> > It includes registers definition, main probe/setup, and device
>
> > utility functions.
>
> >
>
> > ICM-426xx devices are latest generation of 6-axis IMU,
>
> > gyroscope+accelerometer and temperature sensor. This device
>
> > includes a 2K FIFO, supports I2C/I3C/SPI, and provides
>
> > intelligent motion features like pedometer, tilt detection,
>
> > and tap detection.
>
> >
>
> > Signed-off-by: Jean-Baptiste Maneyrol <jmaneyrol@xxxxxxxxxxxxxx>
>
>
>
> Hi Jean-Baptiste,
>
>
>
> A few minor things inline.
>
>
>
> Thanks,
>
>
>
> Jonathan
>
>
>
> > ---
>
> >Â drivers/iio/imu/inv_icm42600/inv_icm42600.hÂÂ | 372 +++++++++++
>
> > .../iio/imu/inv_icm42600/inv_icm42600_core.c | 618 ++++++++++++++++++
>
> >Â 2 files changed, 990 insertions(+)
>
> >Â create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600.h
>
> >Â create mode 100644 drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
>
> >
>
> > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600.h b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
>
> > new file mode 100644
>
> > index 000000000000..8da4c8249aed
>
> > --- /dev/null
>
> > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600.h
>
> > @@ -0,0 +1,372 @@
>
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
>
> > +/*
>
> > + * Copyright (C) 2020 Invensense, Inc.
>
> > + */
>
> > +
>
> > +#ifndef INV_ICM42600_H_
>
> > +#define INV_ICM42600_H_
>
> > +
>
> > +#include <linux/bits.h>
>
> > +#include <linux/bitfield.h>
>
> > +#include <linux/regmap.h>
>
> > +#include <linux/mutex.h>
>
> > +#include <linux/regulator/consumer.h>
>
> > +#include <linux/pm.h>
>
> > +#include <linux/iio/iio.h>
>
> > +
>
> > +enum inv_icm42600_chip {
>
> > +ÂÂÂÂ INV_CHIP_ICM42600,
>
> > +ÂÂÂÂ INV_CHIP_ICM42602,
>
> > +ÂÂÂÂ INV_CHIP_ICM42605,
>
> > +ÂÂÂÂ INV_CHIP_ICM42622,
>
> > +ÂÂÂÂ INV_CHIP_NB,
>
> > +};
>
> > +
>
> > +/* serial bus slew rates */
>
> > +enum inv_icm42600_slew_rate {
>
> > +ÂÂÂÂ INV_ICM42600_SLEW_RATE_20_60NS,
>
> > +ÂÂÂÂ INV_ICM42600_SLEW_RATE_12_36NS,
>
> > +ÂÂÂÂ INV_ICM42600_SLEW_RATE_6_18NS,
>
> > +ÂÂÂÂ INV_ICM42600_SLEW_RATE_4_12NS,
>
> > +ÂÂÂÂ INV_ICM42600_SLEW_RATE_2_6NS,
>
> > +ÂÂÂÂ INV_ICM42600_SLEW_RATE_INF_2NS,
>
> > +};
>
> > +
>
> > +enum inv_icm42600_sensor_mode {
>
> > +ÂÂÂÂ INV_ICM42600_SENSOR_MODE_OFF,
>
> > +ÂÂÂÂ INV_ICM42600_SENSOR_MODE_STANDBY,
>
> > +ÂÂÂÂ INV_ICM42600_SENSOR_MODE_LOW_POWER,
>
> > +ÂÂÂÂ INV_ICM42600_SENSOR_MODE_LOW_NOISE,
>
> > +ÂÂÂÂ INV_ICM42600_SENSOR_MODE_NB,
>
> > +};
>
> > +
>
> > +/* gyroscope fullscale values */
>
> > +enum inv_icm42600_gyro_fs {
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_2000DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_1000DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_500DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_250DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_125DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_62_5DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_31_25DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_15_625DPS,
>
> > +ÂÂÂÂ INV_ICM42600_GYRO_FS_NB,
>
> > +};
>
> > +
>
> > +/* accelerometer fullscale values */
>
> > +enum inv_icm42600_accel_fs {
>
> > +ÂÂÂÂ INV_ICM42600_ACCEL_FS_16G,
>
> > +ÂÂÂÂ INV_ICM42600_ACCEL_FS_8G,
>
> > +ÂÂÂÂ INV_ICM42600_ACCEL_FS_4G,
>
> > +ÂÂÂÂ INV_ICM42600_ACCEL_FS_2G,
>
> > +ÂÂÂÂ INV_ICM42600_ACCEL_FS_NB,
>
> > +};
>
> > +
>
> > +/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */
>
> > +enum inv_icm42600_odr {
>
> > +ÂÂÂÂ INV_ICM42600_ODR_8KHZ_LN = 3,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_4KHZ_LN,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_2KHZ_LN,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_1KHZ_LN,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_200HZ,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_100HZ,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_50HZ,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_25HZ,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_12_5HZ,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_6_25HZ_LP,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_3_125HZ_LP,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_1_5625HZ_LP,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_500HZ,
>
> > +ÂÂÂÂ INV_ICM42600_ODR_NB,
>
> > +};
>
> > +
>
> > +enum inv_icm42600_filter {
>
> > +ÂÂÂÂ /* Low-Noise mode sensor data filter (3rd order filter by default) */
>
> > +ÂÂÂÂ INV_ICM42600_FILTER_BW_ODR_DIV_2,
>
> > +
>
> > +ÂÂÂÂ /* Low-Power mode sensor data filter (averaging) */
>
> > +ÂÂÂÂ INV_ICM42600_FILTER_AVG_1X = 1,
>
> > +ÂÂÂÂ INV_ICM42600_FILTER_AVG_16X = 6,
>
> > +};
>
> > +
>
> > +struct inv_icm42600_sensor_conf {
>
> > +ÂÂÂÂ int mode;
>
> > +ÂÂÂÂ int fs;
>
> > +ÂÂÂÂ int odr;
>
> > +ÂÂÂÂ int filter;
>
> > +};
>
> > +#define INV_ICM42600_SENSOR_CONF_INITÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ {-1, -1, -1, -1}
>
> > +
>
> > +struct inv_icm42600_conf {
>
> > +ÂÂÂÂ struct inv_icm42600_sensor_conf gyro;
>
> > +ÂÂÂÂ struct inv_icm42600_sensor_conf accel;
>
> > +ÂÂÂÂ bool temp_en;
>
> > +};
>
> > +
>
> > +struct inv_icm42600_suspended {
>
> > +ÂÂÂÂ enum inv_icm42600_sensor_mode gyro;
>
> > +ÂÂÂÂ enum inv_icm42600_sensor_mode accel;
>
> > +ÂÂÂÂ bool temp;
>
> > +};
>
> > +
>
> > +/*
>
> /**
>
>
>
> It's valid kernel doc so lets mark it as such.
>
>
>
> > + *Â struct inv_icm42600_state - driver state variables
>
> > + *Â @lock:ÂÂÂÂÂÂÂÂÂÂ chip access lock.
>
>
>
> Nice to be a bit more specific on that. What about the chip needs
>
> a lock at this level as opposed to bus locks etc?
>
>
>
> > + *Â @chip:ÂÂÂÂÂÂÂÂÂÂ chip identifier.
>
> > + *Â @name:ÂÂÂÂÂÂÂÂÂÂ chip name.
>
> > + *Â @map:ÂÂÂÂÂÂÂÂÂÂÂ regmap pointer.
>
> > + *Â @vdd_supply:ÂÂÂÂ VDD voltage regulator for the chip.
>
> > + *Â @vddio_supply:ÂÂ I/O voltage regulator for the chip.
>
> > + *Â @orientation:ÂÂÂ sensor chip orientation relative to main hardware.
>
> > + *Â @conf:ÂÂÂÂÂÂÂÂÂÂ chip sensors configurations.
>
> > + *Â @suspended:ÂÂÂÂÂÂÂÂÂÂÂÂÂ suspended sensors configuration.
>
> > + */
>
> > +struct inv_icm42600_state {
>
> > +ÂÂÂÂ struct mutex lock;
>
> > +ÂÂÂÂ enum inv_icm42600_chip chip;
>
> > +ÂÂÂÂ const char *name;
>
> > +ÂÂÂÂ struct regmap *map;
>
> > +ÂÂÂÂ struct regulator *vdd_supply;
>
> > +ÂÂÂÂ struct regulator *vddio_supply;
>
> > +ÂÂÂÂ struct iio_mount_matrix orientation;
>
> > +ÂÂÂÂ struct inv_icm42600_conf conf;
>
> > +ÂÂÂÂ struct inv_icm42600_suspended suspended;
>
> > +};
>
> > +
>
> > +/* Virtual register addresses: @bank on MSB (4 upper bits), @address on LSB */
>
> > +
>
> > +/* Bank selection register, available in all banks */
>
> > +#define INV_ICM42600_REG_BANK_SELÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x76
>
> > +#define INV_ICM42600_BANK_SEL_MASKÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ GENMASK(2, 0)
>
> > +
>
> > +/* User bank 0 (MSB 0x00) */
>
> > +#define INV_ICM42600_REG_DEVICE_CONFIGÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0011
>
> > +#define INV_ICM42600_DEVICE_CONFIG_SOFT_RESETÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
>
> > +
>
> > +#define INV_ICM42600_REG_DRIVE_CONFIGÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0013
>
> > +#define INV_ICM42600_DRIVE_CONFIG_I2C_MASKÂÂÂÂÂÂÂÂÂÂ GENMASK(5, 3)
>
> > +#define INV_ICM42600_DRIVE_CONFIG_I2C(_rate)ÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(INV_ICM42600_DRIVE_CONFIG_I2C_MASK, (_rate))
>
> > +#define INV_ICM42600_DRIVE_CONFIG_SPI_MASKÂÂÂÂÂÂÂÂÂÂ GENMASK(2, 0)
>
> > +#define INV_ICM42600_DRIVE_CONFIG_SPI(_rate)ÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(INV_ICM42600_DRIVE_CONFIG_SPI_MASK, (_rate))
>
> > +
>
> > +#define INV_ICM42600_REG_INT_CONFIGÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0014
>
> > +#define INV_ICM42600_INT_CONFIG_INT2_LATCHEDÂÂÂÂÂÂÂÂ BIT(5)
>
> > +#define INV_ICM42600_INT_CONFIG_INT2_PUSH_PULLÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
>
> > +#define INV_ICM42600_INT_CONFIG_INT2_ACTIVE_HIGHÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_INT_CONFIG_INT2_ACTIVE_LOWÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x00
>
> > +#define INV_ICM42600_INT_CONFIG_INT1_LATCHEDÂÂÂÂÂÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_INT_CONFIG_INT1_PUSH_PULLÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
>
> > +#define INV_ICM42600_INT_CONFIG_INT1_ACTIVE_HIGHÂÂÂÂ BIT(0)
>
> > +#define INV_ICM42600_INT_CONFIG_INT1_ACTIVE_LOWÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x00
>
> > +
>
> > +#define INV_ICM42600_REG_FIFO_CONFIGÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0016
>
> > +#define INV_ICM42600_FIFO_CONFIG_MASKÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ GENMASK(7, 6)
>
> > +#define INV_ICM42600_FIFO_CONFIG_BYPASSÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(INV_ICM42600_FIFO_CONFIG_MASK, 0)
>
> > +#define INV_ICM42600_FIFO_CONFIG_STREAMÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(INV_ICM42600_FIFO_CONFIG_MASK, 1)
>
> > +#define INV_ICM42600_FIFO_CONFIG_STOP_ON_FULLÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(INV_ICM42600_FIFO_CONFIG_MASK, 2)
>
> > +
>
> > +/* all sensor data are 16 bits (2 registers wide) in big-endian */
>
> > +#define INV_ICM42600_REG_TEMP_DATAÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x001D
>
> > +#define INV_ICM42600_REG_ACCEL_DATA_XÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x001F
>
> > +#define INV_ICM42600_REG_ACCEL_DATA_YÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0021
>
> > +#define INV_ICM42600_REG_ACCEL_DATA_ZÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0023
>
> > +#define INV_ICM42600_REG_GYRO_DATA_XÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0025
>
> > +#define INV_ICM42600_REG_GYRO_DATA_YÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0027
>
> > +#define INV_ICM42600_REG_GYRO_DATA_ZÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0029
>
> > +#define INV_ICM42600_DATA_INVALIDÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ -32768
>
> > +
>
> > +#define INV_ICM42600_REG_INT_STATUSÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x002D
>
> > +#define INV_ICM42600_INT_STATUS_UI_FSYNCÂÂÂÂÂÂÂÂÂÂÂÂ BIT(6)
>
> > +#define INV_ICM42600_INT_STATUS_PLL_RDYÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(5)
>
> > +#define INV_ICM42600_INT_STATUS_RESET_DONEÂÂÂÂÂÂÂÂÂÂ BIT(4)
>
> > +#define INV_ICM42600_INT_STATUS_DATA_RDYÂÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_INT_STATUS_FIFO_THSÂÂÂÂÂÂÂÂÂÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_INT_STATUS_FIFO_FULLÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
>
> > +#define INV_ICM42600_INT_STATUS_AGC_RDYÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
>
> > +
>
> > +/*
>
> > + * 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_ICM42600_REG_FIFO_COUNTÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x002E
>
> > +#define INV_ICM42600_REG_FIFO_DATAÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0030
>
> > +
>
> > +#define INV_ICM42600_REG_SIGNAL_PATH_RESETÂÂÂÂÂÂÂÂÂÂ 0x004B
>
> > +#define INV_ICM42600_SIGNAL_PATH_RESET_DMP_INIT_ENÂÂ BIT(6)
>
> > +#define INV_ICM42600_SIGNAL_PATH_RESET_DMP_MEM_RESET BIT(5)
>
> > +#define INV_ICM42600_SIGNAL_PATH_RESET_RESETÂÂÂÂÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_SIGNAL_PATH_RESET_TMST_STROBEÂÂ BIT(2)
>
> > +#define INV_ICM42600_SIGNAL_PATH_RESET_FIFO_FLUSHÂÂÂ BIT(1)
>
> > +
>
> > +/* default configuration: all data big-endian and fifo count in bytes */
>
> > +#define INV_ICM42600_REG_INTF_CONFIG0ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x004C
>
> > +#define INV_ICM42600_INTF_CONFIG0_FIFO_HOLD_LAST_DATAÂÂÂÂÂÂÂ BIT(7)
>
> > +#define INV_ICM42600_INTF_CONFIG0_FIFO_COUNT_RECÂÂÂÂ BIT(6)
>
> > +#define INV_ICM42600_INTF_CONFIG0_FIFO_COUNT_ENDIANÂ BIT(5)
>
> > +#define INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN BIT(4)
>
> > +#define INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASKÂÂ GENMASK(1, 0)
>
> > +#define INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_SPI_DISÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, 2)
>
> > +#define INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_I2C_DISÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(INV_ICM42600_INTF_CONFIG0_UI_SIFS_CFG_MASK, 3)
>
> > +
>
> > +#define INV_ICM42600_REG_INTF_CONFIG1ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x004D
>
> > +#define INV_ICM42600_INTF_CONFIG1_ACCEL_LP_CLK_RCÂÂÂ BIT(3)
>
> > +
>
> > +#define INV_ICM42600_REG_PWR_MGMT0ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x004E
>
> > +#define INV_ICM42600_PWR_MGMT0_TEMP_DISÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(5)
>
> > +#define INV_ICM42600_PWR_MGMT0_IDLEÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
>
> > +#define INV_ICM42600_PWR_MGMT0_GYRO(_mode)ÂÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(3, 2), (_mode))
>
> > +#define INV_ICM42600_PWR_MGMT0_ACCEL(_mode)ÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(1, 0), (_mode))
>
> > +
>
> > +#define INV_ICM42600_REG_GYRO_CONFIG0ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x004F
>
> > +#define INV_ICM42600_GYRO_CONFIG0_FS(_fs)ÂÂÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(7, 5), (_fs))
>
> > +#define INV_ICM42600_GYRO_CONFIG0_ODR(_odr)ÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(3, 0), (_odr))
>
> > +
>
> > +#define INV_ICM42600_REG_ACCEL_CONFIG0ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0050
>
> > +#define INV_ICM42600_ACCEL_CONFIG0_FS(_fs)ÂÂÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(7, 5), (_fs))
>
> > +#define INV_ICM42600_ACCEL_CONFIG0_ODR(_odr)ÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(3, 0), (_odr))
>
> > +
>
> > +#define INV_ICM42600_REG_GYRO_ACCEL_CONFIG0ÂÂÂÂÂÂÂÂÂ 0x0052
>
> > +#define INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(_f)ÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(7, 4), (_f))
>
> > +#define INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(_f)ÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ FIELD_PREP(GENMASK(3, 0), (_f))
>
> > +
>
> > +#define INV_ICM42600_REG_TMST_CONFIGÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0054
>
> > +#define INV_ICM42600_TMST_CONFIG_MASKÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ GENMASK(4, 0)
>
> > +#define INV_ICM42600_TMST_CONFIG_TMST_TO_REGS_ENÂÂÂÂ BIT(4)
>
> > +#define INV_ICM42600_TMST_CONFIG_TMST_RES_16USÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_TMST_CONFIG_TMST_DELTA_ENÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_TMST_CONFIG_TMST_FSYNC_ENÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
>
> > +#define INV_ICM42600_TMST_CONFIG_TMST_ENÂÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
>
> > +
>
> > +#define INV_ICM42600_REG_FIFO_CONFIG1ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x005F
>
> > +#define INV_ICM42600_FIFO_CONFIG1_RESUME_PARTIAL_RDÂ BIT(6)
>
> > +#define INV_ICM42600_FIFO_CONFIG1_WM_GT_THÂÂÂÂÂÂÂÂÂÂ BIT(5)
>
> > +#define INV_ICM42600_FIFO_CONFIG1_TMST_FSYNC_ENÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_FIFO_CONFIG1_TEMP_ENÂÂÂÂÂÂÂÂÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_FIFO_CONFIG1_GYRO_ENÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
>
> > +#define INV_ICM42600_FIFO_CONFIG1_ACCEL_ENÂÂÂÂÂÂÂÂÂÂ BIT(0)
>
> > +
>
> > +/* FIFO watermark is 16 bits (2 registers wide) in little-endian */
>
> > +#define INV_ICM42600_REG_FIFO_WATERMARKÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0060
>
> > +#define INV_ICM42600_FIFO_WATERMARK_VAL(_wm)ÂÂÂÂÂÂÂÂ \
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ cpu_to_le16((_wm) & GENMASK(11, 0))
>
> > +/* FIFO is 2048 bytes, let 12 samples for reading latency */
>
> > +#define INV_ICM42600_FIFO_WATERMARK_MAXÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ (2048 - 12 * 16)
>
> > +
>
> > +#define INV_ICM42600_REG_INT_CONFIG1ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0064
>
> > +#define INV_ICM42600_INT_CONFIG1_TPULSE_DURATIONÂÂÂÂ BIT(6)
>
> > +#define INV_ICM42600_INT_CONFIG1_TDEASSERT_DISABLEÂÂ BIT(5)
>
> > +#define INV_ICM42600_INT_CONFIG1_ASYNC_RESETÂÂÂÂÂÂÂÂ BIT(4)
>
> > +
>
> > +#define INV_ICM42600_REG_INT_SOURCE0ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0065
>
> > +#define INV_ICM42600_INT_SOURCE0_UI_FSYNC_INT1_ENÂÂÂ BIT(6)
>
> > +#define INV_ICM42600_INT_SOURCE0_PLL_RDY_INT1_ENÂÂÂÂ BIT(5)
>
> > +#define INV_ICM42600_INT_SOURCE0_RESET_DONE_INT1_ENÂ BIT(4)
>
> > +#define INV_ICM42600_INT_SOURCE0_UI_DRDY_INT1_ENÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_INT_SOURCE0_FIFO_THS_INT1_ENÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_INT_SOURCE0_FIFO_FULL_INT1_ENÂÂ BIT(1)
>
> > +#define INV_ICM42600_INT_SOURCE0_UI_AGC_RDY_INT1_ENÂ BIT(0)
>
> > +
>
> > +#define INV_ICM42600_REG_WHOAMIÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x0075
>
> > +#define INV_ICM42600_WHOAMI_ICM42600ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x40
>
> > +#define INV_ICM42600_WHOAMI_ICM42602ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x41
>
> > +#define INV_ICM42600_WHOAMI_ICM42605ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x42
>
> > +#define INV_ICM42600_WHOAMI_ICM42622ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x46
>
> > +
>
> > +/* User bank 1 (MSB 0x10) */
>
> > +#define INV_ICM42600_REG_SENSOR_CONFIG0ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x1003
>
> > +#define INV_ICM42600_SENSOR_CONFIG0_ZG_DISABLEÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(5)
>
> > +#define INV_ICM42600_SENSOR_CONFIG0_YG_DISABLEÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
>
> > +#define INV_ICM42600_SENSOR_CONFIG0_XG_DISABLEÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_SENSOR_CONFIG0_ZA_DISABLEÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_SENSOR_CONFIG0_YA_DISABLEÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
>
> > +#define INV_ICM42600_SENSOR_CONFIG0_XA_DISABLEÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
>
> > +
>
> > +/* Timestamp value is 20 bits (3 registers) in little-endian */
>
> > +#define INV_ICM42600_REG_TMSTVALÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x1062
>
> > +#define INV_ICM42600_TMSTVAL_MASKÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ GENMASK(19, 0)
>
> > +
>
> > +#define INV_ICM42600_REG_INTF_CONFIG4ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x107A
>
> > +#define INV_ICM42600_INTF_CONFIG4_I3C_BUS_ONLYÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(6)
>
> > +#define INV_ICM42600_INTF_CONFIG4_SPI_AP_4WIREÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
>
> > +
>
> > +#define INV_ICM42600_REG_INTF_CONFIG6ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x107C
>
> > +#define INV_ICM42600_INTF_CONFIG6_MASKÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ GENMASK(4, 0)
>
> > +#define INV_ICM42600_INTF_CONFIG6_I3C_ENÂÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
>
> > +#define INV_ICM42600_INTF_CONFIG6_I3C_IBI_BYTE_ENÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_INTF_CONFIG6_I3C_IBI_ENÂÂÂÂÂÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_INTF_CONFIG6_I3C_DDR_ENÂÂÂÂÂÂÂÂ BIT(1)
>
> > +#define INV_ICM42600_INTF_CONFIG6_I3C_SDR_ENÂÂÂÂÂÂÂÂ BIT(0)
>
> > +
>
> > +/* User bank 4 (MSB 0x40) */
>
> > +#define INV_ICM42600_REG_INT_SOURCE8ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x404F
>
> > +#define INV_ICM42600_INT_SOURCE8_FSYNC_IBI_ENÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(5)
>
> > +#define INV_ICM42600_INT_SOURCE8_PLL_RDY_IBI_ENÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
>
> > +#define INV_ICM42600_INT_SOURCE8_UI_DRDY_IBI_ENÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
>
> > +#define INV_ICM42600_INT_SOURCE8_FIFO_THS_IBI_ENÂÂÂÂ BIT(2)
>
> > +#define INV_ICM42600_INT_SOURCE8_FIFO_FULL_IBI_ENÂÂÂ BIT(1)
>
> > +#define INV_ICM42600_INT_SOURCE8_AGC_RDY_IBI_ENÂÂÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
>
> > +
>
> > +#define INV_ICM42600_REG_OFFSET_USER0ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x4077
>
> > +#define INV_ICM42600_REG_OFFSET_USER1ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x4078
>
> > +#define INV_ICM42600_REG_OFFSET_USER2ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x4079
>
> > +#define INV_ICM42600_REG_OFFSET_USER3ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x407A
>
> > +#define INV_ICM42600_REG_OFFSET_USER4ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x407B
>
> > +#define INV_ICM42600_REG_OFFSET_USER5ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x407C
>
> > +#define INV_ICM42600_REG_OFFSET_USER6ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x407D
>
> > +#define INV_ICM42600_REG_OFFSET_USER7ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x407E
>
> > +#define INV_ICM42600_REG_OFFSET_USER8ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 0x407F
>
> > +
>
> > +/* Sleep times required by the driver */
>
> > +#define INV_ICM42600_POWER_UP_TIME_MSÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 100
>
> > +#define INV_ICM42600_RESET_TIME_MSÂÂÂÂÂÂÂÂÂÂ 1
>
> > +#define INV_ICM42600_ACCEL_STARTUP_TIME_MSÂÂ 20
>
> > +#define INV_ICM42600_GYRO_STARTUP_TIME_MSÂÂÂ 60
>
> > +#define INV_ICM42600_GYRO_STOP_TIME_MSÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 150
>
> > +#define INV_ICM42600_TEMP_STARTUP_TIME_MSÂÂÂ 14
>
> > +#define INV_ICM42600_SUSPEND_DELAY_MSÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ 2000
>
> > +
>
> > +typedef int (*inv_icm42600_bus_setup)(struct inv_icm42600_state *);
>
> > +
>
> > +extern const struct regmap_config inv_icm42600_regmap_config;
>
> > +extern const struct dev_pm_ops inv_icm42600_pm_ops;
>
> > +
>
> > +const struct iio_mount_matrix *
>
> > +inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ const struct iio_chan_spec *chan);
>
> > +
>
> > +uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr);
>
> > +
>
> > +int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct inv_icm42600_sensor_conf *conf,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int *sleep);
>
> > +
>
> > +int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct inv_icm42600_sensor_conf *conf,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int *sleep);
>
> > +
>
> > +int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int *sleep);
>
> > +
>
> > +int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int writeval, unsigned int *readval);
>
> > +
>
> > +int inv_icm42600_core_probe(struct regmap *regmap, int chip,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_bus_setup bus_setup);
>
> > +
>
> > +#endif
>
> > diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
>
> > new file mode 100644
>
> > index 000000000000..35bdf4f9d31e
>
> > --- /dev/null
>
> > +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_core.c
>
> > @@ -0,0 +1,618 @@
>
> > +// SPDX-License-Identifier: GPL-2.0-or-later
>
> > +/*
>
> > + * Copyright (C) 2020 Invensense, Inc.
>
> > + */
>
> > +
>
> > +#include <linux/device.h>
>
> > +#include <linux/module.h>
>
> > +#include <linux/slab.h>
>
> > +#include <linux/delay.h>
>
> > +#include <linux/interrupt.h>
>
> > +#include <linux/regulator/consumer.h>
>
> > +#include <linux/pm_runtime.h>
>
> > +#include <linux/regmap.h>
>
> > +#include <linux/iio/iio.h>
>
> > +
>
> > +#include "inv_icm42600.h"
>
> > +
>
> > +static const struct regmap_range_cfg inv_icm42600_regmap_ranges[] = {
>
> > +ÂÂÂÂ {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .name = "user banks",
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .range_min = 0x0000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .range_max = 0x4FFF,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .selector_reg = INV_ICM42600_REG_BANK_SEL,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .selector_mask = INV_ICM42600_BANK_SEL_MASK,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .selector_shift = 0,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .window_start = 0,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .window_len = 0x1000,
>
> > +ÂÂÂÂ },
>
> > +};
>
> > +
>
> > +const struct regmap_config inv_icm42600_regmap_config = {
>
> > +ÂÂÂÂ .reg_bits = 8,
>
> > +ÂÂÂÂ .val_bits = 8,
>
> > +ÂÂÂÂ .max_register = 0x4FFF,
>
> > +ÂÂÂÂ .ranges = inv_icm42600_regmap_ranges,
>
> > +ÂÂÂÂ .num_ranges = ARRAY_SIZE(inv_icm42600_regmap_ranges),
>
> > +};
>
> > +EXPORT_SYMBOL_GPL(inv_icm42600_regmap_config);
>
> > +
>
> > +struct inv_icm42600_hw {
>
> > +ÂÂÂÂ uint8_t whoami;
>
> > +ÂÂÂÂ const char *name;
>
> > +ÂÂÂÂ const struct inv_icm42600_conf *conf;
>
> > +};
>
> > +
>
> > +/* chip initial default configuration */
>
> > +static const struct inv_icm42600_conf inv_icm42600_default_conf = {
>
> > +ÂÂÂÂ .gyro = {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .mode = INV_ICM42600_SENSOR_MODE_OFF,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .fs = INV_ICM42600_GYRO_FS_2000DPS,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .odr = INV_ICM42600_ODR_50HZ,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
>
> > +ÂÂÂÂ },
>
> > +ÂÂÂÂ .accel = {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .mode = INV_ICM42600_SENSOR_MODE_OFF,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .fs = INV_ICM42600_ACCEL_FS_16G,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .odr = INV_ICM42600_ODR_50HZ,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .filter = INV_ICM42600_FILTER_BW_ODR_DIV_2,
>
> > +ÂÂÂÂ },
>
> > +ÂÂÂÂ .temp_en = false,
>
> > +};
>
> > +
>
> > +static const struct inv_icm42600_hw inv_icm42600_hw[] = {
>
> > +ÂÂÂÂ [INV_CHIP_ICM42600] = {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .whoami = INV_ICM42600_WHOAMI_ICM42600,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .name = "icm42600",
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .conf = &inv_icm42600_default_conf,
>
> > +ÂÂÂÂ },
>
> > +ÂÂÂÂ [INV_CHIP_ICM42602] = {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .whoami = INV_ICM42600_WHOAMI_ICM42602,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .name = "icm42602",
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .conf = &inv_icm42600_default_conf,
>
> > +ÂÂÂÂ },
>
> > +ÂÂÂÂ [INV_CHIP_ICM42605] = {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .whoami = INV_ICM42600_WHOAMI_ICM42605,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .name = "icm42605",
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .conf = &inv_icm42600_default_conf,
>
> > +ÂÂÂÂ },
>
> > +ÂÂÂÂ [INV_CHIP_ICM42622] = {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .whoami = INV_ICM42600_WHOAMI_ICM42622,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .name = "icm42622",
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ .conf = &inv_icm42600_default_conf,
>
> > +ÂÂÂÂ },
>
> > +};
>
> > +
>
> > +const struct iio_mount_matrix *
>
> > +inv_icm42600_get_mount_matrix(const struct iio_dev *indio_dev,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ const struct iio_chan_spec *chan)
>
> > +{
>
> > +ÂÂÂÂ const struct inv_icm42600_state *st =
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ iio_device_get_drvdata((struct iio_dev *)indio_dev);
>
>
>
> Interesting... iio_device_get_drvdata is never going to modify
>
> the struct iio_dev. Should we just change that to take a
>
> const struct iio_dev * ?
>
>
>
> > +
>
> > +ÂÂÂÂ return &st->orientation;
>
> > +}
>
> > +
>
> > +uint32_t inv_icm42600_odr_to_period(enum inv_icm42600_odr odr)
>
> > +{
>
> > +ÂÂÂÂ static uint32_t odr_periods[INV_ICM42600_ODR_NB] = {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* reserved values */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 0, 0, 0,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 8kHz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 125000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 4kHz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 250000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 2kHz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 500000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 1kHz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 1000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 200Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 5000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 100Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 10000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 50Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 20000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 25Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 40000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 12.5Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 80000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 6.25Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 160000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 3.125Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 320000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 1.5625Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 640000000,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* 500Hz */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ 2000000,
>
> > +ÂÂÂÂ };
>
> > +
>
> > +ÂÂÂÂ return odr_periods[odr];
>
> > +}
>
> > +
>
> > +static int inv_icm42600_set_pwr_mgmt0(struct inv_icm42600_state *st,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ enum inv_icm42600_sensor_mode gyro,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ enum inv_icm42600_sensor_mode accel,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ bool temp, unsigned int *sleep)
>
>
>
> msleep or similar that indicates the units of the sleep time.
>
>
>
> > +{
>
> > +ÂÂÂÂ enum inv_icm42600_sensor_mode oldgyro = st->conf.gyro.mode;
>
> > +ÂÂÂÂ enum inv_icm42600_sensor_mode oldaccel = st->conf.accel.mode;
>
> > +ÂÂÂÂ bool oldtemp = st->conf.temp_en;
>
> > +ÂÂÂÂ unsigned int sleepval;
>
> > +ÂÂÂÂ unsigned int val;
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ /* if nothing changed, exit */
>
> > +ÂÂÂÂ if (gyro == oldgyro && accel == oldaccel && temp == oldtemp)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return 0;
>
> > +
>
> > +ÂÂÂÂ val = INV_ICM42600_PWR_MGMT0_GYRO(gyro) |
>
> > +ÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_PWR_MGMT0_ACCEL(accel);
>
> > +ÂÂÂÂ if (!temp)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
>
> > +ÂÂÂÂ dev_dbg(regmap_get_device(st->map), "pwr_mgmt0: %#02x\n", val);
>
>
>
> I wonder if you have a little too much in the way of debug prints.
>
> These are internal to the code and so could only be wrong due to a local
>
> bug. Once you've finished writing the driver I'd hope we won't need these!
>
>
>
> > +ÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ st->conf.gyro.mode = gyro;
>
> > +ÂÂÂÂ st->conf.accel.mode = accel;
>
> > +ÂÂÂÂ st->conf.temp_en = temp;
>
> > +
>
> > +ÂÂÂÂ /* compute required wait time for sensors to stabilize */
>
> > +ÂÂÂÂ sleepval = 0;
>
> > +ÂÂÂÂ /* temperature stabilization time */
>
> > +ÂÂÂÂ if (temp && !oldtemp) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (sleepval < INV_ICM42600_TEMP_STARTUP_TIME_MS)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ sleepval = INV_ICM42600_TEMP_STARTUP_TIME_MS;
>
> > +ÂÂÂÂ }
>
> > +ÂÂÂÂ /* accel startup time */
>
> > +ÂÂÂÂ if (accel != oldaccel && oldaccel == INV_ICM42600_SENSOR_MODE_OFF) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* block any register write for at least 200 Âs */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ usleep_range(200, 300);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (sleepval < INV_ICM42600_ACCEL_STARTUP_TIME_MS)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ sleepval = INV_ICM42600_ACCEL_STARTUP_TIME_MS;
>
> > +ÂÂÂÂ }
>
> > +ÂÂÂÂ if (gyro != oldgyro) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* gyro startup time */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (oldgyro == INV_ICM42600_SENSOR_MODE_OFF) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ /* block any register write for at least 200 Âs */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ usleep_range(200, 300);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ if (sleepval < INV_ICM42600_GYRO_STARTUP_TIME_MS)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ sleepval = INV_ICM42600_GYRO_STARTUP_TIME_MS;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ /* gyro stop time */
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ } else if (gyro == INV_ICM42600_SENSOR_MODE_OFF) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ if (sleepval < INV_ICM42600_GYRO_STOP_TIME_MS)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ sleepval =Â INV_ICM42600_GYRO_STOP_TIME_MS;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ }
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ /* deferred sleep value if sleep pointer is provided or direct sleep */
>
> > +ÂÂÂÂ if (sleep)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ *sleep = sleepval;
>
> > +ÂÂÂÂ else if (sleepval)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ msleep(sleepval);
>
> > +
>
> > +ÂÂÂÂ return 0;
>
> > +}
>
> > +
>
> > +int inv_icm42600_set_accel_conf(struct inv_icm42600_state *st,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct inv_icm42600_sensor_conf *conf,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int *sleep)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_sensor_conf *oldconf = &st->conf.accel;
>
> > +ÂÂÂÂ unsigned int val;
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ /* Sanitize missing values with current values */
>
> > +ÂÂÂÂ if (conf->mode < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->mode = oldconf->mode;
>
> > +ÂÂÂÂ if (conf->fs < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->fs = oldconf->fs;
>
> > +ÂÂÂÂ if (conf->odr < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->odr = oldconf->odr;
>
> > +ÂÂÂÂ if (conf->filter < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->filter = oldconf->filter;
>
> > +
>
> > +ÂÂÂÂ /* set ACCEL_CONFIG0 register (accel fullscale & odr) */
>
> > +ÂÂÂÂ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->fs) |
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_ACCEL_CONFIG0_ODR(conf->odr);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_dbg(regmap_get_device(st->map), "accel_config0: %#02x\n", val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ oldconf->fs = conf->fs;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ oldconf->odr = conf->odr;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ /* set GYRO_ACCEL_CONFIG0 register (accel filter) */
>
> > +ÂÂÂÂ if (conf->filter != oldconf->filter) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->filter) |
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(st->conf.gyro.filter);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_dbg(regmap_get_device(st->map), "gyro_accel_config0: %#02x\n", val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ oldconf->filter = conf->filter;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ /* set PWR_MGMT0 register (accel sensor mode) */
>
> > +ÂÂÂÂ return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode, conf->mode,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ st->conf.temp_en, sleep);
>
> > +}
>
> > +
>
> > +int inv_icm42600_set_gyro_conf(struct inv_icm42600_state *st,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct inv_icm42600_sensor_conf *conf,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int *sleep)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_sensor_conf *oldconf = &st->conf.gyro;
>
> > +ÂÂÂÂ unsigned int val;
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ /* sanitize missing values with current values */
>
> > +ÂÂÂÂ if (conf->mode < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->mode = oldconf->mode;
>
> > +ÂÂÂÂ if (conf->fs < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->fs = oldconf->fs;
>
> > +ÂÂÂÂ if (conf->odr < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->odr = oldconf->odr;
>
> > +ÂÂÂÂ if (conf->filter < 0)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ conf->filter = oldconf->filter;
>
> > +
>
> > +ÂÂÂÂ /* set GYRO_CONFIG0 register (gyro fullscale & odr) */
>
> > +ÂÂÂÂ if (conf->fs != oldconf->fs || conf->odr != oldconf->odr) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val = INV_ICM42600_GYRO_CONFIG0_FS(conf->fs) |
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_GYRO_CONFIG0_ODR(conf->odr);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_dbg(regmap_get_device(st->map), "gyro_config0: %#02x\n", val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ oldconf->fs = conf->fs;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ oldconf->odr = conf->odr;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ /* set GYRO_ACCEL_CONFIG0 register (gyro filter) */
>
> > +ÂÂÂÂ if (conf->filter != oldconf->filter) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(st->conf.accel.filter) |
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->filter);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_dbg(regmap_get_device(st->map), "gyro_accel_config0: %#02x\n", val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ oldconf->filter = conf->filter;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ /* set PWR_MGMT0 register (gyro sensor mode) */
>
> > +ÂÂÂÂ return inv_icm42600_set_pwr_mgmt0(st, conf->mode, st->conf.accel.mode,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ st->conf.temp_en, sleep);
>
> > +
>
> > +ÂÂÂÂ return 0;
>
> > +}
>
> > +
>
> > +int inv_icm42600_set_temp_conf(struct inv_icm42600_state *st, bool enable,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int *sleep)
>
> > +{
>
> > +ÂÂÂÂ return inv_icm42600_set_pwr_mgmt0(st, st->conf.gyro.mode,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ st->conf.accel.mode, enable,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ sleep);
>
> > +}
>
> > +
>
> > +int inv_icm42600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ unsigned int writeval, unsigned int *readval)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ mutex_lock(&st->lock);
>
> > +
>
> > +ÂÂÂÂ if (readval)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_read(st->map, reg, readval);
>
> > +ÂÂÂÂ else
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = regmap_write(st->map, reg, writeval);
>
> > +
>
> > +ÂÂÂÂ mutex_unlock(&st->lock);
>
> > +
>
> > +ÂÂÂÂ return ret;
>
> > +}
>
> > +
>
> > +static int inv_icm42600_set_conf(struct inv_icm42600_state *st,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ const struct inv_icm42600_conf *conf)
>
> > +{
>
> > +ÂÂÂÂ unsigned int val;
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ /* set PWR_MGMT0 register (gyro & accel sensor mode, temp enabled) */
>
> > +ÂÂÂÂ val = INV_ICM42600_PWR_MGMT0_GYRO(conf->gyro.mode) |
>
> > +ÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_PWR_MGMT0_ACCEL(conf->accel.mode);
>
> > +ÂÂÂÂ if (!conf->temp_en)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ val |= INV_ICM42600_PWR_MGMT0_TEMP_DIS;
>
> > +ÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_PWR_MGMT0, val);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* set GYRO_CONFIG0 register (gyro fullscale & odr) */
>
> > +ÂÂÂÂ val = INV_ICM42600_GYRO_CONFIG0_FS(conf->gyro.fs) |
>
> > +ÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_GYRO_CONFIG0_ODR(conf->gyro.odr);
>
> > +ÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_CONFIG0, val);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* set ACCEL_CONFIG0 register (accel fullscale & odr) */
>
> > +ÂÂÂÂ val = INV_ICM42600_ACCEL_CONFIG0_FS(conf->accel.fs) |
>
> > +ÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_ACCEL_CONFIG0_ODR(conf->accel.odr);
>
> > +ÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_ACCEL_CONFIG0, val);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* set GYRO_ACCEL_CONFIG0 register (gyro & accel filters) */
>
> > +ÂÂÂÂ val = INV_ICM42600_GYRO_ACCEL_CONFIG0_ACCEL_FILT(conf->accel.filter) |
>
> > +ÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_GYRO_ACCEL_CONFIG0_GYRO_FILT(conf->gyro.filter);
>
> > +ÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_GYRO_ACCEL_CONFIG0, val);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* update internal conf */
>
> > +ÂÂÂÂ st->conf = *conf;
>
> > +
>
> > +ÂÂÂÂ return 0;
>
> > +}
>
> > +
>
> > +/**
>
> > + *Â inv_icm42600_setup() - check and setup chip.
>
>
>
> If doing kernel-doc (which is good) you should do it all.
>
> So document the parameters as well.
>
> It's worth running the kernel-doc script over any file where
>
> you put some and fixing up any warnings / errors.
>
>
>
> > + */
>
> > +static int inv_icm42600_setup(struct inv_icm42600_state *st,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_bus_setup bus_setup)
>
> > +{
>
> > +ÂÂÂÂ const struct inv_icm42600_hw *hw = &inv_icm42600_hw[st->chip];
>
> > +ÂÂÂÂ const struct device *dev = regmap_get_device(st->map);
>
> > +ÂÂÂÂ unsigned int mask, val;
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ /* check chip self-identification value */
>
> > +ÂÂÂÂ ret = regmap_read(st->map, INV_ICM42600_REG_WHOAMI, &val);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ if (val != hw->whoami) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(dev, "invalid whoami %#02x expected %#02x (%s)\n",
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ val, hw->whoami, hw->name);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -ENODEV;
>
> > +ÂÂÂÂ }
>
> > +ÂÂÂÂ dev_info(dev, "found %s (%#02x)\n", hw->name, hw->whoami);
>
>
>
> Hmm. I'm never that keen on this sort of log noise. Why do you need it
>
> except for initial debug?
>
>
>
> > +ÂÂÂÂ st->name = hw->name;
>
> > +
>
> > +ÂÂÂÂ /* reset to make sure previous state are not there */
>
> > +ÂÂÂÂ ret = regmap_write(st->map, INV_ICM42600_REG_DEVICE_CONFIG,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_DEVICE_CONFIG_SOFT_RESET);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ msleep(INV_ICM42600_RESET_TIME_MS);
>
>
>
> blank line here to separate two logical blocks of code.
>
> Slightly helps readability.
>
>
>
> > +ÂÂÂÂ ret = regmap_read(st->map, INV_ICM42600_REG_INT_STATUS, &val);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ if (!(val & INV_ICM42600_INT_STATUS_RESET_DONE)) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(dev, "reset error, reset done bit not set\n");
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -ENODEV;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ /* set chip bus configuration */
>
> > +ÂÂÂÂ ret = bus_setup(st);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* sensor data in big-endian (default) */
>
> > +ÂÂÂÂ mask = INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN;
>
> > +ÂÂÂÂ val = INV_ICM42600_INTF_CONFIG0_SENSOR_DATA_ENDIAN;
>
> > +ÂÂÂÂ ret = regmap_update_bits(st->map, INV_ICM42600_REG_INTF_CONFIG0,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ mask, val);
>
>
>
> Long line, but I'd rather you just didn't bother will local variables
>
> in cases like this where you just set them to a constant.
>
> Take the 80 chars thing as guidance not a rule :)
>
>
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ return inv_icm42600_set_conf(st, hw->conf);
>
> > +}
>
> > +
>
> > +static int inv_icm42600_enable_regulator_vddio(struct inv_icm42600_state *st)
>
> > +{
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ ret = regulator_enable(st->vddio_supply);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* wait a little for supply ramp */
>
> > +ÂÂÂÂ usleep_range(3000, 4000);
>
> > +
>
> > +ÂÂÂÂ return 0;
>
> > +}
>
> > +
>
> > +static void inv_icm42600_disable_regulators(void *_data)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_state *st = _data;
>
> > +ÂÂÂÂ const struct device *dev = regmap_get_device(st->map);
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ ret = regulator_disable(st->vddio_supply);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(dev, "failed to disable vddio error %d\n", ret);
>
> > +
>
> > +ÂÂÂÂ ret = regulator_disable(st->vdd_supply);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(dev, "failed to disable vdd error %d\n", ret);
>
> > +}
>
> > +
>
> > +static void inv_icm42600_disable_pm(void *_data)
>
> > +{
>
> > +ÂÂÂÂ struct device *dev = _data;
>
> > +
>
> > +ÂÂÂÂ pm_runtime_put_sync(dev);
>
> > +ÂÂÂÂ pm_runtime_disable(dev);
>
> > +}
>
> > +
>
> > +int inv_icm42600_core_probe(struct regmap *regmap, int chip,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_bus_setup bus_setup)
>
> > +{
>
> > +ÂÂÂÂ struct device *dev = regmap_get_device(regmap);
>
> > +ÂÂÂÂ struct inv_icm42600_state *st;
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ BUILD_BUG_ON(ARRAY_SIZE(inv_icm42600_hw) != INV_CHIP_NB);
>
>
>
> Why not just give the array an explicit size when you define it above?
>
> I guess it would in theory be possible to not instantiate all of the array
>
> but relying on different size of a variable length array seems less than
>
> ideal.
>
>
>
> > +ÂÂÂÂ if (chip < 0 || chip >= INV_CHIP_NB) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(dev, "invalid chip = %d\n", chip);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -ENODEV;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
>
> > +ÂÂÂÂ if (!st)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return -ENOMEM;
>
> nitpick: blank line here.
>
>
>
> > +ÂÂÂÂ dev_set_drvdata(dev, st);
>
> > +ÂÂÂÂ mutex_init(&st->lock);
>
> > +ÂÂÂÂ st->chip = chip;
>
> > +ÂÂÂÂ st->map = regmap;
>
> > +
>
> > +ÂÂÂÂ ret = iio_read_mount_matrix(dev, "mount-matrix", &st->orientation);
>
> > +ÂÂÂÂ if (ret) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(dev, "failed to retrieve mounting matrix %d\n", ret);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ st->vdd_supply = devm_regulator_get(dev, "vdd");
>
> > +ÂÂÂÂ if (IS_ERR(st->vdd_supply))
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return PTR_ERR(st->vdd_supply);
>
> > +
>
> > +ÂÂÂÂ st->vddio_supply = devm_regulator_get(dev, "vddio");
>
> > +ÂÂÂÂ if (IS_ERR(st->vddio_supply))
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return PTR_ERR(st->vddio_supply);
>
> > +
>
> > +ÂÂÂÂ ret = regulator_enable(st->vdd_supply);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ msleep(INV_ICM42600_POWER_UP_TIME_MS);
>
> > +
>
> > +ÂÂÂÂ ret = inv_icm42600_enable_regulator_vddio(st);
>
> > +ÂÂÂÂ if (ret) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ regulator_disable(st->vdd_supply);
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ ret = devm_add_action_or_reset(dev, inv_icm42600_disable_regulators,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ st);
>
>
>
> I'd prefer to see two devm_add_action_or_reset calls. One for each regulator.
>
> That means you don't have to do the extra disable logic above which is
>
> a bit fragile in amongst a whole load of device managed calls.
>
>
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* setup chip registers */
>
> > +ÂÂÂÂ ret = inv_icm42600_setup(st, bus_setup);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +
>
> > +ÂÂÂÂ /* setup runtime power management */
>
> > +ÂÂÂÂ ret = pm_runtime_set_active(dev);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ return ret;
>
> > +ÂÂÂÂ pm_runtime_get_noresume(dev);
>
> > +ÂÂÂÂ pm_runtime_enable(dev);
>
> > +ÂÂÂÂ pm_runtime_set_autosuspend_delay(dev, INV_ICM42600_SUSPEND_DELAY_MS);
>
> > +ÂÂÂÂ pm_runtime_use_autosuspend(dev);
>
> > +ÂÂÂÂ pm_runtime_put(dev);
>
> > +
>
> > +ÂÂÂÂ return devm_add_action_or_reset(dev, inv_icm42600_disable_pm, dev);
>
> > +}
>
> > +EXPORT_SYMBOL_GPL(inv_icm42600_core_probe);
>
> > +
>
> > +static int __maybe_unused inv_icm42600_suspend(struct device *dev)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_state *st = dev_get_drvdata(dev);
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ mutex_lock(&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)) {
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ ret = 0;
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
>
> > +ÂÂÂÂ }
>
> > +
>
> > +ÂÂÂÂ ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_SENSOR_MODE_OFF, false,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ NULL);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
>
> > +
>
> > +ÂÂÂÂ regulator_disable(st->vddio_supply);
>
> > +
>
> > +out_unlock:
>
> > +ÂÂÂÂ mutex_unlock(&st->lock);
>
> > +ÂÂÂÂ return ret;
>
> > +}
>
> > +
>
> > +static int __maybe_unused inv_icm42600_resume(struct device *dev)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_state *st = dev_get_drvdata(dev);
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ mutex_lock(&st->lock);
>
> > +
>
> > +ÂÂÂÂ ret = inv_icm42600_enable_regulator_vddio(st);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
>
> > +
>
> > +ÂÂÂÂ pm_runtime_disable(dev);
>
> > +ÂÂÂÂ pm_runtime_set_active(dev);
>
> > +ÂÂÂÂ pm_runtime_enable(dev);
>
> > +
>
> > +ÂÂÂÂ /* restore sensors state */
>
> > +ÂÂÂÂ ret = inv_icm42600_set_pwr_mgmt0(st, st->suspended.gyro,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ st->suspended.accel,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ st->suspended.temp, NULL);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto out_unlock;
>
>
>
> You may need this later, but for now it's a bit comic so ideally introduce
>
> it only when needed.
>
>
>
> > +
>
> > +out_unlock:
>
> > +ÂÂÂÂ mutex_unlock(&st->lock);
>
> > +ÂÂÂÂ return ret;
>
> > +}
>
> > +
>
> > +static int __maybe_unused inv_icm42600_runtime_suspend(struct device *dev)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_state *st = dev_get_drvdata(dev);
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ mutex_lock(&st->lock);
>
> > +
>
> > +ÂÂÂÂ /* disable all sensors */
>
> > +ÂÂÂÂ ret = inv_icm42600_set_pwr_mgmt0(st, INV_ICM42600_SENSOR_MODE_OFF,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ INV_ICM42600_SENSOR_MODE_OFF, false,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ NULL);
>
> > +ÂÂÂÂ if (ret)
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂ goto error_unlock;
>
> > +
>
> > +ÂÂÂÂ regulator_disable(st->vddio_supply);
>
> > +
>
> > +error_unlock:
>
> > +ÂÂÂÂ mutex_unlock(&st->lock);
>
> > +ÂÂÂÂ return ret;
>
> > +}
>
> > +
>
> > +static int __maybe_unused inv_icm42600_runtime_resume(struct device *dev)
>
> > +{
>
> > +ÂÂÂÂ struct inv_icm42600_state *st = dev_get_drvdata(dev);
>
> > +ÂÂÂÂ int ret;
>
> > +
>
> > +ÂÂÂÂ mutex_lock(&st->lock);
>
> > +
>
>
>
> Why don't we need to reenable all the sensors we disabled in runtime suspend?
>
> I can guess why we might not, but a comment here to explain would save on
>
> possible confusion..
>
>
>
> > +ÂÂÂÂ ret = inv_icm42600_enable_regulator_vddio(st);
>
> > +
>
> > +ÂÂÂÂ mutex_unlock(&st->lock);
>
> > +ÂÂÂÂ return ret;
>
> > +}
>
> > +
>
> > +const struct dev_pm_ops inv_icm42600_pm_ops = {
>
> > +ÂÂÂÂ SET_SYSTEM_SLEEP_PM_OPS(inv_icm42600_suspend, inv_icm42600_resume)
>
> > +ÂÂÂÂ SET_RUNTIME_PM_OPS(inv_icm42600_runtime_suspend,
>
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ inv_icm42600_runtime_resume, NULL)
>
> > +};
>
> > +EXPORT_SYMBOL_GPL(inv_icm42600_pm_ops);
>
> > +
>
> > +MODULE_AUTHOR("InvenSense, Inc.");
>
> > +MODULE_DESCRIPTION("InvenSense ICM-426xx device driver");
>
> > +MODULE_LICENSE("GPL");
>
>
>
>
>