root/drivers/iio/imu/inv_icm45600/inv_icm45600.h
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2025 Invensense, Inc. */

#ifndef INV_ICM45600_H_
#define INV_ICM45600_H_

#include <linux/bits.h>
#include <linux/limits.h>
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
#include <linux/types.h>

#include <linux/iio/common/inv_sensors_timestamp.h>
#include <linux/iio/iio.h>

#include "inv_icm45600_buffer.h"

#define INV_ICM45600_REG_BANK_MASK      GENMASK(15, 8)
#define INV_ICM45600_REG_ADDR_MASK      GENMASK(7, 0)

enum inv_icm45600_sensor_mode {
        INV_ICM45600_SENSOR_MODE_OFF,
        INV_ICM45600_SENSOR_MODE_STANDBY,
        INV_ICM45600_SENSOR_MODE_LOW_POWER,
        INV_ICM45600_SENSOR_MODE_LOW_NOISE,
        INV_ICM45600_SENSOR_MODE_MAX
};

/* gyroscope fullscale values */
enum inv_icm45600_gyro_fs {
        INV_ICM45600_GYRO_FS_2000DPS,
        INV_ICM45600_GYRO_FS_1000DPS,
        INV_ICM45600_GYRO_FS_500DPS,
        INV_ICM45600_GYRO_FS_250DPS,
        INV_ICM45600_GYRO_FS_125DPS,
        INV_ICM45600_GYRO_FS_62_5DPS,
        INV_ICM45600_GYRO_FS_31_25DPS,
        INV_ICM45600_GYRO_FS_15_625DPS,
        INV_ICM45600_GYRO_FS_MAX
};

enum inv_icm45686_gyro_fs {
        INV_ICM45686_GYRO_FS_4000DPS,
        INV_ICM45686_GYRO_FS_2000DPS,
        INV_ICM45686_GYRO_FS_1000DPS,
        INV_ICM45686_GYRO_FS_500DPS,
        INV_ICM45686_GYRO_FS_250DPS,
        INV_ICM45686_GYRO_FS_125DPS,
        INV_ICM45686_GYRO_FS_62_5DPS,
        INV_ICM45686_GYRO_FS_31_25DPS,
        INV_ICM45686_GYRO_FS_15_625DPS,
        INV_ICM45686_GYRO_FS_MAX
};

/* accelerometer fullscale values */
enum inv_icm45600_accel_fs {
        INV_ICM45600_ACCEL_FS_16G,
        INV_ICM45600_ACCEL_FS_8G,
        INV_ICM45600_ACCEL_FS_4G,
        INV_ICM45600_ACCEL_FS_2G,
        INV_ICM45600_ACCEL_FS_MAX
};

enum inv_icm45686_accel_fs {
        INV_ICM45686_ACCEL_FS_32G,
        INV_ICM45686_ACCEL_FS_16G,
        INV_ICM45686_ACCEL_FS_8G,
        INV_ICM45686_ACCEL_FS_4G,
        INV_ICM45686_ACCEL_FS_2G,
        INV_ICM45686_ACCEL_FS_MAX
};

/* ODR suffixed by LN or LP are Low-Noise or Low-Power mode only */
enum inv_icm45600_odr {
        INV_ICM45600_ODR_6400HZ_LN = 0x03,
        INV_ICM45600_ODR_3200HZ_LN,
        INV_ICM45600_ODR_1600HZ_LN,
        INV_ICM45600_ODR_800HZ_LN,
        INV_ICM45600_ODR_400HZ,
        INV_ICM45600_ODR_200HZ,
        INV_ICM45600_ODR_100HZ,
        INV_ICM45600_ODR_50HZ,
        INV_ICM45600_ODR_25HZ,
        INV_ICM45600_ODR_12_5HZ,
        INV_ICM45600_ODR_6_25HZ_LP,
        INV_ICM45600_ODR_3_125HZ_LP,
        INV_ICM45600_ODR_1_5625HZ_LP,
        INV_ICM45600_ODR_MAX
};

struct inv_icm45600_sensor_conf {
        u8 mode;
        u8 fs;
        u8 odr;
        u8 filter;
};

#define INV_ICM45600_SENSOR_CONF_KEEP_VALUES { U8_MAX, U8_MAX, U8_MAX, U8_MAX }

struct inv_icm45600_conf {
        struct inv_icm45600_sensor_conf gyro;
        struct inv_icm45600_sensor_conf accel;
};

struct inv_icm45600_suspended {
        enum inv_icm45600_sensor_mode gyro;
        enum inv_icm45600_sensor_mode accel;
};

struct inv_icm45600_chip_info {
        u8 whoami;
        const char *name;
        const struct inv_icm45600_conf *conf;
        const int *accel_scales;
        const int accel_scales_len;
        const int *gyro_scales;
        const int gyro_scales_len;
};

