1290a6ce1SLorenzo Bianconi /*
2290a6ce1SLorenzo Bianconi  * STMicroelectronics st_lsm6dsx sensor driver
3290a6ce1SLorenzo Bianconi  *
4290a6ce1SLorenzo Bianconi  * The ST LSM6DSx IMU MEMS series consists of 3D digital accelerometer
5290a6ce1SLorenzo Bianconi  * and 3D digital gyroscope system-in-package with a digital I2C/SPI serial
6290a6ce1SLorenzo Bianconi  * interface standard output.
7290a6ce1SLorenzo Bianconi  * LSM6DSx IMU MEMS series has a dynamic user-selectable full-scale
8290a6ce1SLorenzo Bianconi  * acceleration range of +-2/+-4/+-8/+-16 g and an angular rate range of
9290a6ce1SLorenzo Bianconi  * +-125/+-245/+-500/+-1000/+-2000 dps
10290a6ce1SLorenzo Bianconi  * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer
11290a6ce1SLorenzo Bianconi  * allowing dynamic batching of sensor data.
12290a6ce1SLorenzo Bianconi  *
13290a6ce1SLorenzo Bianconi  * Supported sensors:
14290a6ce1SLorenzo Bianconi  * - LSM6DS3:
15290a6ce1SLorenzo Bianconi  *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
16290a6ce1SLorenzo Bianconi  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
17290a6ce1SLorenzo Bianconi  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
18290a6ce1SLorenzo Bianconi  *   - FIFO size: 8KB
19290a6ce1SLorenzo Bianconi  *
20179c8d60SLorenzo Bianconi  * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC:
21290a6ce1SLorenzo Bianconi  *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
22290a6ce1SLorenzo Bianconi  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
23290a6ce1SLorenzo Bianconi  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
24290a6ce1SLorenzo Bianconi  *   - FIFO size: 4KB
25290a6ce1SLorenzo Bianconi  *
2643901008SLorenzo Bianconi  * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR
27801a6e0aSLorenzo Bianconi  *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
28801a6e0aSLorenzo Bianconi  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
29801a6e0aSLorenzo Bianconi  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
30801a6e0aSLorenzo Bianconi  *   - FIFO size: 3KB
31801a6e0aSLorenzo Bianconi  *
32290a6ce1SLorenzo Bianconi  * Copyright 2016 STMicroelectronics Inc.
33290a6ce1SLorenzo Bianconi  *
34290a6ce1SLorenzo Bianconi  * Lorenzo Bianconi <lorenzo.bianconi@st.com>
35290a6ce1SLorenzo Bianconi  * Denis Ciocca <denis.ciocca@st.com>
36290a6ce1SLorenzo Bianconi  *
37290a6ce1SLorenzo Bianconi  * Licensed under the GPL-2.
38290a6ce1SLorenzo Bianconi  */
39290a6ce1SLorenzo Bianconi 
40290a6ce1SLorenzo Bianconi #include <linux/kernel.h>
41290a6ce1SLorenzo Bianconi #include <linux/module.h>
42290a6ce1SLorenzo Bianconi #include <linux/delay.h>
43290a6ce1SLorenzo Bianconi #include <linux/iio/iio.h>
44290a6ce1SLorenzo Bianconi #include <linux/iio/sysfs.h>
45d3f77058SLorenzo Bianconi #include <linux/pm.h>
4651a8b707SLorenzo Bianconi #include <linux/regmap.h>
4751a8b707SLorenzo Bianconi #include <linux/bitfield.h>
48290a6ce1SLorenzo Bianconi 
49dba32904SLorenzo Bianconi #include <linux/platform_data/st_sensors_pdata.h>
50dba32904SLorenzo Bianconi 
51290a6ce1SLorenzo Bianconi #include "st_lsm6dsx.h"
52290a6ce1SLorenzo Bianconi 
53290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT1_ADDR		0x0d
54dba32904SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ADDR		0x0e
55290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK	BIT(3)
56290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_WHOAMI_ADDR		0x0f
57290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_ADDR		0x12
58290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_MASK		BIT(0)
5919435425SLorenzo Bianconi #define ST_LSM6DSX_REG_BOOT_MASK		BIT(7)
60290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_ADDR			0x12
61290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_MASK			BIT(6)
62290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR	0x13
63290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_MASK	BIT(5)
64290a6ce1SLorenzo Bianconi 
65290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_ADDR		0x10
66290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_MASK		GENMASK(7, 4)
67290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_ADDR		0x10
68290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_MASK		GENMASK(3, 2)
69290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR		0x28
70290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR		0x2a
71290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR		0x2c
72290a6ce1SLorenzo Bianconi 
73290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_ADDR		0x11
74290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_MASK		GENMASK(7, 4)
75290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_ADDR		0x11
76290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_MASK		GENMASK(3, 2)
77290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR	0x22
78290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR	0x24
79290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR	0x26
80290a6ce1SLorenzo Bianconi 
81290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_2G_GAIN		IIO_G_TO_M_S_2(61)
82290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_4G_GAIN		IIO_G_TO_M_S_2(122)
83290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_8G_GAIN		IIO_G_TO_M_S_2(244)
84290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_16G_GAIN		IIO_G_TO_M_S_2(488)
85290a6ce1SLorenzo Bianconi 
86dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_245_GAIN		IIO_DEGREE_TO_RAD(8750)
87dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_500_GAIN		IIO_DEGREE_TO_RAD(17500)
88dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_1000_GAIN		IIO_DEGREE_TO_RAD(35000)
89290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_2000_GAIN		IIO_DEGREE_TO_RAD(70000)
90290a6ce1SLorenzo Bianconi 
91290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
92290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_ACC] = {
93290a6ce1SLorenzo Bianconi 		.reg = {
94290a6ce1SLorenzo Bianconi 			.addr = ST_LSM6DSX_REG_ACC_ODR_ADDR,
95290a6ce1SLorenzo Bianconi 			.mask = ST_LSM6DSX_REG_ACC_ODR_MASK,
96290a6ce1SLorenzo Bianconi 		},
97290a6ce1SLorenzo Bianconi 		.odr_avl[0] = {  13, 0x01 },
98290a6ce1SLorenzo Bianconi 		.odr_avl[1] = {  26, 0x02 },
99290a6ce1SLorenzo Bianconi 		.odr_avl[2] = {  52, 0x03 },
100290a6ce1SLorenzo Bianconi 		.odr_avl[3] = { 104, 0x04 },
101290a6ce1SLorenzo Bianconi 		.odr_avl[4] = { 208, 0x05 },
102290a6ce1SLorenzo Bianconi 		.odr_avl[5] = { 416, 0x06 },
103290a6ce1SLorenzo Bianconi 	},
104290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_GYRO] = {
105290a6ce1SLorenzo Bianconi 		.reg = {
106290a6ce1SLorenzo Bianconi 			.addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR,
107290a6ce1SLorenzo Bianconi 			.mask = ST_LSM6DSX_REG_GYRO_ODR_MASK,
108290a6ce1SLorenzo Bianconi 		},
109290a6ce1SLorenzo Bianconi 		.odr_avl[0] = {  13, 0x01 },
110290a6ce1SLorenzo Bianconi 		.odr_avl[1] = {  26, 0x02 },
111290a6ce1SLorenzo Bianconi 		.odr_avl[2] = {  52, 0x03 },
112290a6ce1SLorenzo Bianconi 		.odr_avl[3] = { 104, 0x04 },
113290a6ce1SLorenzo Bianconi 		.odr_avl[4] = { 208, 0x05 },
114290a6ce1SLorenzo Bianconi 		.odr_avl[5] = { 416, 0x06 },
115290a6ce1SLorenzo Bianconi 	}
116290a6ce1SLorenzo Bianconi };
117290a6ce1SLorenzo Bianconi 
118290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
119290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_ACC] = {
120290a6ce1SLorenzo Bianconi 		.reg = {
121290a6ce1SLorenzo Bianconi 			.addr = ST_LSM6DSX_REG_ACC_FS_ADDR,
122290a6ce1SLorenzo Bianconi 			.mask = ST_LSM6DSX_REG_ACC_FS_MASK,
123290a6ce1SLorenzo Bianconi 		},
124290a6ce1SLorenzo Bianconi 		.fs_avl[0] = {  ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 },
125290a6ce1SLorenzo Bianconi 		.fs_avl[1] = {  ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 },
126290a6ce1SLorenzo Bianconi 		.fs_avl[2] = {  ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 },
127290a6ce1SLorenzo Bianconi 		.fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 },
128290a6ce1SLorenzo Bianconi 	},
129290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_GYRO] = {
130290a6ce1SLorenzo Bianconi 		.reg = {
131290a6ce1SLorenzo Bianconi 			.addr = ST_LSM6DSX_REG_GYRO_FS_ADDR,
132290a6ce1SLorenzo Bianconi 			.mask = ST_LSM6DSX_REG_GYRO_FS_MASK,
133290a6ce1SLorenzo Bianconi 		},
134290a6ce1SLorenzo Bianconi 		.fs_avl[0] = {  ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 },
135290a6ce1SLorenzo Bianconi 		.fs_avl[1] = {  ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 },
136290a6ce1SLorenzo Bianconi 		.fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 },
137290a6ce1SLorenzo Bianconi 		.fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 },
138290a6ce1SLorenzo Bianconi 	}
139290a6ce1SLorenzo Bianconi };
140290a6ce1SLorenzo Bianconi 
141290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
142290a6ce1SLorenzo Bianconi 	{
143d068e4a0SLorenzo Bianconi 		.wai = 0x69,
1448f2a88a2SLorenzo Bianconi 		.max_fifo_size = 1365,
145d068e4a0SLorenzo Bianconi 		.id = {
146d068e4a0SLorenzo Bianconi 			[0] = ST_LSM6DS3_ID,
147d068e4a0SLorenzo Bianconi 		},
1487ca3ac9eSLorenzo Bianconi 		.decimator = {
1497ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
1507ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
1517ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(2, 0),
1527ca3ac9eSLorenzo Bianconi 			},
1537ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
1547ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
1557ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(5, 3),
1567ca3ac9eSLorenzo Bianconi 			},
1577ca3ac9eSLorenzo Bianconi 		},
15892617c15SLorenzo Bianconi 		.fifo_ops = {
15950ff457dSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_fifo,
16092617c15SLorenzo Bianconi 			.fifo_th = {
16192617c15SLorenzo Bianconi 				.addr = 0x06,
16292617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
16392617c15SLorenzo Bianconi 			},
16492617c15SLorenzo Bianconi 			.fifo_diff = {
16592617c15SLorenzo Bianconi 				.addr = 0x3a,
16692617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
16792617c15SLorenzo Bianconi 			},
16892617c15SLorenzo Bianconi 			.th_wl = 3, /* 1LSB = 2B */
16992617c15SLorenzo Bianconi 		},
17021345107SLorenzo Bianconi 		.ts_settings = {
17121345107SLorenzo Bianconi 			.timer_en = {
17221345107SLorenzo Bianconi 				.addr = 0x58,
17321345107SLorenzo Bianconi 				.mask = BIT(7),
17421345107SLorenzo Bianconi 			},
17521345107SLorenzo Bianconi 			.hr_timer = {
17621345107SLorenzo Bianconi 				.addr = 0x5c,
17721345107SLorenzo Bianconi 				.mask = BIT(4),
17821345107SLorenzo Bianconi 			},
17921345107SLorenzo Bianconi 			.fifo_en = {
18021345107SLorenzo Bianconi 				.addr = 0x07,
18121345107SLorenzo Bianconi 				.mask = BIT(7),
18221345107SLorenzo Bianconi 			},
18321345107SLorenzo Bianconi 			.decimator = {
18421345107SLorenzo Bianconi 				.addr = 0x09,
18521345107SLorenzo Bianconi 				.mask = GENMASK(5, 3),
18621345107SLorenzo Bianconi 			},
18721345107SLorenzo Bianconi 		},
188290a6ce1SLorenzo Bianconi 	},
189290a6ce1SLorenzo Bianconi 	{
190df47710aSLorenzo Bianconi 		.wai = 0x69,
1918f2a88a2SLorenzo Bianconi 		.max_fifo_size = 682,
192df47710aSLorenzo Bianconi 		.id = {
193df47710aSLorenzo Bianconi 			[0] = ST_LSM6DS3H_ID,
194df47710aSLorenzo Bianconi 		},
1957ca3ac9eSLorenzo Bianconi 		.decimator = {
1967ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
1977ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
1987ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(2, 0),
1997ca3ac9eSLorenzo Bianconi 			},
2007ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
2017ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
2027ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(5, 3),
2037ca3ac9eSLorenzo Bianconi 			},
2047ca3ac9eSLorenzo Bianconi 		},
20592617c15SLorenzo Bianconi 		.fifo_ops = {
20650ff457dSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_fifo,
20792617c15SLorenzo Bianconi 			.fifo_th = {
20892617c15SLorenzo Bianconi 				.addr = 0x06,
20992617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
21092617c15SLorenzo Bianconi 			},
21192617c15SLorenzo Bianconi 			.fifo_diff = {
21292617c15SLorenzo Bianconi 				.addr = 0x3a,
21392617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
21492617c15SLorenzo Bianconi 			},
21592617c15SLorenzo Bianconi 			.th_wl = 3, /* 1LSB = 2B */
21692617c15SLorenzo Bianconi 		},
21721345107SLorenzo Bianconi 		.ts_settings = {
21821345107SLorenzo Bianconi 			.timer_en = {
21921345107SLorenzo Bianconi 				.addr = 0x58,
22021345107SLorenzo Bianconi 				.mask = BIT(7),
22121345107SLorenzo Bianconi 			},
22221345107SLorenzo Bianconi 			.hr_timer = {
22321345107SLorenzo Bianconi 				.addr = 0x5c,
22421345107SLorenzo Bianconi 				.mask = BIT(4),
22521345107SLorenzo Bianconi 			},
22621345107SLorenzo Bianconi 			.fifo_en = {
22721345107SLorenzo Bianconi 				.addr = 0x07,
22821345107SLorenzo Bianconi 				.mask = BIT(7),
22921345107SLorenzo Bianconi 			},
23021345107SLorenzo Bianconi 			.decimator = {
23121345107SLorenzo Bianconi 				.addr = 0x09,
23221345107SLorenzo Bianconi 				.mask = GENMASK(5, 3),
23321345107SLorenzo Bianconi 			},
23421345107SLorenzo Bianconi 		},
235df47710aSLorenzo Bianconi 	},
236df47710aSLorenzo Bianconi 	{
237d068e4a0SLorenzo Bianconi 		.wai = 0x6a,
2388f2a88a2SLorenzo Bianconi 		.max_fifo_size = 682,
239d068e4a0SLorenzo Bianconi 		.id = {
2400b2a3e5fSLorenzo Bianconi 			[0] = ST_LSM6DSL_ID,
2410b2a3e5fSLorenzo Bianconi 			[1] = ST_LSM6DSM_ID,
242179c8d60SLorenzo Bianconi 			[2] = ST_ISM330DLC_ID,
243d068e4a0SLorenzo Bianconi 		},
2447ca3ac9eSLorenzo Bianconi 		.decimator = {
2457ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
2467ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
2477ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(2, 0),
2487ca3ac9eSLorenzo Bianconi 			},
2497ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
2507ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
2517ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(5, 3),
2527ca3ac9eSLorenzo Bianconi 			},
2537ca3ac9eSLorenzo Bianconi 		},
25492617c15SLorenzo Bianconi 		.fifo_ops = {
25550ff457dSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_fifo,
25692617c15SLorenzo Bianconi 			.fifo_th = {
25792617c15SLorenzo Bianconi 				.addr = 0x06,
258be75eb86SLorenzo Bianconi 				.mask = GENMASK(10, 0),
25992617c15SLorenzo Bianconi 			},
26092617c15SLorenzo Bianconi 			.fifo_diff = {
26192617c15SLorenzo Bianconi 				.addr = 0x3a,
262be75eb86SLorenzo Bianconi 				.mask = GENMASK(10, 0),
26392617c15SLorenzo Bianconi 			},
26492617c15SLorenzo Bianconi 			.th_wl = 3, /* 1LSB = 2B */
26592617c15SLorenzo Bianconi 		},
26621345107SLorenzo Bianconi 		.ts_settings = {
26721345107SLorenzo Bianconi 			.timer_en = {
26821345107SLorenzo Bianconi 				.addr = 0x19,
26921345107SLorenzo Bianconi 				.mask = BIT(5),
27021345107SLorenzo Bianconi 			},
27121345107SLorenzo Bianconi 			.hr_timer = {
27221345107SLorenzo Bianconi 				.addr = 0x5c,
27321345107SLorenzo Bianconi 				.mask = BIT(4),
27421345107SLorenzo Bianconi 			},
27521345107SLorenzo Bianconi 			.fifo_en = {
27621345107SLorenzo Bianconi 				.addr = 0x07,
27721345107SLorenzo Bianconi 				.mask = BIT(7),
27821345107SLorenzo Bianconi 			},
27921345107SLorenzo Bianconi 			.decimator = {
28021345107SLorenzo Bianconi 				.addr = 0x09,
28121345107SLorenzo Bianconi 				.mask = GENMASK(5, 3),
28221345107SLorenzo Bianconi 			},
28321345107SLorenzo Bianconi 		},
284290a6ce1SLorenzo Bianconi 	},
285801a6e0aSLorenzo Bianconi 	{
286801a6e0aSLorenzo Bianconi 		.wai = 0x6c,
287801a6e0aSLorenzo Bianconi 		.max_fifo_size = 512,
288801a6e0aSLorenzo Bianconi 		.id = {
289801a6e0aSLorenzo Bianconi 			[0] = ST_LSM6DSO_ID,
2906af0e8a9SLorenzo Bianconi 			[1] = ST_LSM6DSOX_ID,
291801a6e0aSLorenzo Bianconi 		},
292801a6e0aSLorenzo Bianconi 		.batch = {
293801a6e0aSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
294801a6e0aSLorenzo Bianconi 				.addr = 0x09,
295801a6e0aSLorenzo Bianconi 				.mask = GENMASK(3, 0),
296801a6e0aSLorenzo Bianconi 			},
297801a6e0aSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
298801a6e0aSLorenzo Bianconi 				.addr = 0x09,
299801a6e0aSLorenzo Bianconi 				.mask = GENMASK(7, 4),
300801a6e0aSLorenzo Bianconi 			},
301801a6e0aSLorenzo Bianconi 		},
302801a6e0aSLorenzo Bianconi 		.fifo_ops = {
303801a6e0aSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_tagged_fifo,
304801a6e0aSLorenzo Bianconi 			.fifo_th = {
305801a6e0aSLorenzo Bianconi 				.addr = 0x07,
306801a6e0aSLorenzo Bianconi 				.mask = GENMASK(8, 0),
307801a6e0aSLorenzo Bianconi 			},
308801a6e0aSLorenzo Bianconi 			.fifo_diff = {
309801a6e0aSLorenzo Bianconi 				.addr = 0x3a,
310801a6e0aSLorenzo Bianconi 				.mask = GENMASK(8, 0),
311801a6e0aSLorenzo Bianconi 			},
312801a6e0aSLorenzo Bianconi 			.th_wl = 1,
313801a6e0aSLorenzo Bianconi 		},
314801a6e0aSLorenzo Bianconi 		.ts_settings = {
315801a6e0aSLorenzo Bianconi 			.timer_en = {
316801a6e0aSLorenzo Bianconi 				.addr = 0x19,
317801a6e0aSLorenzo Bianconi 				.mask = BIT(5),
318801a6e0aSLorenzo Bianconi 			},
319801a6e0aSLorenzo Bianconi 			.decimator = {
320801a6e0aSLorenzo Bianconi 				.addr = 0x0a,
321801a6e0aSLorenzo Bianconi 				.mask = GENMASK(7, 6),
322801a6e0aSLorenzo Bianconi 			},
323801a6e0aSLorenzo Bianconi 		},
324c91c1c84SLorenzo Bianconi 		.shub_settings = {
325c91c1c84SLorenzo Bianconi 			.page_mux = {
326c91c1c84SLorenzo Bianconi 				.addr = 0x01,
327c91c1c84SLorenzo Bianconi 				.mask = BIT(6),
328c91c1c84SLorenzo Bianconi 			},
329c91c1c84SLorenzo Bianconi 			.master_en = {
330c91c1c84SLorenzo Bianconi 				.addr = 0x14,
331c91c1c84SLorenzo Bianconi 				.mask = BIT(2),
332c91c1c84SLorenzo Bianconi 			},
333c91c1c84SLorenzo Bianconi 			.pullup_en = {
334c91c1c84SLorenzo Bianconi 				.addr = 0x14,
335c91c1c84SLorenzo Bianconi 				.mask = BIT(3),
336c91c1c84SLorenzo Bianconi 			},
337c91c1c84SLorenzo Bianconi 			.aux_sens = {
338c91c1c84SLorenzo Bianconi 				.addr = 0x14,
339c91c1c84SLorenzo Bianconi 				.mask = GENMASK(1, 0),
340c91c1c84SLorenzo Bianconi 			},
3416d0205fdSLorenzo Bianconi 			.wr_once = {
3426d0205fdSLorenzo Bianconi 				.addr = 0x14,
3436d0205fdSLorenzo Bianconi 				.mask = BIT(6),
3446d0205fdSLorenzo Bianconi 			},
345c91c1c84SLorenzo Bianconi 			.shub_out = 0x02,
346c91c1c84SLorenzo Bianconi 			.slv0_addr = 0x15,
347c91c1c84SLorenzo Bianconi 			.dw_slv0_addr = 0x21,
3486d0205fdSLorenzo Bianconi 			.batch_en = BIT(3),
349c91c1c84SLorenzo Bianconi 		}
350801a6e0aSLorenzo Bianconi 	},
3513054c4ffSLorenzo Bianconi 	{
3523054c4ffSLorenzo Bianconi 		.wai = 0x6b,
3533054c4ffSLorenzo Bianconi 		.max_fifo_size = 512,
3543054c4ffSLorenzo Bianconi 		.id = {
3553054c4ffSLorenzo Bianconi 			[0] = ST_ASM330LHH_ID,
3563054c4ffSLorenzo Bianconi 		},
3573054c4ffSLorenzo Bianconi 		.batch = {
3583054c4ffSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
3593054c4ffSLorenzo Bianconi 				.addr = 0x09,
3603054c4ffSLorenzo Bianconi 				.mask = GENMASK(3, 0),
3613054c4ffSLorenzo Bianconi 			},
3623054c4ffSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
3633054c4ffSLorenzo Bianconi 				.addr = 0x09,
3643054c4ffSLorenzo Bianconi 				.mask = GENMASK(7, 4),
3653054c4ffSLorenzo Bianconi 			},
3663054c4ffSLorenzo Bianconi 		},
3673054c4ffSLorenzo Bianconi 		.fifo_ops = {
3683054c4ffSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_tagged_fifo,
3693054c4ffSLorenzo Bianconi 			.fifo_th = {
3703054c4ffSLorenzo Bianconi 				.addr = 0x07,
3713054c4ffSLorenzo Bianconi 				.mask = GENMASK(8, 0),
3723054c4ffSLorenzo Bianconi 			},
3733054c4ffSLorenzo Bianconi 			.fifo_diff = {
3743054c4ffSLorenzo Bianconi 				.addr = 0x3a,
3753054c4ffSLorenzo Bianconi 				.mask = GENMASK(8, 0),
3763054c4ffSLorenzo Bianconi 			},
3773054c4ffSLorenzo Bianconi 			.th_wl = 1,
3783054c4ffSLorenzo Bianconi 		},
3793054c4ffSLorenzo Bianconi 		.ts_settings = {
3803054c4ffSLorenzo Bianconi 			.timer_en = {
3813054c4ffSLorenzo Bianconi 				.addr = 0x19,
3823054c4ffSLorenzo Bianconi 				.mask = BIT(5),
3833054c4ffSLorenzo Bianconi 			},
3843054c4ffSLorenzo Bianconi 			.decimator = {
3853054c4ffSLorenzo Bianconi 				.addr = 0x0a,
3863054c4ffSLorenzo Bianconi 				.mask = GENMASK(7, 6),
3873054c4ffSLorenzo Bianconi 			},
3883054c4ffSLorenzo Bianconi 		},
3893054c4ffSLorenzo Bianconi 	},
39043901008SLorenzo Bianconi 	{
39143901008SLorenzo Bianconi 		.wai = 0x6b,
39243901008SLorenzo Bianconi 		.max_fifo_size = 512,
39343901008SLorenzo Bianconi 		.id = {
39443901008SLorenzo Bianconi 			[0] = ST_LSM6DSR_ID,
39543901008SLorenzo Bianconi 		},
39643901008SLorenzo Bianconi 		.batch = {
39743901008SLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
39843901008SLorenzo Bianconi 				.addr = 0x09,
39943901008SLorenzo Bianconi 				.mask = GENMASK(3, 0),
40043901008SLorenzo Bianconi 			},
40143901008SLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
40243901008SLorenzo Bianconi 				.addr = 0x09,
40343901008SLorenzo Bianconi 				.mask = GENMASK(7, 4),
40443901008SLorenzo Bianconi 			},
40543901008SLorenzo Bianconi 		},
40643901008SLorenzo Bianconi 		.fifo_ops = {
40743901008SLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_tagged_fifo,
40843901008SLorenzo Bianconi 			.fifo_th = {
40943901008SLorenzo Bianconi 				.addr = 0x07,
41043901008SLorenzo Bianconi 				.mask = GENMASK(8, 0),
41143901008SLorenzo Bianconi 			},
41243901008SLorenzo Bianconi 			.fifo_diff = {
41343901008SLorenzo Bianconi 				.addr = 0x3a,
41443901008SLorenzo Bianconi 				.mask = GENMASK(8, 0),
41543901008SLorenzo Bianconi 			},
41643901008SLorenzo Bianconi 			.th_wl = 1,
41743901008SLorenzo Bianconi 		},
41843901008SLorenzo Bianconi 		.ts_settings = {
41943901008SLorenzo Bianconi 			.timer_en = {
42043901008SLorenzo Bianconi 				.addr = 0x19,
42143901008SLorenzo Bianconi 				.mask = BIT(5),
42243901008SLorenzo Bianconi 			},
42343901008SLorenzo Bianconi 			.decimator = {
42443901008SLorenzo Bianconi 				.addr = 0x0a,
42543901008SLorenzo Bianconi 				.mask = GENMASK(7, 6),
42643901008SLorenzo Bianconi 			},
42743901008SLorenzo Bianconi 		},
42843901008SLorenzo Bianconi 		.shub_settings = {
42943901008SLorenzo Bianconi 			.page_mux = {
43043901008SLorenzo Bianconi 				.addr = 0x01,
43143901008SLorenzo Bianconi 				.mask = BIT(6),
43243901008SLorenzo Bianconi 			},
43343901008SLorenzo Bianconi 			.master_en = {
43443901008SLorenzo Bianconi 				.addr = 0x14,
43543901008SLorenzo Bianconi 				.mask = BIT(2),
43643901008SLorenzo Bianconi 			},
43743901008SLorenzo Bianconi 			.pullup_en = {
43843901008SLorenzo Bianconi 				.addr = 0x14,
43943901008SLorenzo Bianconi 				.mask = BIT(3),
44043901008SLorenzo Bianconi 			},
44143901008SLorenzo Bianconi 			.aux_sens = {
44243901008SLorenzo Bianconi 				.addr = 0x14,
44343901008SLorenzo Bianconi 				.mask = GENMASK(1, 0),
44443901008SLorenzo Bianconi 			},
44543901008SLorenzo Bianconi 			.wr_once = {
44643901008SLorenzo Bianconi 				.addr = 0x14,
44743901008SLorenzo Bianconi 				.mask = BIT(6),
44843901008SLorenzo Bianconi 			},
44943901008SLorenzo Bianconi 			.shub_out = 0x02,
45043901008SLorenzo Bianconi 			.slv0_addr = 0x15,
45143901008SLorenzo Bianconi 			.dw_slv0_addr = 0x21,
45243901008SLorenzo Bianconi 			.batch_en = BIT(3),
45343901008SLorenzo Bianconi 		}
45443901008SLorenzo Bianconi 	},
455290a6ce1SLorenzo Bianconi };
456290a6ce1SLorenzo Bianconi 
457290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
458290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
459290a6ce1SLorenzo Bianconi 			   IIO_MOD_X, 0),
460290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
461290a6ce1SLorenzo Bianconi 			   IIO_MOD_Y, 1),
462290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
463290a6ce1SLorenzo Bianconi 			   IIO_MOD_Z, 2),
464290a6ce1SLorenzo Bianconi 	IIO_CHAN_SOFT_TIMESTAMP(3),
465290a6ce1SLorenzo Bianconi };
466290a6ce1SLorenzo Bianconi 
467290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
468290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR,
469290a6ce1SLorenzo Bianconi 			   IIO_MOD_X, 0),
470290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR,
471290a6ce1SLorenzo Bianconi 			   IIO_MOD_Y, 1),
472290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR,
473290a6ce1SLorenzo Bianconi 			   IIO_MOD_Z, 2),
474290a6ce1SLorenzo Bianconi 	IIO_CHAN_SOFT_TIMESTAMP(3),
475290a6ce1SLorenzo Bianconi };
476290a6ce1SLorenzo Bianconi 
477c91c1c84SLorenzo Bianconi int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
478c91c1c84SLorenzo Bianconi {
479c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
480c91c1c84SLorenzo Bianconi 	unsigned int data;
481c91c1c84SLorenzo Bianconi 	int err;
482c91c1c84SLorenzo Bianconi 
483c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
484c91c1c84SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->page_mux.mask);
485c91c1c84SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, hub_settings->page_mux.addr,
486c91c1c84SLorenzo Bianconi 				 hub_settings->page_mux.mask, data);
487c91c1c84SLorenzo Bianconi 	usleep_range(100, 150);
488c91c1c84SLorenzo Bianconi 
489c91c1c84SLorenzo Bianconi 	return err;
490c91c1c84SLorenzo Bianconi }
491c91c1c84SLorenzo Bianconi 
492290a6ce1SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
493290a6ce1SLorenzo Bianconi {
49451a8b707SLorenzo Bianconi 	int err, i, j, data;
495290a6ce1SLorenzo Bianconi 
496290a6ce1SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
497d068e4a0SLorenzo Bianconi 		for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) {
498d068e4a0SLorenzo Bianconi 			if (id == st_lsm6dsx_sensor_settings[i].id[j])
499d068e4a0SLorenzo Bianconi 				break;
500d068e4a0SLorenzo Bianconi 		}
501d068e4a0SLorenzo Bianconi 		if (j < ST_LSM6DSX_MAX_ID)
502290a6ce1SLorenzo Bianconi 			break;
503290a6ce1SLorenzo Bianconi 	}
504290a6ce1SLorenzo Bianconi 
505290a6ce1SLorenzo Bianconi 	if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) {
506290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "unsupported hw id [%02x]\n", id);
507290a6ce1SLorenzo Bianconi 		return -ENODEV;
508290a6ce1SLorenzo Bianconi 	}
509290a6ce1SLorenzo Bianconi 
51051a8b707SLorenzo Bianconi 	err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data);
511290a6ce1SLorenzo Bianconi 	if (err < 0) {
512290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "failed to read whoami register\n");
513290a6ce1SLorenzo Bianconi 		return err;
514290a6ce1SLorenzo Bianconi 	}
515290a6ce1SLorenzo Bianconi 
516290a6ce1SLorenzo Bianconi 	if (data != st_lsm6dsx_sensor_settings[i].wai) {
517290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
518290a6ce1SLorenzo Bianconi 		return -ENODEV;
519290a6ce1SLorenzo Bianconi 	}
520290a6ce1SLorenzo Bianconi 
521290a6ce1SLorenzo Bianconi 	hw->settings = &st_lsm6dsx_sensor_settings[i];
522290a6ce1SLorenzo Bianconi 
523290a6ce1SLorenzo Bianconi 	return 0;
524290a6ce1SLorenzo Bianconi }
525290a6ce1SLorenzo Bianconi 
526290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
527290a6ce1SLorenzo Bianconi 				     u32 gain)
528290a6ce1SLorenzo Bianconi {
52951a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
53051a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
531739aff87SLorenzo Bianconi 	unsigned int data;
532290a6ce1SLorenzo Bianconi 	int i, err;
533290a6ce1SLorenzo Bianconi 	u8 val;
534290a6ce1SLorenzo Bianconi 
535290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
53651a8b707SLorenzo Bianconi 		if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain)
537290a6ce1SLorenzo Bianconi 			break;
538290a6ce1SLorenzo Bianconi 
539290a6ce1SLorenzo Bianconi 	if (i == ST_LSM6DSX_FS_LIST_SIZE)
540290a6ce1SLorenzo Bianconi 		return -EINVAL;
541290a6ce1SLorenzo Bianconi 
54251a8b707SLorenzo Bianconi 	val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val;
54351a8b707SLorenzo Bianconi 	reg = &st_lsm6dsx_fs_table[sensor->id].reg;
544739aff87SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
545739aff87SLorenzo Bianconi 	err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
546290a6ce1SLorenzo Bianconi 	if (err < 0)
547290a6ce1SLorenzo Bianconi 		return err;
548290a6ce1SLorenzo Bianconi 
549290a6ce1SLorenzo Bianconi 	sensor->gain = gain;
550290a6ce1SLorenzo Bianconi 
551290a6ce1SLorenzo Bianconi 	return 0;
552290a6ce1SLorenzo Bianconi }
553290a6ce1SLorenzo Bianconi 
55454a6d0c6SLorenzo Bianconi int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
555290a6ce1SLorenzo Bianconi {
5562ccc1503SLorenzo Bianconi 	int i;
557290a6ce1SLorenzo Bianconi 
558290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
5596ffb55e5SLorenzo Bianconi 		/*
5606ffb55e5SLorenzo Bianconi 		 * ext devices can run at different odr respect to
5616ffb55e5SLorenzo Bianconi 		 * accel sensor
5626ffb55e5SLorenzo Bianconi 		 */
5636ffb55e5SLorenzo Bianconi 		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
564290a6ce1SLorenzo Bianconi 			break;
565290a6ce1SLorenzo Bianconi 
566290a6ce1SLorenzo Bianconi 	if (i == ST_LSM6DSX_ODR_LIST_SIZE)
567290a6ce1SLorenzo Bianconi 		return -EINVAL;
568290a6ce1SLorenzo Bianconi 
5692ccc1503SLorenzo Bianconi 	*val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val;
570290a6ce1SLorenzo Bianconi 
571290a6ce1SLorenzo Bianconi 	return 0;
572290a6ce1SLorenzo Bianconi }
573290a6ce1SLorenzo Bianconi 
5746ffb55e5SLorenzo Bianconi static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
5756ffb55e5SLorenzo Bianconi 					   enum st_lsm6dsx_sensor_id id)
5762ccc1503SLorenzo Bianconi {
5776ffb55e5SLorenzo Bianconi 	struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
5786ffb55e5SLorenzo Bianconi 
5796ffb55e5SLorenzo Bianconi 	if (odr > 0) {
5806ffb55e5SLorenzo Bianconi 		if (hw->enable_mask & BIT(id))
5816ffb55e5SLorenzo Bianconi 			return max_t(u16, ref->odr, odr);
5826ffb55e5SLorenzo Bianconi 		else
5836ffb55e5SLorenzo Bianconi 			return odr;
5846ffb55e5SLorenzo Bianconi 	} else {
5856ffb55e5SLorenzo Bianconi 		return (hw->enable_mask & BIT(id)) ? ref->odr : 0;
5866ffb55e5SLorenzo Bianconi 	}
5876ffb55e5SLorenzo Bianconi }
5886ffb55e5SLorenzo Bianconi 
5896ffb55e5SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
5906ffb55e5SLorenzo Bianconi {
5916ffb55e5SLorenzo Bianconi 	struct st_lsm6dsx_sensor *ref_sensor = sensor;
59251a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
59351a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
594739aff87SLorenzo Bianconi 	unsigned int data;
5956ffb55e5SLorenzo Bianconi 	u8 val = 0;
5962ccc1503SLorenzo Bianconi 	int err;
5972ccc1503SLorenzo Bianconi 
5986ffb55e5SLorenzo Bianconi 	switch (sensor->id) {
5996ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT0:
6006ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT1:
6016ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT2:
6026ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_ACC: {
6036ffb55e5SLorenzo Bianconi 		u16 odr;
6046ffb55e5SLorenzo Bianconi 		int i;
6056ffb55e5SLorenzo Bianconi 
6066ffb55e5SLorenzo Bianconi 		/*
6076ffb55e5SLorenzo Bianconi 		 * i2c embedded controller relies on the accelerometer sensor as
6086ffb55e5SLorenzo Bianconi 		 * bus read/write trigger so we need to enable accel device
6096ffb55e5SLorenzo Bianconi 		 * at odr = max(accel_odr, ext_odr) in order to properly
6106ffb55e5SLorenzo Bianconi 		 * communicate with i2c slave devices
6116ffb55e5SLorenzo Bianconi 		 */
6126ffb55e5SLorenzo Bianconi 		ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
6136ffb55e5SLorenzo Bianconi 		for (i = ST_LSM6DSX_ID_ACC; i < ST_LSM6DSX_ID_MAX; i++) {
6146ffb55e5SLorenzo Bianconi 			if (!hw->iio_devs[i] || i == sensor->id)
6156ffb55e5SLorenzo Bianconi 				continue;
6166ffb55e5SLorenzo Bianconi 
6176ffb55e5SLorenzo Bianconi 			odr = st_lsm6dsx_check_odr_dependency(hw, req_odr, i);
6186ffb55e5SLorenzo Bianconi 			if (odr != req_odr)
6196ffb55e5SLorenzo Bianconi 				/* device already configured */
6206ffb55e5SLorenzo Bianconi 				return 0;
6216ffb55e5SLorenzo Bianconi 		}
6226ffb55e5SLorenzo Bianconi 		break;
6236ffb55e5SLorenzo Bianconi 	}
6246ffb55e5SLorenzo Bianconi 	default:
6256ffb55e5SLorenzo Bianconi 		break;
6266ffb55e5SLorenzo Bianconi 	}
6276ffb55e5SLorenzo Bianconi 
6286ffb55e5SLorenzo Bianconi 	if (req_odr > 0) {
6296ffb55e5SLorenzo Bianconi 		err = st_lsm6dsx_check_odr(ref_sensor, req_odr, &val);
6302ccc1503SLorenzo Bianconi 		if (err < 0)
6312ccc1503SLorenzo Bianconi 			return err;
6326ffb55e5SLorenzo Bianconi 	}
6332ccc1503SLorenzo Bianconi 
6346ffb55e5SLorenzo Bianconi 	reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg;
635739aff87SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
636739aff87SLorenzo Bianconi 	return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
6372ccc1503SLorenzo Bianconi }
6382ccc1503SLorenzo Bianconi 
63917750443SLorenzo Bianconi int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
64017750443SLorenzo Bianconi 				 bool enable)
641290a6ce1SLorenzo Bianconi {
64251a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
64317750443SLorenzo Bianconi 	u16 odr = enable ? sensor->odr : 0;
644290a6ce1SLorenzo Bianconi 	int err;
645290a6ce1SLorenzo Bianconi 
64617750443SLorenzo Bianconi 	err = st_lsm6dsx_set_odr(sensor, odr);
647290a6ce1SLorenzo Bianconi 	if (err < 0)
648290a6ce1SLorenzo Bianconi 		return err;
649290a6ce1SLorenzo Bianconi 
65017750443SLorenzo Bianconi 	if (enable)
65117750443SLorenzo Bianconi 		hw->enable_mask |= BIT(sensor->id);
65217750443SLorenzo Bianconi 	else
65317750443SLorenzo Bianconi 		hw->enable_mask &= ~BIT(sensor->id);
654290a6ce1SLorenzo Bianconi 
655290a6ce1SLorenzo Bianconi 	return 0;
656290a6ce1SLorenzo Bianconi }
657290a6ce1SLorenzo Bianconi 
658290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
659290a6ce1SLorenzo Bianconi 				   u8 addr, int *val)
660290a6ce1SLorenzo Bianconi {
66151a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
662290a6ce1SLorenzo Bianconi 	int err, delay;
663290a6ce1SLorenzo Bianconi 	__le16 data;
664290a6ce1SLorenzo Bianconi 
66517750443SLorenzo Bianconi 	err = st_lsm6dsx_sensor_set_enable(sensor, true);
666290a6ce1SLorenzo Bianconi 	if (err < 0)
667290a6ce1SLorenzo Bianconi 		return err;
668290a6ce1SLorenzo Bianconi 
669290a6ce1SLorenzo Bianconi 	delay = 1000000 / sensor->odr;
670290a6ce1SLorenzo Bianconi 	usleep_range(delay, 2 * delay);
671290a6ce1SLorenzo Bianconi 
672739aff87SLorenzo Bianconi 	err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
673290a6ce1SLorenzo Bianconi 	if (err < 0)
674290a6ce1SLorenzo Bianconi 		return err;
675290a6ce1SLorenzo Bianconi 
67617750443SLorenzo Bianconi 	st_lsm6dsx_sensor_set_enable(sensor, false);
677290a6ce1SLorenzo Bianconi 
6787b9ebe42SLorenzo Bianconi 	*val = (s16)le16_to_cpu(data);
679290a6ce1SLorenzo Bianconi 
680290a6ce1SLorenzo Bianconi 	return IIO_VAL_INT;
681290a6ce1SLorenzo Bianconi }
682290a6ce1SLorenzo Bianconi 
683290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
684290a6ce1SLorenzo Bianconi 			       struct iio_chan_spec const *ch,
685290a6ce1SLorenzo Bianconi 			       int *val, int *val2, long mask)
686290a6ce1SLorenzo Bianconi {
687290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
688290a6ce1SLorenzo Bianconi 	int ret;
689290a6ce1SLorenzo Bianconi 
690290a6ce1SLorenzo Bianconi 	switch (mask) {
691290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_RAW:
692290a6ce1SLorenzo Bianconi 		ret = iio_device_claim_direct_mode(iio_dev);
693290a6ce1SLorenzo Bianconi 		if (ret)
694290a6ce1SLorenzo Bianconi 			break;
695290a6ce1SLorenzo Bianconi 
696290a6ce1SLorenzo Bianconi 		ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val);
697290a6ce1SLorenzo Bianconi 		iio_device_release_direct_mode(iio_dev);
698290a6ce1SLorenzo Bianconi 		break;
699290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SAMP_FREQ:
700290a6ce1SLorenzo Bianconi 		*val = sensor->odr;
701290a6ce1SLorenzo Bianconi 		ret = IIO_VAL_INT;
702290a6ce1SLorenzo Bianconi 		break;
703290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SCALE:
704290a6ce1SLorenzo Bianconi 		*val = 0;
705290a6ce1SLorenzo Bianconi 		*val2 = sensor->gain;
706290a6ce1SLorenzo Bianconi 		ret = IIO_VAL_INT_PLUS_MICRO;
707290a6ce1SLorenzo Bianconi 		break;
708290a6ce1SLorenzo Bianconi 	default:
709290a6ce1SLorenzo Bianconi 		ret = -EINVAL;
710290a6ce1SLorenzo Bianconi 		break;
711290a6ce1SLorenzo Bianconi 	}
712290a6ce1SLorenzo Bianconi 
713290a6ce1SLorenzo Bianconi 	return ret;
714290a6ce1SLorenzo Bianconi }
715290a6ce1SLorenzo Bianconi 
716290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
717290a6ce1SLorenzo Bianconi 				struct iio_chan_spec const *chan,
718290a6ce1SLorenzo Bianconi 				int val, int val2, long mask)
719290a6ce1SLorenzo Bianconi {
720290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
721290a6ce1SLorenzo Bianconi 	int err;
722290a6ce1SLorenzo Bianconi 
723290a6ce1SLorenzo Bianconi 	err = iio_device_claim_direct_mode(iio_dev);
724290a6ce1SLorenzo Bianconi 	if (err)
725290a6ce1SLorenzo Bianconi 		return err;
726290a6ce1SLorenzo Bianconi 
727290a6ce1SLorenzo Bianconi 	switch (mask) {
728290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SCALE:
729290a6ce1SLorenzo Bianconi 		err = st_lsm6dsx_set_full_scale(sensor, val2);
730290a6ce1SLorenzo Bianconi 		break;
7312ccc1503SLorenzo Bianconi 	case IIO_CHAN_INFO_SAMP_FREQ: {
7322ccc1503SLorenzo Bianconi 		u8 data;
7332ccc1503SLorenzo Bianconi 
7342ccc1503SLorenzo Bianconi 		err = st_lsm6dsx_check_odr(sensor, val, &data);
7355e3c3e33SLorenzo Bianconi 		if (!err)
7365e3c3e33SLorenzo Bianconi 			sensor->odr = val;
737290a6ce1SLorenzo Bianconi 		break;
7382ccc1503SLorenzo Bianconi 	}
739290a6ce1SLorenzo Bianconi 	default:
740290a6ce1SLorenzo Bianconi 		err = -EINVAL;
741290a6ce1SLorenzo Bianconi 		break;
742290a6ce1SLorenzo Bianconi 	}
743290a6ce1SLorenzo Bianconi 
744290a6ce1SLorenzo Bianconi 	iio_device_release_direct_mode(iio_dev);
745290a6ce1SLorenzo Bianconi 
746290a6ce1SLorenzo Bianconi 	return err;
747290a6ce1SLorenzo Bianconi }
748290a6ce1SLorenzo Bianconi 
749d40464f3SLorenzo Bianconi int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
750290a6ce1SLorenzo Bianconi {
751290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
752290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
7538f2a88a2SLorenzo Bianconi 	int err;
754290a6ce1SLorenzo Bianconi 
7558f2a88a2SLorenzo Bianconi 	if (val < 1 || val > hw->settings->max_fifo_size)
756290a6ce1SLorenzo Bianconi 		return -EINVAL;
757290a6ce1SLorenzo Bianconi 
758335eaedcSLorenzo Bianconi 	mutex_lock(&hw->conf_lock);
759335eaedcSLorenzo Bianconi 
760290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_update_watermark(sensor, val);
761335eaedcSLorenzo Bianconi 
762335eaedcSLorenzo Bianconi 	mutex_unlock(&hw->conf_lock);
763335eaedcSLorenzo Bianconi 
764290a6ce1SLorenzo Bianconi 	if (err < 0)
765290a6ce1SLorenzo Bianconi 		return err;
766290a6ce1SLorenzo Bianconi 
767290a6ce1SLorenzo Bianconi 	sensor->watermark = val;
768290a6ce1SLorenzo Bianconi 
769290a6ce1SLorenzo Bianconi 	return 0;
770290a6ce1SLorenzo Bianconi }
771290a6ce1SLorenzo Bianconi 
772290a6ce1SLorenzo Bianconi static ssize_t
773290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
774290a6ce1SLorenzo Bianconi 					  struct device_attribute *attr,
775290a6ce1SLorenzo Bianconi 					  char *buf)
776290a6ce1SLorenzo Bianconi {
777290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
778290a6ce1SLorenzo Bianconi 	enum st_lsm6dsx_sensor_id id = sensor->id;
779290a6ce1SLorenzo Bianconi 	int i, len = 0;
780290a6ce1SLorenzo Bianconi 
781290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
782290a6ce1SLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
783290a6ce1SLorenzo Bianconi 				 st_lsm6dsx_odr_table[id].odr_avl[i].hz);
784290a6ce1SLorenzo Bianconi 	buf[len - 1] = '\n';
785290a6ce1SLorenzo Bianconi 
786290a6ce1SLorenzo Bianconi 	return len;
787290a6ce1SLorenzo Bianconi }
788290a6ce1SLorenzo Bianconi 
789290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
790290a6ce1SLorenzo Bianconi 					    struct device_attribute *attr,
791290a6ce1SLorenzo Bianconi 					    char *buf)
792290a6ce1SLorenzo Bianconi {
793290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
794290a6ce1SLorenzo Bianconi 	enum st_lsm6dsx_sensor_id id = sensor->id;
795290a6ce1SLorenzo Bianconi 	int i, len = 0;
796290a6ce1SLorenzo Bianconi 
797290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
798290a6ce1SLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
799290a6ce1SLorenzo Bianconi 				 st_lsm6dsx_fs_table[id].fs_avl[i].gain);
800290a6ce1SLorenzo Bianconi 	buf[len - 1] = '\n';
801290a6ce1SLorenzo Bianconi 
802290a6ce1SLorenzo Bianconi 	return len;
803290a6ce1SLorenzo Bianconi }
804290a6ce1SLorenzo Bianconi 
805290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail);
806290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
807290a6ce1SLorenzo Bianconi 		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
808290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444,
809290a6ce1SLorenzo Bianconi 		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
810290a6ce1SLorenzo Bianconi 
811290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = {
812290a6ce1SLorenzo Bianconi 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
813290a6ce1SLorenzo Bianconi 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
814290a6ce1SLorenzo Bianconi 	NULL,
815290a6ce1SLorenzo Bianconi };
816290a6ce1SLorenzo Bianconi 
817290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = {
818290a6ce1SLorenzo Bianconi 	.attrs = st_lsm6dsx_acc_attributes,
819290a6ce1SLorenzo Bianconi };
820290a6ce1SLorenzo Bianconi 
821290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = {
822290a6ce1SLorenzo Bianconi 	.attrs = &st_lsm6dsx_acc_attribute_group,
823290a6ce1SLorenzo Bianconi 	.read_raw = st_lsm6dsx_read_raw,
824290a6ce1SLorenzo Bianconi 	.write_raw = st_lsm6dsx_write_raw,
825290a6ce1SLorenzo Bianconi 	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
826290a6ce1SLorenzo Bianconi };
827290a6ce1SLorenzo Bianconi 
828290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = {
829290a6ce1SLorenzo Bianconi 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
830290a6ce1SLorenzo Bianconi 	&iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
831290a6ce1SLorenzo Bianconi 	NULL,
832290a6ce1SLorenzo Bianconi };
833290a6ce1SLorenzo Bianconi 
834290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = {
835290a6ce1SLorenzo Bianconi 	.attrs = st_lsm6dsx_gyro_attributes,
836290a6ce1SLorenzo Bianconi };
837290a6ce1SLorenzo Bianconi 
838290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = {
839290a6ce1SLorenzo Bianconi 	.attrs = &st_lsm6dsx_gyro_attribute_group,
840290a6ce1SLorenzo Bianconi 	.read_raw = st_lsm6dsx_read_raw,
841290a6ce1SLorenzo Bianconi 	.write_raw = st_lsm6dsx_write_raw,
842290a6ce1SLorenzo Bianconi 	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
843290a6ce1SLorenzo Bianconi };
844290a6ce1SLorenzo Bianconi 
845dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
846dba32904SLorenzo Bianconi {
847dba32904SLorenzo Bianconi 	struct device_node *np = hw->dev->of_node;
848dba32904SLorenzo Bianconi 
849dba32904SLorenzo Bianconi 	if (!np)
850dba32904SLorenzo Bianconi 		return -EINVAL;
851dba32904SLorenzo Bianconi 
852bf235277SLorenzo Bianconi 	return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
853dba32904SLorenzo Bianconi }
854dba32904SLorenzo Bianconi 
855dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
856dba32904SLorenzo Bianconi {
857dba32904SLorenzo Bianconi 	int err = 0, drdy_pin;
858dba32904SLorenzo Bianconi 
859dba32904SLorenzo Bianconi 	if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) {
860dba32904SLorenzo Bianconi 		struct st_sensors_platform_data *pdata;
861dba32904SLorenzo Bianconi 		struct device *dev = hw->dev;
862dba32904SLorenzo Bianconi 
863dba32904SLorenzo Bianconi 		pdata = (struct st_sensors_platform_data *)dev->platform_data;
864dba32904SLorenzo Bianconi 		drdy_pin = pdata ? pdata->drdy_int_pin : 1;
865dba32904SLorenzo Bianconi 	}
866dba32904SLorenzo Bianconi 
867dba32904SLorenzo Bianconi 	switch (drdy_pin) {
868dba32904SLorenzo Bianconi 	case 1:
869dba32904SLorenzo Bianconi 		*drdy_reg = ST_LSM6DSX_REG_INT1_ADDR;
870dba32904SLorenzo Bianconi 		break;
871dba32904SLorenzo Bianconi 	case 2:
872dba32904SLorenzo Bianconi 		*drdy_reg = ST_LSM6DSX_REG_INT2_ADDR;
873dba32904SLorenzo Bianconi 		break;
874dba32904SLorenzo Bianconi 	default:
875dba32904SLorenzo Bianconi 		dev_err(hw->dev, "unsupported data ready pin\n");
876dba32904SLorenzo Bianconi 		err = -EINVAL;
877dba32904SLorenzo Bianconi 		break;
878dba32904SLorenzo Bianconi 	}
879dba32904SLorenzo Bianconi 
880dba32904SLorenzo Bianconi 	return err;
881dba32904SLorenzo Bianconi }
882dba32904SLorenzo Bianconi 
883c91c1c84SLorenzo Bianconi static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
884c91c1c84SLorenzo Bianconi {
885c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
886c91c1c84SLorenzo Bianconi 	struct device_node *np = hw->dev->of_node;
887c91c1c84SLorenzo Bianconi 	struct st_sensors_platform_data *pdata;
888c91c1c84SLorenzo Bianconi 	unsigned int data;
889c91c1c84SLorenzo Bianconi 	int err = 0;
890c91c1c84SLorenzo Bianconi 
891c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
892c91c1c84SLorenzo Bianconi 
893c91c1c84SLorenzo Bianconi 	pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
894c91c1c84SLorenzo Bianconi 	if ((np && of_property_read_bool(np, "st,pullups")) ||
895c91c1c84SLorenzo Bianconi 	    (pdata && pdata->pullups)) {
896c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_set_page(hw, true);
897c91c1c84SLorenzo Bianconi 		if (err < 0)
898c91c1c84SLorenzo Bianconi 			return err;
899c91c1c84SLorenzo Bianconi 
900c91c1c84SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->pullup_en.mask);
901c91c1c84SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
902c91c1c84SLorenzo Bianconi 					 hub_settings->pullup_en.addr,
903c91c1c84SLorenzo Bianconi 					 hub_settings->pullup_en.mask, data);
904c91c1c84SLorenzo Bianconi 
905c91c1c84SLorenzo Bianconi 		st_lsm6dsx_set_page(hw, false);
906c91c1c84SLorenzo Bianconi 
907c91c1c84SLorenzo Bianconi 		if (err < 0)
908c91c1c84SLorenzo Bianconi 			return err;
909c91c1c84SLorenzo Bianconi 	}
910c91c1c84SLorenzo Bianconi 
911c91c1c84SLorenzo Bianconi 	if (hub_settings->aux_sens.addr) {
912c91c1c84SLorenzo Bianconi 		/* configure aux sensors */
913c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_set_page(hw, true);
914c91c1c84SLorenzo Bianconi 		if (err < 0)
915c91c1c84SLorenzo Bianconi 			return err;
916c91c1c84SLorenzo Bianconi 
917c91c1c84SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(3, hub_settings->aux_sens.mask);
918c91c1c84SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
919c91c1c84SLorenzo Bianconi 					 hub_settings->aux_sens.addr,
920c91c1c84SLorenzo Bianconi 					 hub_settings->aux_sens.mask, data);
921c91c1c84SLorenzo Bianconi 
922c91c1c84SLorenzo Bianconi 		st_lsm6dsx_set_page(hw, false);
923c91c1c84SLorenzo Bianconi 	}
924c91c1c84SLorenzo Bianconi 
925c91c1c84SLorenzo Bianconi 	return err;
926c91c1c84SLorenzo Bianconi }
927c91c1c84SLorenzo Bianconi 
92821345107SLorenzo Bianconi static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw)
92921345107SLorenzo Bianconi {
93021345107SLorenzo Bianconi 	const struct st_lsm6dsx_hw_ts_settings *ts_settings;
93121345107SLorenzo Bianconi 	int err, val;
93221345107SLorenzo Bianconi 
93321345107SLorenzo Bianconi 	ts_settings = &hw->settings->ts_settings;
93421345107SLorenzo Bianconi 	/* enable hw timestamp generation if necessary */
93521345107SLorenzo Bianconi 	if (ts_settings->timer_en.addr) {
93621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask);
93721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
93821345107SLorenzo Bianconi 					 ts_settings->timer_en.addr,
93921345107SLorenzo Bianconi 					 ts_settings->timer_en.mask, val);
94021345107SLorenzo Bianconi 		if (err < 0)
94121345107SLorenzo Bianconi 			return err;
94221345107SLorenzo Bianconi 	}
94321345107SLorenzo Bianconi 
94421345107SLorenzo Bianconi 	/* enable high resolution for hw ts timer if necessary */
94521345107SLorenzo Bianconi 	if (ts_settings->hr_timer.addr) {
94621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask);
94721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
94821345107SLorenzo Bianconi 					 ts_settings->hr_timer.addr,
94921345107SLorenzo Bianconi 					 ts_settings->hr_timer.mask, val);
95021345107SLorenzo Bianconi 		if (err < 0)
95121345107SLorenzo Bianconi 			return err;
95221345107SLorenzo Bianconi 	}
95321345107SLorenzo Bianconi 
95421345107SLorenzo Bianconi 	/* enable ts queueing in FIFO if necessary */
95521345107SLorenzo Bianconi 	if (ts_settings->fifo_en.addr) {
95621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask);
95721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
95821345107SLorenzo Bianconi 					 ts_settings->fifo_en.addr,
95921345107SLorenzo Bianconi 					 ts_settings->fifo_en.mask, val);
96021345107SLorenzo Bianconi 		if (err < 0)
96121345107SLorenzo Bianconi 			return err;
96221345107SLorenzo Bianconi 	}
96321345107SLorenzo Bianconi 	return 0;
96421345107SLorenzo Bianconi }
96521345107SLorenzo Bianconi 
966290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
967290a6ce1SLorenzo Bianconi {
96851a8b707SLorenzo Bianconi 	u8 drdy_int_reg;
969290a6ce1SLorenzo Bianconi 	int err;
970290a6ce1SLorenzo Bianconi 
97119435425SLorenzo Bianconi 	/* device sw reset */
97219435425SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
97319435425SLorenzo Bianconi 				 ST_LSM6DSX_REG_RESET_MASK,
97419435425SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1));
975290a6ce1SLorenzo Bianconi 	if (err < 0)
976290a6ce1SLorenzo Bianconi 		return err;
977290a6ce1SLorenzo Bianconi 
97819435425SLorenzo Bianconi 	msleep(50);
97919435425SLorenzo Bianconi 
98019435425SLorenzo Bianconi 	/* reload trimming parameter */
98119435425SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
98219435425SLorenzo Bianconi 				 ST_LSM6DSX_REG_BOOT_MASK,
98319435425SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1));
98419435425SLorenzo Bianconi 	if (err < 0)
98519435425SLorenzo Bianconi 		return err;
98619435425SLorenzo Bianconi 
98719435425SLorenzo Bianconi 	msleep(50);
988290a6ce1SLorenzo Bianconi 
989290a6ce1SLorenzo Bianconi 	/* enable Block Data Update */
99051a8b707SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR,
99151a8b707SLorenzo Bianconi 				 ST_LSM6DSX_REG_BDU_MASK,
99251a8b707SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1));
993290a6ce1SLorenzo Bianconi 	if (err < 0)
994290a6ce1SLorenzo Bianconi 		return err;
995290a6ce1SLorenzo Bianconi 
996290a6ce1SLorenzo Bianconi 	/* enable FIFO watermak interrupt */
997dba32904SLorenzo Bianconi 	err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg);
998290a6ce1SLorenzo Bianconi 	if (err < 0)
999290a6ce1SLorenzo Bianconi 		return err;
1000290a6ce1SLorenzo Bianconi 
100121345107SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, drdy_int_reg,
100251a8b707SLorenzo Bianconi 				 ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
100351a8b707SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
100451a8b707SLorenzo Bianconi 					    1));
100521345107SLorenzo Bianconi 	if (err < 0)
100621345107SLorenzo Bianconi 		return err;
100721345107SLorenzo Bianconi 
1008c91c1c84SLorenzo Bianconi 	err = st_lsm6dsx_init_shub(hw);
1009c91c1c84SLorenzo Bianconi 	if (err < 0)
1010c91c1c84SLorenzo Bianconi 		return err;
1011c91c1c84SLorenzo Bianconi 
101221345107SLorenzo Bianconi 	return st_lsm6dsx_init_hw_timer(hw);
1013290a6ce1SLorenzo Bianconi }
1014290a6ce1SLorenzo Bianconi 
1015290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
1016510c0106SLorenzo Bianconi 					       enum st_lsm6dsx_sensor_id id,
1017510c0106SLorenzo Bianconi 					       const char *name)
1018290a6ce1SLorenzo Bianconi {
1019290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
1020290a6ce1SLorenzo Bianconi 	struct iio_dev *iio_dev;
1021290a6ce1SLorenzo Bianconi 
1022290a6ce1SLorenzo Bianconi 	iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
1023290a6ce1SLorenzo Bianconi 	if (!iio_dev)
1024290a6ce1SLorenzo Bianconi 		return NULL;
1025290a6ce1SLorenzo Bianconi 
1026290a6ce1SLorenzo Bianconi 	iio_dev->modes = INDIO_DIRECT_MODE;
1027290a6ce1SLorenzo Bianconi 	iio_dev->dev.parent = hw->dev;
1028290a6ce1SLorenzo Bianconi 	iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
1029290a6ce1SLorenzo Bianconi 
1030290a6ce1SLorenzo Bianconi 	sensor = iio_priv(iio_dev);
1031290a6ce1SLorenzo Bianconi 	sensor->id = id;
1032290a6ce1SLorenzo Bianconi 	sensor->hw = hw;
1033290a6ce1SLorenzo Bianconi 	sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
1034290a6ce1SLorenzo Bianconi 	sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
1035290a6ce1SLorenzo Bianconi 	sensor->watermark = 1;
1036290a6ce1SLorenzo Bianconi 
1037290a6ce1SLorenzo Bianconi 	switch (id) {
1038290a6ce1SLorenzo Bianconi 	case ST_LSM6DSX_ID_ACC:
1039290a6ce1SLorenzo Bianconi 		iio_dev->channels = st_lsm6dsx_acc_channels;
1040290a6ce1SLorenzo Bianconi 		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
1041290a6ce1SLorenzo Bianconi 		iio_dev->info = &st_lsm6dsx_acc_info;
1042290a6ce1SLorenzo Bianconi 
1043510c0106SLorenzo Bianconi 		scnprintf(sensor->name, sizeof(sensor->name), "%s_accel",
1044510c0106SLorenzo Bianconi 			  name);
1045290a6ce1SLorenzo Bianconi 		break;
1046290a6ce1SLorenzo Bianconi 	case ST_LSM6DSX_ID_GYRO:
1047290a6ce1SLorenzo Bianconi 		iio_dev->channels = st_lsm6dsx_gyro_channels;
1048290a6ce1SLorenzo Bianconi 		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
1049290a6ce1SLorenzo Bianconi 		iio_dev->info = &st_lsm6dsx_gyro_info;
1050290a6ce1SLorenzo Bianconi 
1051510c0106SLorenzo Bianconi 		scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
1052510c0106SLorenzo Bianconi 			  name);
1053290a6ce1SLorenzo Bianconi 		break;
1054290a6ce1SLorenzo Bianconi 	default:
1055290a6ce1SLorenzo Bianconi 		return NULL;
1056290a6ce1SLorenzo Bianconi 	}
1057510c0106SLorenzo Bianconi 	iio_dev->name = sensor->name;
1058290a6ce1SLorenzo Bianconi 
1059290a6ce1SLorenzo Bianconi 	return iio_dev;
1060290a6ce1SLorenzo Bianconi }
1061290a6ce1SLorenzo Bianconi 
1062510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
106351a8b707SLorenzo Bianconi 		     struct regmap *regmap)
1064290a6ce1SLorenzo Bianconi {
1065c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
1066290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw;
1067290a6ce1SLorenzo Bianconi 	int i, err;
1068290a6ce1SLorenzo Bianconi 
1069290a6ce1SLorenzo Bianconi 	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
1070290a6ce1SLorenzo Bianconi 	if (!hw)
1071290a6ce1SLorenzo Bianconi 		return -ENOMEM;
1072290a6ce1SLorenzo Bianconi 
1073290a6ce1SLorenzo Bianconi 	dev_set_drvdata(dev, (void *)hw);
1074290a6ce1SLorenzo Bianconi 
1075290a6ce1SLorenzo Bianconi 	mutex_init(&hw->fifo_lock);
1076335eaedcSLorenzo Bianconi 	mutex_init(&hw->conf_lock);
1077739aff87SLorenzo Bianconi 	mutex_init(&hw->page_lock);
1078290a6ce1SLorenzo Bianconi 
107991a6b841SLorenzo Bianconi 	hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL);
108091a6b841SLorenzo Bianconi 	if (!hw->buff)
108191a6b841SLorenzo Bianconi 		return -ENOMEM;
108291a6b841SLorenzo Bianconi 
1083290a6ce1SLorenzo Bianconi 	hw->dev = dev;
1084290a6ce1SLorenzo Bianconi 	hw->irq = irq;
108551a8b707SLorenzo Bianconi 	hw->regmap = regmap;
1086290a6ce1SLorenzo Bianconi 
1087290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_check_whoami(hw, hw_id);
1088290a6ce1SLorenzo Bianconi 	if (err < 0)
1089290a6ce1SLorenzo Bianconi 		return err;
1090290a6ce1SLorenzo Bianconi 
10916ffb55e5SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) {
1092510c0106SLorenzo Bianconi 		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
1093290a6ce1SLorenzo Bianconi 		if (!hw->iio_devs[i])
1094290a6ce1SLorenzo Bianconi 			return -ENOMEM;
1095290a6ce1SLorenzo Bianconi 	}
1096290a6ce1SLorenzo Bianconi 
1097290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_init_device(hw);
1098290a6ce1SLorenzo Bianconi 	if (err < 0)
1099290a6ce1SLorenzo Bianconi 		return err;
1100290a6ce1SLorenzo Bianconi 
1101c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
1102c91c1c84SLorenzo Bianconi 	if (hub_settings->master_en.addr) {
1103c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_shub_probe(hw, name);
1104c91c1c84SLorenzo Bianconi 		if (err < 0)
1105c91c1c84SLorenzo Bianconi 			return err;
1106c91c1c84SLorenzo Bianconi 	}
1107c91c1c84SLorenzo Bianconi 
1108290a6ce1SLorenzo Bianconi 	if (hw->irq > 0) {
1109290a6ce1SLorenzo Bianconi 		err = st_lsm6dsx_fifo_setup(hw);
1110290a6ce1SLorenzo Bianconi 		if (err < 0)
1111290a6ce1SLorenzo Bianconi 			return err;
1112290a6ce1SLorenzo Bianconi 	}
1113290a6ce1SLorenzo Bianconi 
1114290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
11156ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
11166ffb55e5SLorenzo Bianconi 			continue;
11176ffb55e5SLorenzo Bianconi 
1118290a6ce1SLorenzo Bianconi 		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
1119290a6ce1SLorenzo Bianconi 		if (err)
1120290a6ce1SLorenzo Bianconi 			return err;
1121290a6ce1SLorenzo Bianconi 	}
1122290a6ce1SLorenzo Bianconi 
1123290a6ce1SLorenzo Bianconi 	return 0;
1124290a6ce1SLorenzo Bianconi }
1125290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe);
1126290a6ce1SLorenzo Bianconi 
11273cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
1128d3f77058SLorenzo Bianconi {
1129d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
1130d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
113151a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
1132739aff87SLorenzo Bianconi 	unsigned int data;
1133d3f77058SLorenzo Bianconi 	int i, err = 0;
1134d3f77058SLorenzo Bianconi 
1135d3f77058SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
11366ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
11376ffb55e5SLorenzo Bianconi 			continue;
11386ffb55e5SLorenzo Bianconi 
1139d3f77058SLorenzo Bianconi 		sensor = iio_priv(hw->iio_devs[i]);
1140d3f77058SLorenzo Bianconi 		if (!(hw->enable_mask & BIT(sensor->id)))
1141d3f77058SLorenzo Bianconi 			continue;
1142d3f77058SLorenzo Bianconi 
114351a8b707SLorenzo Bianconi 		reg = &st_lsm6dsx_odr_table[sensor->id].reg;
1144739aff87SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(0, reg->mask);
1145739aff87SLorenzo Bianconi 		err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask,
1146739aff87SLorenzo Bianconi 						    data);
1147d3f77058SLorenzo Bianconi 		if (err < 0)
1148d3f77058SLorenzo Bianconi 			return err;
1149d3f77058SLorenzo Bianconi 	}
1150d3f77058SLorenzo Bianconi 
1151d3f77058SLorenzo Bianconi 	if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS)
1152d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_flush_fifo(hw);
1153d3f77058SLorenzo Bianconi 
1154d3f77058SLorenzo Bianconi 	return err;
1155d3f77058SLorenzo Bianconi }
1156d3f77058SLorenzo Bianconi 
11573cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
1158d3f77058SLorenzo Bianconi {
1159d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
1160d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
1161d3f77058SLorenzo Bianconi 	int i, err = 0;
1162d3f77058SLorenzo Bianconi 
1163d3f77058SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
11646ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
11656ffb55e5SLorenzo Bianconi 			continue;
11666ffb55e5SLorenzo Bianconi 
1167d3f77058SLorenzo Bianconi 		sensor = iio_priv(hw->iio_devs[i]);
1168d3f77058SLorenzo Bianconi 		if (!(hw->enable_mask & BIT(sensor->id)))
1169d3f77058SLorenzo Bianconi 			continue;
1170d3f77058SLorenzo Bianconi 
1171d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_set_odr(sensor, sensor->odr);
1172d3f77058SLorenzo Bianconi 		if (err < 0)
1173d3f77058SLorenzo Bianconi 			return err;
1174d3f77058SLorenzo Bianconi 	}
1175d3f77058SLorenzo Bianconi 
1176d3f77058SLorenzo Bianconi 	if (hw->enable_mask)
1177d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
1178d3f77058SLorenzo Bianconi 
1179d3f77058SLorenzo Bianconi 	return err;
1180d3f77058SLorenzo Bianconi }
1181d3f77058SLorenzo Bianconi 
1182d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = {
1183d3f77058SLorenzo Bianconi 	SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume)
1184d3f77058SLorenzo Bianconi };
1185d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops);
1186d3f77058SLorenzo Bianconi 
1187290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
1188290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
1189290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
1190290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2");
1191