summaryrefslogtreecommitdiff
path: root/drivers/iio/imu/inv_icm45600/inv_icm45600.h
blob: c5b5446f6c3b43150512bcc4357cee385080b634 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
/* 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_PUSH_PULL		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