extern const struct inv_icm45600_chip_info inv_icm45605_chip_info;
extern const struct inv_icm45600_chip_info inv_icm45606_chip_info;
extern const struct inv_icm45600_chip_info inv_icm45608_chip_info;
extern const struct inv_icm45600_chip_info inv_icm45634_chip_info;
extern const struct inv_icm45600_chip_info inv_icm45686_chip_info;
extern const struct inv_icm45600_chip_info inv_icm45687_chip_info;
extern const struct inv_icm45600_chip_info inv_icm45688p_chip_info;
extern const struct inv_icm45600_chip_info inv_icm45689_chip_info;

extern const int inv_icm45600_accel_scale[][2];
extern const int inv_icm45686_accel_scale[][2];
extern const int inv_icm45600_gyro_scale[][2];
extern const int inv_icm45686_gyro_scale[][2];

/**
 *  struct inv_icm45600_state - driver state variables
 *  @lock:              lock for serializing multiple registers access.
 *  @map:               regmap pointer.
 *  @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.
 *  @indio_gyro:        gyroscope IIO device.
 *  @indio_accel:       accelerometer IIO device.
 *  @chip_info:         chip driver data.
 *  @timestamp:         interrupt timestamps.
 *  @fifo:              FIFO management structure.
 *  @buffer:            data transfer buffer aligned for DMA.
 */
struct inv_icm45600_state {
        struct mutex lock;
        struct regmap *map;
        struct regulator *vddio_supply;
        struct iio_mount_matrix orientation;
        struct inv_icm45600_conf conf;
        struct inv_icm45600_suspended suspended;
        struct iio_dev *indio_gyro;
        struct iio_dev *indio_accel;
        const struct inv_icm45600_chip_info *chip_info;
        struct {
                s64 gyro;
                s64 accel;
        } timestamp;
        struct inv_icm45600_fifo fifo;
        union {
                u8 buff[2];
                __le16 u16;
                u8 ireg[3];
        } buffer __aligned(IIO_DMA_MINALIGN);
};

/**
 * struct inv_icm45600_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)
 * @ts:                 timestamp module states.
 */
struct inv_icm45600_sensor_state {
        const int *scales;
        size_t scales_len;
        enum inv_icm45600_sensor_mode power_mode;
        struct inv_sensors_timestamp ts;
};

/* Virtual register addresses: @bank on MSB (16 bits), @address on LSB */

/* Indirect register access */
#define INV_ICM45600_REG_IREG_ADDR                      0x7C
#define INV_ICM45600_REG_IREG_DATA                      0x7E

/* Direct acces registers */
#define INV_ICM45600_REG_MISC2                          0x007F
#define INV_ICM45600_MISC2_SOFT_RESET                   BIT(1)

#define INV_ICM45600_REG_DRIVE_CONFIG0                  0x0032
#define INV_ICM45600_DRIVE_CONFIG0_SPI_MASK             GENMASK(3, 1)
#define INV_ICM45600_SPI_SLEW_RATE_0_5NS                6
#define INV_ICM45600_SPI_SLEW_RATE_4NS                  5
#define INV_ICM45600_SPI_SLEW_RATE_5NS                  4
#define INV_ICM45600_SPI_SLEW_RATE_7NS                  3
#define INV_ICM45600_SPI_SLEW_RATE_10NS                 2
#define INV_ICM45600_SPI_SLEW_RATE_14NS                 1
#define INV_ICM45600_SPI_SLEW_RATE_38NS                 0

#define INV_ICM45600_REG_INT1_CONFIG2                   0x0018
#define INV_ICM45600_INT1_CONFIG2_OPEN_DRAIN            BIT(2)
#define INV_ICM45600_INT1_CONFIG2_LATCHED               BIT(1)
#define INV_ICM45600_INT1_CONFIG2_ACTIVE_HIGH           BIT(0)
#define INV_ICM45600_INT1_CONFIG2_ACTIVE_LOW            0x00

#define INV_ICM45600_REG_FIFO_CONFIG0                   0x001D
#define INV_ICM45600_FIFO_CONFIG0_MODE_MASK             GENMASK(7, 6)
#define INV_ICM45600_FIFO_CONFIG0_MODE_BYPASS           0
#define INV_ICM45600_FIFO_CONFIG0_MODE_STREAM           1
#define INV_ICM45600_FIFO_CONFIG0_MODE_STOP_ON_FULL     2
#define INV_ICM45600_FIFO_CONFIG0_FIFO_DEPTH_MASK       GENMASK(5, 0)
#define INV_ICM45600_FIFO_CONFIG0_FIFO_DEPTH_MAX        0x1F

