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  *
26801a6e0aSLorenzo Bianconi  * - LSM6DSO
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,
290801a6e0aSLorenzo Bianconi 		},
291801a6e0aSLorenzo Bianconi 		.batch = {
292801a6e0aSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
293801a6e0aSLorenzo Bianconi 				.addr = 0x09,
294801a6e0aSLorenzo Bianconi 				.mask = GENMASK(3, 0),
295801a6e0aSLorenzo Bianconi 			},
296801a6e0aSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
297801a6e0aSLorenzo Bianconi 				.addr = 0x09,
298801a6e0aSLorenzo Bianconi 				.mask = GENMASK(7, 4),
299801a6e0aSLorenzo Bianconi 			},
300801a6e0aSLorenzo Bianconi 		},
301801a6e0aSLorenzo Bianconi 		.fifo_ops = {
302801a6e0aSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_tagged_fifo,
303801a6e0aSLorenzo Bianconi 			.fifo_th = {
304801a6e0aSLorenzo Bianconi 				.addr = 0x07,
305801a6e0aSLorenzo Bianconi 				.mask = GENMASK(8, 0),
306801a6e0aSLorenzo Bianconi 			},
307801a6e0aSLorenzo Bianconi 			.fifo_diff = {
308801a6e0aSLorenzo Bianconi 				.addr = 0x3a,
309801a6e0aSLorenzo Bianconi 				.mask = GENMASK(8, 0),
310801a6e0aSLorenzo Bianconi 			},
311801a6e0aSLorenzo Bianconi 			.th_wl = 1,
312801a6e0aSLorenzo Bianconi 		},
313801a6e0aSLorenzo Bianconi 		.ts_settings = {
314801a6e0aSLorenzo Bianconi 			.timer_en = {
315801a6e0aSLorenzo Bianconi 				.addr = 0x19,
316801a6e0aSLorenzo Bianconi 				.mask = BIT(5),
317801a6e0aSLorenzo Bianconi 			},
318801a6e0aSLorenzo Bianconi 			.decimator = {
319801a6e0aSLorenzo Bianconi 				.addr = 0x0a,
320801a6e0aSLorenzo Bianconi 				.mask = GENMASK(7, 6),
321801a6e0aSLorenzo Bianconi 			},
322801a6e0aSLorenzo Bianconi 		},
323c91c1c84SLorenzo Bianconi 		.shub_settings = {
324c91c1c84SLorenzo Bianconi 			.page_mux = {
325c91c1c84SLorenzo Bianconi 				.addr = 0x01,
326c91c1c84SLorenzo Bianconi 				.mask = BIT(6),
327c91c1c84SLorenzo Bianconi 			},
328c91c1c84SLorenzo Bianconi 			.master_en = {
329c91c1c84SLorenzo Bianconi 				.addr = 0x14,
330c91c1c84SLorenzo Bianconi 				.mask = BIT(2),
331c91c1c84SLorenzo Bianconi 			},
332c91c1c84SLorenzo Bianconi 			.pullup_en = {
333c91c1c84SLorenzo Bianconi 				.addr = 0x14,
334c91c1c84SLorenzo Bianconi 				.mask = BIT(3),
335c91c1c84SLorenzo Bianconi 			},
336c91c1c84SLorenzo Bianconi 			.aux_sens = {
337c91c1c84SLorenzo Bianconi 				.addr = 0x14,
338c91c1c84SLorenzo Bianconi 				.mask = GENMASK(1, 0),
339c91c1c84SLorenzo Bianconi 			},
340c91c1c84SLorenzo Bianconi 			.shub_out = 0x02,
341c91c1c84SLorenzo Bianconi 			.slv0_addr = 0x15,
342c91c1c84SLorenzo Bianconi 			.dw_slv0_addr = 0x21,
343c91c1c84SLorenzo Bianconi 		}
344801a6e0aSLorenzo Bianconi 	},
345290a6ce1SLorenzo Bianconi };
346290a6ce1SLorenzo Bianconi 
347290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
348290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
349290a6ce1SLorenzo Bianconi 			   IIO_MOD_X, 0),
350290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
351290a6ce1SLorenzo Bianconi 			   IIO_MOD_Y, 1),
352290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
353290a6ce1SLorenzo Bianconi 			   IIO_MOD_Z, 2),
354290a6ce1SLorenzo Bianconi 	IIO_CHAN_SOFT_TIMESTAMP(3),
355290a6ce1SLorenzo Bianconi };
356290a6ce1SLorenzo Bianconi 
357290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
358290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR,
359290a6ce1SLorenzo Bianconi 			   IIO_MOD_X, 0),
360290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR,
361290a6ce1SLorenzo Bianconi 			   IIO_MOD_Y, 1),
362290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR,
363290a6ce1SLorenzo Bianconi 			   IIO_MOD_Z, 2),
364290a6ce1SLorenzo Bianconi 	IIO_CHAN_SOFT_TIMESTAMP(3),
365290a6ce1SLorenzo Bianconi };
366290a6ce1SLorenzo Bianconi 
367c91c1c84SLorenzo Bianconi int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
368c91c1c84SLorenzo Bianconi {
369c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
370c91c1c84SLorenzo Bianconi 	unsigned int data;
371c91c1c84SLorenzo Bianconi 	int err;
372c91c1c84SLorenzo Bianconi 
373c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
374c91c1c84SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->page_mux.mask);
375c91c1c84SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, hub_settings->page_mux.addr,
376c91c1c84SLorenzo Bianconi 				 hub_settings->page_mux.mask, data);
377c91c1c84SLorenzo Bianconi 	usleep_range(100, 150);
378c91c1c84SLorenzo Bianconi 
379c91c1c84SLorenzo Bianconi 	return err;
380c91c1c84SLorenzo Bianconi }
381c91c1c84SLorenzo Bianconi 
382290a6ce1SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
383290a6ce1SLorenzo Bianconi {
38451a8b707SLorenzo Bianconi 	int err, i, j, data;
385290a6ce1SLorenzo Bianconi 
386290a6ce1SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
387d068e4a0SLorenzo Bianconi 		for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) {
388d068e4a0SLorenzo Bianconi 			if (id == st_lsm6dsx_sensor_settings[i].id[j])
389d068e4a0SLorenzo Bianconi 				break;
390d068e4a0SLorenzo Bianconi 		}
391d068e4a0SLorenzo Bianconi 		if (j < ST_LSM6DSX_MAX_ID)
392290a6ce1SLorenzo Bianconi 			break;
393290a6ce1SLorenzo Bianconi 	}
394290a6ce1SLorenzo Bianconi 
395290a6ce1SLorenzo Bianconi 	if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) {
396290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "unsupported hw id [%02x]\n", id);
397290a6ce1SLorenzo Bianconi 		return -ENODEV;
398290a6ce1SLorenzo Bianconi 	}
399290a6ce1SLorenzo Bianconi 
40051a8b707SLorenzo Bianconi 	err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data);
401290a6ce1SLorenzo Bianconi 	if (err < 0) {
402290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "failed to read whoami register\n");
403290a6ce1SLorenzo Bianconi 		return err;
404290a6ce1SLorenzo Bianconi 	}
405290a6ce1SLorenzo Bianconi 
406290a6ce1SLorenzo Bianconi 	if (data != st_lsm6dsx_sensor_settings[i].wai) {
407290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
408290a6ce1SLorenzo Bianconi 		return -ENODEV;
409290a6ce1SLorenzo Bianconi 	}
410290a6ce1SLorenzo Bianconi 
411290a6ce1SLorenzo Bianconi 	hw->settings = &st_lsm6dsx_sensor_settings[i];
412290a6ce1SLorenzo Bianconi 
413290a6ce1SLorenzo Bianconi 	return 0;
414290a6ce1SLorenzo Bianconi }
415290a6ce1SLorenzo Bianconi 
416290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
417290a6ce1SLorenzo Bianconi 				     u32 gain)
418290a6ce1SLorenzo Bianconi {
41951a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
42051a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
421739aff87SLorenzo Bianconi 	unsigned int data;
422290a6ce1SLorenzo Bianconi 	int i, err;
423290a6ce1SLorenzo Bianconi 	u8 val;
424290a6ce1SLorenzo Bianconi 
425290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
42651a8b707SLorenzo Bianconi 		if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain)
427290a6ce1SLorenzo Bianconi 			break;
428290a6ce1SLorenzo Bianconi 
429290a6ce1SLorenzo Bianconi 	if (i == ST_LSM6DSX_FS_LIST_SIZE)
430290a6ce1SLorenzo Bianconi 		return -EINVAL;
431290a6ce1SLorenzo Bianconi 
43251a8b707SLorenzo Bianconi 	val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val;
43351a8b707SLorenzo Bianconi 	reg = &st_lsm6dsx_fs_table[sensor->id].reg;
434739aff87SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
435739aff87SLorenzo Bianconi 	err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
436290a6ce1SLorenzo Bianconi 	if (err < 0)
437290a6ce1SLorenzo Bianconi 		return err;
438290a6ce1SLorenzo Bianconi 
439290a6ce1SLorenzo Bianconi 	sensor->gain = gain;
440290a6ce1SLorenzo Bianconi 
441290a6ce1SLorenzo Bianconi 	return 0;
442290a6ce1SLorenzo Bianconi }
443290a6ce1SLorenzo Bianconi 
44454a6d0c6SLorenzo Bianconi int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
445290a6ce1SLorenzo Bianconi {
4462ccc1503SLorenzo Bianconi 	int i;
447290a6ce1SLorenzo Bianconi 
448290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
4496ffb55e5SLorenzo Bianconi 		/*
4506ffb55e5SLorenzo Bianconi 		 * ext devices can run at different odr respect to
4516ffb55e5SLorenzo Bianconi 		 * accel sensor
4526ffb55e5SLorenzo Bianconi 		 */
4536ffb55e5SLorenzo Bianconi 		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
454290a6ce1SLorenzo Bianconi 			break;
455290a6ce1SLorenzo Bianconi 
456290a6ce1SLorenzo Bianconi 	if (i == ST_LSM6DSX_ODR_LIST_SIZE)
457290a6ce1SLorenzo Bianconi 		return -EINVAL;
458290a6ce1SLorenzo Bianconi 
4592ccc1503SLorenzo Bianconi 	*val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val;
460290a6ce1SLorenzo Bianconi 
461290a6ce1SLorenzo Bianconi 	return 0;
462290a6ce1SLorenzo Bianconi }
463290a6ce1SLorenzo Bianconi 
4646ffb55e5SLorenzo Bianconi static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
4656ffb55e5SLorenzo Bianconi 					   enum st_lsm6dsx_sensor_id id)
4662ccc1503SLorenzo Bianconi {
4676ffb55e5SLorenzo Bianconi 	struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
4686ffb55e5SLorenzo Bianconi 
4696ffb55e5SLorenzo Bianconi 	if (odr > 0) {
4706ffb55e5SLorenzo Bianconi 		if (hw->enable_mask & BIT(id))
4716ffb55e5SLorenzo Bianconi 			return max_t(u16, ref->odr, odr);
4726ffb55e5SLorenzo Bianconi 		else
4736ffb55e5SLorenzo Bianconi 			return odr;
4746ffb55e5SLorenzo Bianconi 	} else {
4756ffb55e5SLorenzo Bianconi 		return (hw->enable_mask & BIT(id)) ? ref->odr : 0;
4766ffb55e5SLorenzo Bianconi 	}
4776ffb55e5SLorenzo Bianconi }
4786ffb55e5SLorenzo Bianconi 
4796ffb55e5SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
4806ffb55e5SLorenzo Bianconi {
4816ffb55e5SLorenzo Bianconi 	struct st_lsm6dsx_sensor *ref_sensor = sensor;
48251a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
48351a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
484739aff87SLorenzo Bianconi 	unsigned int data;
4856ffb55e5SLorenzo Bianconi 	u8 val = 0;
4862ccc1503SLorenzo Bianconi 	int err;
4872ccc1503SLorenzo Bianconi 
4886ffb55e5SLorenzo Bianconi 	switch (sensor->id) {
4896ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT0:
4906ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT1:
4916ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT2:
4926ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_ACC: {
4936ffb55e5SLorenzo Bianconi 		u16 odr;
4946ffb55e5SLorenzo Bianconi 		int i;
4956ffb55e5SLorenzo Bianconi 
4966ffb55e5SLorenzo Bianconi 		/*
4976ffb55e5SLorenzo Bianconi 		 * i2c embedded controller relies on the accelerometer sensor as
4986ffb55e5SLorenzo Bianconi 		 * bus read/write trigger so we need to enable accel device
4996ffb55e5SLorenzo Bianconi 		 * at odr = max(accel_odr, ext_odr) in order to properly
5006ffb55e5SLorenzo Bianconi 		 * communicate with i2c slave devices
5016ffb55e5SLorenzo Bianconi 		 */
5026ffb55e5SLorenzo Bianconi 		ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
5036ffb55e5SLorenzo Bianconi 		for (i = ST_LSM6DSX_ID_ACC; i < ST_LSM6DSX_ID_MAX; i++) {
5046ffb55e5SLorenzo Bianconi 			if (!hw->iio_devs[i] || i == sensor->id)
5056ffb55e5SLorenzo Bianconi 				continue;
5066ffb55e5SLorenzo Bianconi 
5076ffb55e5SLorenzo Bianconi 			odr = st_lsm6dsx_check_odr_dependency(hw, req_odr, i);
5086ffb55e5SLorenzo Bianconi 			if (odr != req_odr)
5096ffb55e5SLorenzo Bianconi 				/* device already configured */
5106ffb55e5SLorenzo Bianconi 				return 0;
5116ffb55e5SLorenzo Bianconi 		}
5126ffb55e5SLorenzo Bianconi 		break;
5136ffb55e5SLorenzo Bianconi 	}
5146ffb55e5SLorenzo Bianconi 	default:
5156ffb55e5SLorenzo Bianconi 		break;
5166ffb55e5SLorenzo Bianconi 	}
5176ffb55e5SLorenzo Bianconi 
5186ffb55e5SLorenzo Bianconi 	if (req_odr > 0) {
5196ffb55e5SLorenzo Bianconi 		err = st_lsm6dsx_check_odr(ref_sensor, req_odr, &val);
5202ccc1503SLorenzo Bianconi 		if (err < 0)
5212ccc1503SLorenzo Bianconi 			return err;
5226ffb55e5SLorenzo Bianconi 	}
5232ccc1503SLorenzo Bianconi 
5246ffb55e5SLorenzo Bianconi 	reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg;
525739aff87SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
526739aff87SLorenzo Bianconi 	return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
5272ccc1503SLorenzo Bianconi }
5282ccc1503SLorenzo Bianconi 
52917750443SLorenzo Bianconi int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
53017750443SLorenzo Bianconi 				 bool enable)
531290a6ce1SLorenzo Bianconi {
53251a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
53317750443SLorenzo Bianconi 	u16 odr = enable ? sensor->odr : 0;
534290a6ce1SLorenzo Bianconi 	int err;
535290a6ce1SLorenzo Bianconi 
53617750443SLorenzo Bianconi 	err = st_lsm6dsx_set_odr(sensor, odr);
537290a6ce1SLorenzo Bianconi 	if (err < 0)
538290a6ce1SLorenzo Bianconi 		return err;
539290a6ce1SLorenzo Bianconi 
54017750443SLorenzo Bianconi 	if (enable)
54117750443SLorenzo Bianconi 		hw->enable_mask |= BIT(sensor->id);
54217750443SLorenzo Bianconi 	else
54317750443SLorenzo Bianconi 		hw->enable_mask &= ~BIT(sensor->id);
544290a6ce1SLorenzo Bianconi 
545290a6ce1SLorenzo Bianconi 	return 0;
546290a6ce1SLorenzo Bianconi }
547290a6ce1SLorenzo Bianconi 
548290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
549290a6ce1SLorenzo Bianconi 				   u8 addr, int *val)
550290a6ce1SLorenzo Bianconi {
55151a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
552290a6ce1SLorenzo Bianconi 	int err, delay;
553290a6ce1SLorenzo Bianconi 	__le16 data;
554290a6ce1SLorenzo Bianconi 
55517750443SLorenzo Bianconi 	err = st_lsm6dsx_sensor_set_enable(sensor, true);
556290a6ce1SLorenzo Bianconi 	if (err < 0)
557290a6ce1SLorenzo Bianconi 		return err;
558290a6ce1SLorenzo Bianconi 
559290a6ce1SLorenzo Bianconi 	delay = 1000000 / sensor->odr;
560290a6ce1SLorenzo Bianconi 	usleep_range(delay, 2 * delay);
561290a6ce1SLorenzo Bianconi 
562739aff87SLorenzo Bianconi 	err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
563290a6ce1SLorenzo Bianconi 	if (err < 0)
564290a6ce1SLorenzo Bianconi 		return err;
565290a6ce1SLorenzo Bianconi 
56617750443SLorenzo Bianconi 	st_lsm6dsx_sensor_set_enable(sensor, false);
567290a6ce1SLorenzo Bianconi 
5687b9ebe42SLorenzo Bianconi 	*val = (s16)le16_to_cpu(data);
569290a6ce1SLorenzo Bianconi 
570290a6ce1SLorenzo Bianconi 	return IIO_VAL_INT;
571290a6ce1SLorenzo Bianconi }
572290a6ce1SLorenzo Bianconi 
573290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
574290a6ce1SLorenzo Bianconi 			       struct iio_chan_spec const *ch,
575290a6ce1SLorenzo Bianconi 			       int *val, int *val2, long mask)
576290a6ce1SLorenzo Bianconi {
577290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
578290a6ce1SLorenzo Bianconi 	int ret;
579290a6ce1SLorenzo Bianconi 
580290a6ce1SLorenzo Bianconi 	switch (mask) {
581290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_RAW:
582290a6ce1SLorenzo Bianconi 		ret = iio_device_claim_direct_mode(iio_dev);
583290a6ce1SLorenzo Bianconi 		if (ret)
584290a6ce1SLorenzo Bianconi 			break;
585290a6ce1SLorenzo Bianconi 
586290a6ce1SLorenzo Bianconi 		ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val);
587290a6ce1SLorenzo Bianconi 		iio_device_release_direct_mode(iio_dev);
588290a6ce1SLorenzo Bianconi 		break;
589290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SAMP_FREQ:
590290a6ce1SLorenzo Bianconi 		*val = sensor->odr;
591290a6ce1SLorenzo Bianconi 		ret = IIO_VAL_INT;
592290a6ce1SLorenzo Bianconi 		break;
593290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SCALE:
594290a6ce1SLorenzo Bianconi 		*val = 0;
595290a6ce1SLorenzo Bianconi 		*val2 = sensor->gain;
596290a6ce1SLorenzo Bianconi 		ret = IIO_VAL_INT_PLUS_MICRO;
597290a6ce1SLorenzo Bianconi 		break;
598290a6ce1SLorenzo Bianconi 	default:
599290a6ce1SLorenzo Bianconi 		ret = -EINVAL;
600290a6ce1SLorenzo Bianconi 		break;
601290a6ce1SLorenzo Bianconi 	}
602290a6ce1SLorenzo Bianconi 
603290a6ce1SLorenzo Bianconi 	return ret;
604290a6ce1SLorenzo Bianconi }
605290a6ce1SLorenzo Bianconi 
606290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
607290a6ce1SLorenzo Bianconi 				struct iio_chan_spec const *chan,
608290a6ce1SLorenzo Bianconi 				int val, int val2, long mask)
609290a6ce1SLorenzo Bianconi {
610290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
611290a6ce1SLorenzo Bianconi 	int err;
612290a6ce1SLorenzo Bianconi 
613290a6ce1SLorenzo Bianconi 	err = iio_device_claim_direct_mode(iio_dev);
614290a6ce1SLorenzo Bianconi 	if (err)
615290a6ce1SLorenzo Bianconi 		return err;
616290a6ce1SLorenzo Bianconi 
617290a6ce1SLorenzo Bianconi 	switch (mask) {
618290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SCALE:
619290a6ce1SLorenzo Bianconi 		err = st_lsm6dsx_set_full_scale(sensor, val2);
620290a6ce1SLorenzo Bianconi 		break;
6212ccc1503SLorenzo Bianconi 	case IIO_CHAN_INFO_SAMP_FREQ: {
6222ccc1503SLorenzo Bianconi 		u8 data;
6232ccc1503SLorenzo Bianconi 
6242ccc1503SLorenzo Bianconi 		err = st_lsm6dsx_check_odr(sensor, val, &data);
6255e3c3e33SLorenzo Bianconi 		if (!err)
6265e3c3e33SLorenzo Bianconi 			sensor->odr = val;
627290a6ce1SLorenzo Bianconi 		break;
6282ccc1503SLorenzo Bianconi 	}
629290a6ce1SLorenzo Bianconi 	default:
630290a6ce1SLorenzo Bianconi 		err = -EINVAL;
631290a6ce1SLorenzo Bianconi 		break;
632290a6ce1SLorenzo Bianconi 	}
633290a6ce1SLorenzo Bianconi 
634290a6ce1SLorenzo Bianconi 	iio_device_release_direct_mode(iio_dev);
635290a6ce1SLorenzo Bianconi 
636290a6ce1SLorenzo Bianconi 	return err;
637290a6ce1SLorenzo Bianconi }
638290a6ce1SLorenzo Bianconi 
639d40464f3SLorenzo Bianconi int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
640290a6ce1SLorenzo Bianconi {
641290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
642290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
6438f2a88a2SLorenzo Bianconi 	int err;
644290a6ce1SLorenzo Bianconi 
6458f2a88a2SLorenzo Bianconi 	if (val < 1 || val > hw->settings->max_fifo_size)
646290a6ce1SLorenzo Bianconi 		return -EINVAL;
647290a6ce1SLorenzo Bianconi 
648335eaedcSLorenzo Bianconi 	mutex_lock(&hw->conf_lock);
649335eaedcSLorenzo Bianconi 
650290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_update_watermark(sensor, val);
651335eaedcSLorenzo Bianconi 
652335eaedcSLorenzo Bianconi 	mutex_unlock(&hw->conf_lock);
653335eaedcSLorenzo Bianconi 
654290a6ce1SLorenzo Bianconi 	if (err < 0)
655290a6ce1SLorenzo Bianconi 		return err;
656290a6ce1SLorenzo Bianconi 
657290a6ce1SLorenzo Bianconi 	sensor->watermark = val;
658290a6ce1SLorenzo Bianconi 
659290a6ce1SLorenzo Bianconi 	return 0;
660290a6ce1SLorenzo Bianconi }
661290a6ce1SLorenzo Bianconi 
662290a6ce1SLorenzo Bianconi static ssize_t
663290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
664290a6ce1SLorenzo Bianconi 					  struct device_attribute *attr,
665290a6ce1SLorenzo Bianconi 					  char *buf)
666290a6ce1SLorenzo Bianconi {
667290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
668290a6ce1SLorenzo Bianconi 	enum st_lsm6dsx_sensor_id id = sensor->id;
669290a6ce1SLorenzo Bianconi 	int i, len = 0;
670290a6ce1SLorenzo Bianconi 
671290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
672290a6ce1SLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
673290a6ce1SLorenzo Bianconi 				 st_lsm6dsx_odr_table[id].odr_avl[i].hz);
674290a6ce1SLorenzo Bianconi 	buf[len - 1] = '\n';
675290a6ce1SLorenzo Bianconi 
676290a6ce1SLorenzo Bianconi 	return len;
677290a6ce1SLorenzo Bianconi }
678290a6ce1SLorenzo Bianconi 
679290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
680290a6ce1SLorenzo Bianconi 					    struct device_attribute *attr,
681290a6ce1SLorenzo Bianconi 					    char *buf)
682290a6ce1SLorenzo Bianconi {
683290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
684290a6ce1SLorenzo Bianconi 	enum st_lsm6dsx_sensor_id id = sensor->id;
685290a6ce1SLorenzo Bianconi 	int i, len = 0;
686290a6ce1SLorenzo Bianconi 
687290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
688290a6ce1SLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
689290a6ce1SLorenzo Bianconi 				 st_lsm6dsx_fs_table[id].fs_avl[i].gain);
690290a6ce1SLorenzo Bianconi 	buf[len - 1] = '\n';
691290a6ce1SLorenzo Bianconi 
692290a6ce1SLorenzo Bianconi 	return len;
693290a6ce1SLorenzo Bianconi }
694290a6ce1SLorenzo Bianconi 
695290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail);
696290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
697290a6ce1SLorenzo Bianconi 		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
698290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444,
699290a6ce1SLorenzo Bianconi 		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
700290a6ce1SLorenzo Bianconi 
701290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = {
702290a6ce1SLorenzo Bianconi 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
703290a6ce1SLorenzo Bianconi 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
704290a6ce1SLorenzo Bianconi 	NULL,
705290a6ce1SLorenzo Bianconi };
706290a6ce1SLorenzo Bianconi 
707290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = {
708290a6ce1SLorenzo Bianconi 	.attrs = st_lsm6dsx_acc_attributes,
709290a6ce1SLorenzo Bianconi };
710290a6ce1SLorenzo Bianconi 
711290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = {
712290a6ce1SLorenzo Bianconi 	.attrs = &st_lsm6dsx_acc_attribute_group,
713290a6ce1SLorenzo Bianconi 	.read_raw = st_lsm6dsx_read_raw,
714290a6ce1SLorenzo Bianconi 	.write_raw = st_lsm6dsx_write_raw,
715290a6ce1SLorenzo Bianconi 	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
716290a6ce1SLorenzo Bianconi };
717290a6ce1SLorenzo Bianconi 
718290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = {
719290a6ce1SLorenzo Bianconi 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
720290a6ce1SLorenzo Bianconi 	&iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
721290a6ce1SLorenzo Bianconi 	NULL,
722290a6ce1SLorenzo Bianconi };
723290a6ce1SLorenzo Bianconi 
724290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = {
725290a6ce1SLorenzo Bianconi 	.attrs = st_lsm6dsx_gyro_attributes,
726290a6ce1SLorenzo Bianconi };
727290a6ce1SLorenzo Bianconi 
728290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = {
729290a6ce1SLorenzo Bianconi 	.attrs = &st_lsm6dsx_gyro_attribute_group,
730290a6ce1SLorenzo Bianconi 	.read_raw = st_lsm6dsx_read_raw,
731290a6ce1SLorenzo Bianconi 	.write_raw = st_lsm6dsx_write_raw,
732290a6ce1SLorenzo Bianconi 	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
733290a6ce1SLorenzo Bianconi };
734290a6ce1SLorenzo Bianconi 
735dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
736dba32904SLorenzo Bianconi {
737dba32904SLorenzo Bianconi 	struct device_node *np = hw->dev->of_node;
738dba32904SLorenzo Bianconi 
739dba32904SLorenzo Bianconi 	if (!np)
740dba32904SLorenzo Bianconi 		return -EINVAL;
741dba32904SLorenzo Bianconi 
742bf235277SLorenzo Bianconi 	return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
743dba32904SLorenzo Bianconi }
744dba32904SLorenzo Bianconi 
745dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
746dba32904SLorenzo Bianconi {
747dba32904SLorenzo Bianconi 	int err = 0, drdy_pin;
748dba32904SLorenzo Bianconi 
749dba32904SLorenzo Bianconi 	if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) {
750dba32904SLorenzo Bianconi 		struct st_sensors_platform_data *pdata;
751dba32904SLorenzo Bianconi 		struct device *dev = hw->dev;
752dba32904SLorenzo Bianconi 
753dba32904SLorenzo Bianconi 		pdata = (struct st_sensors_platform_data *)dev->platform_data;
754dba32904SLorenzo Bianconi 		drdy_pin = pdata ? pdata->drdy_int_pin : 1;
755dba32904SLorenzo Bianconi 	}
756dba32904SLorenzo Bianconi 
757dba32904SLorenzo Bianconi 	switch (drdy_pin) {
758dba32904SLorenzo Bianconi 	case 1:
759dba32904SLorenzo Bianconi 		*drdy_reg = ST_LSM6DSX_REG_INT1_ADDR;
760dba32904SLorenzo Bianconi 		break;
761dba32904SLorenzo Bianconi 	case 2:
762dba32904SLorenzo Bianconi 		*drdy_reg = ST_LSM6DSX_REG_INT2_ADDR;
763dba32904SLorenzo Bianconi 		break;
764dba32904SLorenzo Bianconi 	default:
765dba32904SLorenzo Bianconi 		dev_err(hw->dev, "unsupported data ready pin\n");
766dba32904SLorenzo Bianconi 		err = -EINVAL;
767dba32904SLorenzo Bianconi 		break;
768dba32904SLorenzo Bianconi 	}
769dba32904SLorenzo Bianconi 
770dba32904SLorenzo Bianconi 	return err;
771dba32904SLorenzo Bianconi }
772dba32904SLorenzo Bianconi 
773c91c1c84SLorenzo Bianconi static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
774c91c1c84SLorenzo Bianconi {
775c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
776c91c1c84SLorenzo Bianconi 	struct device_node *np = hw->dev->of_node;
777c91c1c84SLorenzo Bianconi 	struct st_sensors_platform_data *pdata;
778c91c1c84SLorenzo Bianconi 	unsigned int data;
779c91c1c84SLorenzo Bianconi 	int err = 0;
780c91c1c84SLorenzo Bianconi 
781c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
782c91c1c84SLorenzo Bianconi 
783c91c1c84SLorenzo Bianconi 	pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
784c91c1c84SLorenzo Bianconi 	if ((np && of_property_read_bool(np, "st,pullups")) ||
785c91c1c84SLorenzo Bianconi 	    (pdata && pdata->pullups)) {
786c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_set_page(hw, true);
787c91c1c84SLorenzo Bianconi 		if (err < 0)
788c91c1c84SLorenzo Bianconi 			return err;
789c91c1c84SLorenzo Bianconi 
790c91c1c84SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->pullup_en.mask);
791c91c1c84SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
792c91c1c84SLorenzo Bianconi 					 hub_settings->pullup_en.addr,
793c91c1c84SLorenzo Bianconi 					 hub_settings->pullup_en.mask, data);
794c91c1c84SLorenzo Bianconi 
795c91c1c84SLorenzo Bianconi 		st_lsm6dsx_set_page(hw, false);
796c91c1c84SLorenzo Bianconi 
797c91c1c84SLorenzo Bianconi 		if (err < 0)
798c91c1c84SLorenzo Bianconi 			return err;
799c91c1c84SLorenzo Bianconi 	}
800c91c1c84SLorenzo Bianconi 
801c91c1c84SLorenzo Bianconi 	if (hub_settings->aux_sens.addr) {
802c91c1c84SLorenzo Bianconi 		/* configure aux sensors */
803c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_set_page(hw, true);
804c91c1c84SLorenzo Bianconi 		if (err < 0)
805c91c1c84SLorenzo Bianconi 			return err;
806c91c1c84SLorenzo Bianconi 
807c91c1c84SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(3, hub_settings->aux_sens.mask);
808c91c1c84SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
809c91c1c84SLorenzo Bianconi 					 hub_settings->aux_sens.addr,
810c91c1c84SLorenzo Bianconi 					 hub_settings->aux_sens.mask, data);
811c91c1c84SLorenzo Bianconi 
812c91c1c84SLorenzo Bianconi 		st_lsm6dsx_set_page(hw, false);
813c91c1c84SLorenzo Bianconi 	}
814c91c1c84SLorenzo Bianconi 
815c91c1c84SLorenzo Bianconi 	return err;
816c91c1c84SLorenzo Bianconi }
817c91c1c84SLorenzo Bianconi 
81821345107SLorenzo Bianconi static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw)
81921345107SLorenzo Bianconi {
82021345107SLorenzo Bianconi 	const struct st_lsm6dsx_hw_ts_settings *ts_settings;
82121345107SLorenzo Bianconi 	int err, val;
82221345107SLorenzo Bianconi 
82321345107SLorenzo Bianconi 	ts_settings = &hw->settings->ts_settings;
82421345107SLorenzo Bianconi 	/* enable hw timestamp generation if necessary */
82521345107SLorenzo Bianconi 	if (ts_settings->timer_en.addr) {
82621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask);
82721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
82821345107SLorenzo Bianconi 					 ts_settings->timer_en.addr,
82921345107SLorenzo Bianconi 					 ts_settings->timer_en.mask, val);
83021345107SLorenzo Bianconi 		if (err < 0)
83121345107SLorenzo Bianconi 			return err;
83221345107SLorenzo Bianconi 	}
83321345107SLorenzo Bianconi 
83421345107SLorenzo Bianconi 	/* enable high resolution for hw ts timer if necessary */
83521345107SLorenzo Bianconi 	if (ts_settings->hr_timer.addr) {
83621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask);
83721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
83821345107SLorenzo Bianconi 					 ts_settings->hr_timer.addr,
83921345107SLorenzo Bianconi 					 ts_settings->hr_timer.mask, val);
84021345107SLorenzo Bianconi 		if (err < 0)
84121345107SLorenzo Bianconi 			return err;
84221345107SLorenzo Bianconi 	}
84321345107SLorenzo Bianconi 
84421345107SLorenzo Bianconi 	/* enable ts queueing in FIFO if necessary */
84521345107SLorenzo Bianconi 	if (ts_settings->fifo_en.addr) {
84621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask);
84721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
84821345107SLorenzo Bianconi 					 ts_settings->fifo_en.addr,
84921345107SLorenzo Bianconi 					 ts_settings->fifo_en.mask, val);
85021345107SLorenzo Bianconi 		if (err < 0)
85121345107SLorenzo Bianconi 			return err;
85221345107SLorenzo Bianconi 	}
85321345107SLorenzo Bianconi 	return 0;
85421345107SLorenzo Bianconi }
85521345107SLorenzo Bianconi 
856290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
857290a6ce1SLorenzo Bianconi {
85851a8b707SLorenzo Bianconi 	u8 drdy_int_reg;
859290a6ce1SLorenzo Bianconi 	int err;
860290a6ce1SLorenzo Bianconi 
86119435425SLorenzo Bianconi 	/* device sw reset */
86219435425SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
86319435425SLorenzo Bianconi 				 ST_LSM6DSX_REG_RESET_MASK,
86419435425SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1));
865290a6ce1SLorenzo Bianconi 	if (err < 0)
866290a6ce1SLorenzo Bianconi 		return err;
867290a6ce1SLorenzo Bianconi 
86819435425SLorenzo Bianconi 	msleep(50);
86919435425SLorenzo Bianconi 
87019435425SLorenzo Bianconi 	/* reload trimming parameter */
87119435425SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
87219435425SLorenzo Bianconi 				 ST_LSM6DSX_REG_BOOT_MASK,
87319435425SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1));
87419435425SLorenzo Bianconi 	if (err < 0)
87519435425SLorenzo Bianconi 		return err;
87619435425SLorenzo Bianconi 
87719435425SLorenzo Bianconi 	msleep(50);
878290a6ce1SLorenzo Bianconi 
879290a6ce1SLorenzo Bianconi 	/* enable Block Data Update */
88051a8b707SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR,
88151a8b707SLorenzo Bianconi 				 ST_LSM6DSX_REG_BDU_MASK,
88251a8b707SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1));
883290a6ce1SLorenzo Bianconi 	if (err < 0)
884290a6ce1SLorenzo Bianconi 		return err;
885290a6ce1SLorenzo Bianconi 
886290a6ce1SLorenzo Bianconi 	/* enable FIFO watermak interrupt */
887dba32904SLorenzo Bianconi 	err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg);
888290a6ce1SLorenzo Bianconi 	if (err < 0)
889290a6ce1SLorenzo Bianconi 		return err;
890290a6ce1SLorenzo Bianconi 
89121345107SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, drdy_int_reg,
89251a8b707SLorenzo Bianconi 				 ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
89351a8b707SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
89451a8b707SLorenzo Bianconi 					    1));
89521345107SLorenzo Bianconi 	if (err < 0)
89621345107SLorenzo Bianconi 		return err;
89721345107SLorenzo Bianconi 
898c91c1c84SLorenzo Bianconi 	err = st_lsm6dsx_init_shub(hw);
899c91c1c84SLorenzo Bianconi 	if (err < 0)
900c91c1c84SLorenzo Bianconi 		return err;
901c91c1c84SLorenzo Bianconi 
90221345107SLorenzo Bianconi 	return st_lsm6dsx_init_hw_timer(hw);
903290a6ce1SLorenzo Bianconi }
904290a6ce1SLorenzo Bianconi 
905290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
906510c0106SLorenzo Bianconi 					       enum st_lsm6dsx_sensor_id id,
907510c0106SLorenzo Bianconi 					       const char *name)
908290a6ce1SLorenzo Bianconi {
909290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
910290a6ce1SLorenzo Bianconi 	struct iio_dev *iio_dev;
911290a6ce1SLorenzo Bianconi 
912290a6ce1SLorenzo Bianconi 	iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
913290a6ce1SLorenzo Bianconi 	if (!iio_dev)
914290a6ce1SLorenzo Bianconi 		return NULL;
915290a6ce1SLorenzo Bianconi 
916290a6ce1SLorenzo Bianconi 	iio_dev->modes = INDIO_DIRECT_MODE;
917290a6ce1SLorenzo Bianconi 	iio_dev->dev.parent = hw->dev;
918290a6ce1SLorenzo Bianconi 	iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
919290a6ce1SLorenzo Bianconi 
920290a6ce1SLorenzo Bianconi 	sensor = iio_priv(iio_dev);
921290a6ce1SLorenzo Bianconi 	sensor->id = id;
922290a6ce1SLorenzo Bianconi 	sensor->hw = hw;
923290a6ce1SLorenzo Bianconi 	sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
924290a6ce1SLorenzo Bianconi 	sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
925290a6ce1SLorenzo Bianconi 	sensor->watermark = 1;
926290a6ce1SLorenzo Bianconi 
927290a6ce1SLorenzo Bianconi 	switch (id) {
928290a6ce1SLorenzo Bianconi 	case ST_LSM6DSX_ID_ACC:
929290a6ce1SLorenzo Bianconi 		iio_dev->channels = st_lsm6dsx_acc_channels;
930290a6ce1SLorenzo Bianconi 		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
931290a6ce1SLorenzo Bianconi 		iio_dev->info = &st_lsm6dsx_acc_info;
932290a6ce1SLorenzo Bianconi 
933510c0106SLorenzo Bianconi 		scnprintf(sensor->name, sizeof(sensor->name), "%s_accel",
934510c0106SLorenzo Bianconi 			  name);
935290a6ce1SLorenzo Bianconi 		break;
936290a6ce1SLorenzo Bianconi 	case ST_LSM6DSX_ID_GYRO:
937290a6ce1SLorenzo Bianconi 		iio_dev->channels = st_lsm6dsx_gyro_channels;
938290a6ce1SLorenzo Bianconi 		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
939290a6ce1SLorenzo Bianconi 		iio_dev->info = &st_lsm6dsx_gyro_info;
940290a6ce1SLorenzo Bianconi 
941510c0106SLorenzo Bianconi 		scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
942510c0106SLorenzo Bianconi 			  name);
943290a6ce1SLorenzo Bianconi 		break;
944290a6ce1SLorenzo Bianconi 	default:
945290a6ce1SLorenzo Bianconi 		return NULL;
946290a6ce1SLorenzo Bianconi 	}
947510c0106SLorenzo Bianconi 	iio_dev->name = sensor->name;
948290a6ce1SLorenzo Bianconi 
949290a6ce1SLorenzo Bianconi 	return iio_dev;
950290a6ce1SLorenzo Bianconi }
951290a6ce1SLorenzo Bianconi 
952510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name,
95351a8b707SLorenzo Bianconi 		     struct regmap *regmap)
954290a6ce1SLorenzo Bianconi {
955c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
956290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw;
957290a6ce1SLorenzo Bianconi 	int i, err;
958290a6ce1SLorenzo Bianconi 
959290a6ce1SLorenzo Bianconi 	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
960290a6ce1SLorenzo Bianconi 	if (!hw)
961290a6ce1SLorenzo Bianconi 		return -ENOMEM;
962290a6ce1SLorenzo Bianconi 
963290a6ce1SLorenzo Bianconi 	dev_set_drvdata(dev, (void *)hw);
964290a6ce1SLorenzo Bianconi 
965290a6ce1SLorenzo Bianconi 	mutex_init(&hw->fifo_lock);
966335eaedcSLorenzo Bianconi 	mutex_init(&hw->conf_lock);
967739aff87SLorenzo Bianconi 	mutex_init(&hw->page_lock);
968290a6ce1SLorenzo Bianconi 
96991a6b841SLorenzo Bianconi 	hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL);
97091a6b841SLorenzo Bianconi 	if (!hw->buff)
97191a6b841SLorenzo Bianconi 		return -ENOMEM;
97291a6b841SLorenzo Bianconi 
973290a6ce1SLorenzo Bianconi 	hw->dev = dev;
974290a6ce1SLorenzo Bianconi 	hw->irq = irq;
97551a8b707SLorenzo Bianconi 	hw->regmap = regmap;
976290a6ce1SLorenzo Bianconi 
977290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_check_whoami(hw, hw_id);
978290a6ce1SLorenzo Bianconi 	if (err < 0)
979290a6ce1SLorenzo Bianconi 		return err;
980290a6ce1SLorenzo Bianconi 
9816ffb55e5SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) {
982510c0106SLorenzo Bianconi 		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
983290a6ce1SLorenzo Bianconi 		if (!hw->iio_devs[i])
984290a6ce1SLorenzo Bianconi 			return -ENOMEM;
985290a6ce1SLorenzo Bianconi 	}
986290a6ce1SLorenzo Bianconi 
987290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_init_device(hw);
988290a6ce1SLorenzo Bianconi 	if (err < 0)
989290a6ce1SLorenzo Bianconi 		return err;
990290a6ce1SLorenzo Bianconi 
991c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
992c91c1c84SLorenzo Bianconi 	if (hub_settings->master_en.addr) {
993c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_shub_probe(hw, name);
994c91c1c84SLorenzo Bianconi 		if (err < 0)
995c91c1c84SLorenzo Bianconi 			return err;
996c91c1c84SLorenzo Bianconi 	}
997c91c1c84SLorenzo Bianconi 
998290a6ce1SLorenzo Bianconi 	if (hw->irq > 0) {
999290a6ce1SLorenzo Bianconi 		err = st_lsm6dsx_fifo_setup(hw);
1000290a6ce1SLorenzo Bianconi 		if (err < 0)
1001290a6ce1SLorenzo Bianconi 			return err;
1002290a6ce1SLorenzo Bianconi 	}
1003290a6ce1SLorenzo Bianconi 
1004290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
10056ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
10066ffb55e5SLorenzo Bianconi 			continue;
10076ffb55e5SLorenzo Bianconi 
1008290a6ce1SLorenzo Bianconi 		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
1009290a6ce1SLorenzo Bianconi 		if (err)
1010290a6ce1SLorenzo Bianconi 			return err;
1011290a6ce1SLorenzo Bianconi 	}
1012290a6ce1SLorenzo Bianconi 
1013290a6ce1SLorenzo Bianconi 	return 0;
1014290a6ce1SLorenzo Bianconi }
1015290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe);
1016290a6ce1SLorenzo Bianconi 
10173cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
1018d3f77058SLorenzo Bianconi {
1019d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
1020d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
102151a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
1022739aff87SLorenzo Bianconi 	unsigned int data;
1023d3f77058SLorenzo Bianconi 	int i, err = 0;
1024d3f77058SLorenzo Bianconi 
1025d3f77058SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
10266ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
10276ffb55e5SLorenzo Bianconi 			continue;
10286ffb55e5SLorenzo Bianconi 
1029d3f77058SLorenzo Bianconi 		sensor = iio_priv(hw->iio_devs[i]);
1030d3f77058SLorenzo Bianconi 		if (!(hw->enable_mask & BIT(sensor->id)))
1031d3f77058SLorenzo Bianconi 			continue;
1032d3f77058SLorenzo Bianconi 
103351a8b707SLorenzo Bianconi 		reg = &st_lsm6dsx_odr_table[sensor->id].reg;
1034739aff87SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(0, reg->mask);
1035739aff87SLorenzo Bianconi 		err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask,
1036739aff87SLorenzo Bianconi 						    data);
1037d3f77058SLorenzo Bianconi 		if (err < 0)
1038d3f77058SLorenzo Bianconi 			return err;
1039d3f77058SLorenzo Bianconi 	}
1040d3f77058SLorenzo Bianconi 
1041d3f77058SLorenzo Bianconi 	if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS)
1042d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_flush_fifo(hw);
1043d3f77058SLorenzo Bianconi 
1044d3f77058SLorenzo Bianconi 	return err;
1045d3f77058SLorenzo Bianconi }
1046d3f77058SLorenzo Bianconi 
10473cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
1048d3f77058SLorenzo Bianconi {
1049d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
1050d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
1051d3f77058SLorenzo Bianconi 	int i, err = 0;
1052d3f77058SLorenzo Bianconi 
1053d3f77058SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
10546ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
10556ffb55e5SLorenzo Bianconi 			continue;
10566ffb55e5SLorenzo Bianconi 
1057d3f77058SLorenzo Bianconi 		sensor = iio_priv(hw->iio_devs[i]);
1058d3f77058SLorenzo Bianconi 		if (!(hw->enable_mask & BIT(sensor->id)))
1059d3f77058SLorenzo Bianconi 			continue;
1060d3f77058SLorenzo Bianconi 
1061d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_set_odr(sensor, sensor->odr);
1062d3f77058SLorenzo Bianconi 		if (err < 0)
1063d3f77058SLorenzo Bianconi 			return err;
1064d3f77058SLorenzo Bianconi 	}
1065d3f77058SLorenzo Bianconi 
1066d3f77058SLorenzo Bianconi 	if (hw->enable_mask)
1067d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
1068d3f77058SLorenzo Bianconi 
1069d3f77058SLorenzo Bianconi 	return err;
1070d3f77058SLorenzo Bianconi }
1071d3f77058SLorenzo Bianconi 
1072d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = {
1073d3f77058SLorenzo Bianconi 	SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume)
1074d3f77058SLorenzo Bianconi };
1075d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops);
1076d3f77058SLorenzo Bianconi 
1077290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
1078290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
1079290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
1080290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2");
1081