#define INV_ICM45600_REG_FIFO_CONFIG2                   0x0020
#define INV_ICM45600_REG_FIFO_CONFIG2_FIFO_FLUSH        BIT(7)
#define INV_ICM45600_REG_FIFO_CONFIG2_WM_GT_TH          BIT(3)

#define INV_ICM45600_REG_FIFO_CONFIG3                   0x0021
#define INV_ICM45600_FIFO_CONFIG3_ES1_EN                BIT(5)
#define INV_ICM45600_FIFO_CONFIG3_ES0_EN                BIT(4)
#define INV_ICM45600_FIFO_CONFIG3_HIRES_EN              BIT(3)
#define INV_ICM45600_FIFO_CONFIG3_GYRO_EN               BIT(2)
#define INV_ICM45600_FIFO_CONFIG3_ACCEL_EN              BIT(1)
#define INV_ICM45600_FIFO_CONFIG3_IF_EN                 BIT(0)

#define INV_ICM45600_REG_FIFO_CONFIG4                   0x0022
#define INV_ICM45600_FIFO_CONFIG4_COMP_EN               BIT(2)
#define INV_ICM45600_FIFO_CONFIG4_TMST_FSYNC_EN         BIT(1)
#define INV_ICM45600_FIFO_CONFIG4_ES0_9B                BIT(0)

/* all sensor data are 16 bits (2 registers wide) in big-endian */
#define INV_ICM45600_REG_TEMP_DATA                      0x000C
#define INV_ICM45600_REG_ACCEL_DATA_X                   0x0000
#define INV_ICM45600_REG_ACCEL_DATA_Y                   0x0002
#define INV_ICM45600_REG_ACCEL_DATA_Z                   0x0004
#define INV_ICM45600_REG_GYRO_DATA_X                    0x0006
#define INV_ICM45600_REG_GYRO_DATA_Y                    0x0008
#define INV_ICM45600_REG_GYRO_DATA_Z                    0x000A

#define INV_ICM45600_REG_INT_STATUS                     0x0019
#define INV_ICM45600_INT_STATUS_RESET_DONE              BIT(7)
#define INV_ICM45600_INT_STATUS_AUX1_AGC_RDY            BIT(6)
#define INV_ICM45600_INT_STATUS_AP_AGC_RDY              BIT(5)
#define INV_ICM45600_INT_STATUS_AP_FSYNC                BIT(4)
#define INV_ICM45600_INT_STATUS_AUX1_DRDY               BIT(3)
#define INV_ICM45600_INT_STATUS_DATA_RDY                BIT(2)
#define INV_ICM45600_INT_STATUS_FIFO_THS                BIT(1)
#define INV_ICM45600_INT_STATUS_FIFO_FULL               BIT(0)

/*
 * FIFO access registers
 * FIFO count is 16 bits (2 registers)
 * FIFO data is a continuous read register to read FIFO content
 */
#define INV_ICM45600_REG_FIFO_COUNT                     0x0012
#define INV_ICM45600_REG_FIFO_DATA                      0x0014

#define INV_ICM45600_REG_PWR_MGMT0                      0x0010
#define INV_ICM45600_PWR_MGMT0_GYRO_MODE_MASK           GENMASK(3, 2)
#define INV_ICM45600_PWR_MGMT0_ACCEL_MODE_MASK          GENMASK(1, 0)

#define INV_ICM45600_REG_ACCEL_CONFIG0                  0x001B
#define INV_ICM45600_ACCEL_CONFIG0_FS_MASK              GENMASK(6, 4)
#define INV_ICM45600_ACCEL_CONFIG0_ODR_MASK             GENMASK(3, 0)
#define INV_ICM45600_REG_GYRO_CONFIG0                   0x001C
#define INV_ICM45600_GYRO_CONFIG0_FS_MASK               GENMASK(7, 4)
#define INV_ICM45600_GYRO_CONFIG0_ODR_MASK              GENMASK(3, 0)

#define INV_ICM45600_REG_SMC_CONTROL_0                  0xA258
#define INV_ICM45600_SMC_CONTROL_0_ACCEL_LP_CLK_SEL     BIT(4)
#define INV_ICM45600_SMC_CONTROL_0_TMST_EN              BIT(0)

/* FIFO watermark is 16 bits (2 registers wide) in little-endian */
#define INV_ICM45600_REG_FIFO_WATERMARK                 0x001E

/* FIFO is configured for 8kb */
#define INV_ICM45600_FIFO_SIZE_MAX                      SZ_8K

#define INV_ICM45600_REG_INT1_CONFIG0                   0x0016
#define INV_ICM45600_INT1_CONFIG0_RESET_DONE_EN         BIT(7)
#define INV_ICM45600_INT1_CONFIG0_AUX1_AGC_RDY_EN       BIT(6)
#define INV_ICM45600_INT1_CONFIG0_AP_AGC_RDY_EN         BIT(5)
#define INV_ICM45600_INT1_CONFIG0_AP_FSYNC_EN           BIT(4)
#define INV_ICM45600_INT1_CONFIG0_AUX1_DRDY_EN          BIT(3)
#define INV_ICM45600_INT1_CONFIG0_DRDY_EN               BIT(2)
#define INV_ICM45600_INT1_CONFIG0_FIFO_THS_EN           BIT(1)
#define INV_ICM45600_INT1_CONFIG0_FIFO_FULL_EN          BIT(0)

#define INV_ICM45600_REG_WHOAMI                         0x0072
#define INV_ICM45600_WHOAMI_ICM45605                    0xE5
#define INV_ICM45600_WHOAMI_ICM45686                    0xE9
#define INV_ICM45600_WHOAMI_ICM45688P                   0xE7
#define INV_ICM45600_WHOAMI_ICM45608                    0x81
#define INV_ICM45600_WHOAMI_ICM45634                    0x82
#define INV_ICM45600_WHOAMI_ICM45689                    0x83
#define INV_ICM45600_WHOAMI_ICM45606                    0x84
#define INV_ICM45600_WHOAMI_ICM45687                    0x85

/* Gyro USER offset */
#define INV_ICM45600_IPREG_SYS1_REG_42                  0xA42A
#define INV_ICM45600_IPREG_SYS1_REG_56                  0xA438
#define INV_ICM45600_IPREG_SYS1_REG_70                  0xA446
#define INV_ICM45600_GYRO_OFFUSER_MASK                  GENMASK(13, 0)
/* Gyro Averaging filter */
#define INV_ICM45600_IPREG_SYS1_REG_170                 0xA4AA
#define INV_ICM45600_IPREG_SYS1_170_GYRO_LP_AVG_MASK    GENMASK(4, 1)
#define INV_ICM45600_GYRO_LP_AVG_SEL_8X                 5
#define INV_ICM45600_GYRO_LP_AVG_SEL_2X                 1
/* Accel USER offset */
#define INV_ICM45600_IPREG_SYS2_REG_24                  0xA518
#define INV_ICM45600_IPREG_SYS2_REG_32                  0xA520
#define INV_ICM45600_IPREG_SYS2_REG_40                  0xA528
#define INV_ICM45600_ACCEL_OFFUSER_MASK                 GENMASK(13, 0)
/* Accel averaging filter */
#define INV_ICM45600_IPREG_SYS2_REG_129                 0xA581
#define INV_ICM45600_ACCEL_LP_AVG_SEL_1X                0x0000
#define INV_ICM45600_ACCEL_LP_AVG_SEL_4X                0x0002

/* Sleep times required by the driver */
#define INV_ICM45600_ACCEL_STARTUP_TIME_MS      60
#define INV_ICM45600_GYRO_STARTUP_TIME_MS       60
#define INV_ICM45600_GYRO_STOP_TIME_MS          150
#define INV_ICM45600_IREG_DELAY_US              4

typedef int (*inv_icm45600_bus_setup)(struct inv_icm45600_state *);

extern const struct dev_pm_ops inv_icm45600_pm_ops;

const struct iio_mount_matrix *
inv_icm45600_get_mount_matrix(const struct iio_dev *indio_dev,
                              const struct iio_chan_spec *chan);

#define INV_ICM45600_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,                              \
                        .endianness = IIO_LE,                           \
                },                                                      \
        }

int inv_icm45600_temp_read_raw(struct iio_dev *indio_dev,
                               struct iio_chan_spec const *chan,
                               int *val, int *val2, long mask);

u32 inv_icm45600_odr_to_period(enum inv_icm45600_odr odr);

int inv_icm45600_set_accel_conf(struct inv_icm45600_state *st,
                                struct inv_icm45600_sensor_conf *conf,
                                unsigned int *sleep_ms);

int inv_icm45600_set_gyro_conf(struct inv_icm45600_state *st,
                               struct inv_icm45600_sensor_conf *conf,
                               unsigned int *sleep_ms);

int inv_icm45600_debugfs_reg(struct iio_dev *indio_dev, unsigned int reg,
                             unsigned int writeval, unsigned int *readval);

int inv_icm45600_core_probe(struct regmap *regmap,
                                const struct inv_icm45600_chip_info *chip_info,
                                bool reset, inv_icm45600_bus_setup bus_setup);

struct iio_dev *inv_icm45600_gyro_init(struct inv_icm45600_state *st);

int inv_icm45600_gyro_parse_fifo(struct iio_dev *indio_dev);

struct iio_dev *inv_icm45600_accel_init(struct inv_icm45600_state *st);

int inv_icm45600_accel_parse_fifo(struct iio_dev *indio_dev);

#endif