1fda8d26eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2290a6ce1SLorenzo Bianconi /*
3290a6ce1SLorenzo Bianconi  * STMicroelectronics st_lsm6dsx sensor driver
4290a6ce1SLorenzo Bianconi  *
5290a6ce1SLorenzo Bianconi  * The ST LSM6DSx IMU MEMS series consists of 3D digital accelerometer
6290a6ce1SLorenzo Bianconi  * and 3D digital gyroscope system-in-package with a digital I2C/SPI serial
7290a6ce1SLorenzo Bianconi  * interface standard output.
8290a6ce1SLorenzo Bianconi  * LSM6DSx IMU MEMS series has a dynamic user-selectable full-scale
9290a6ce1SLorenzo Bianconi  * acceleration range of +-2/+-4/+-8/+-16 g and an angular rate range of
10290a6ce1SLorenzo Bianconi  * +-125/+-245/+-500/+-1000/+-2000 dps
11290a6ce1SLorenzo Bianconi  * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer
12290a6ce1SLorenzo Bianconi  * allowing dynamic batching of sensor data.
13290a6ce1SLorenzo Bianconi  *
14290a6ce1SLorenzo Bianconi  * Supported sensors:
15290a6ce1SLorenzo Bianconi  * - LSM6DS3:
16290a6ce1SLorenzo Bianconi  *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
17290a6ce1SLorenzo Bianconi  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
18290a6ce1SLorenzo Bianconi  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
19290a6ce1SLorenzo Bianconi  *   - FIFO size: 8KB
20290a6ce1SLorenzo Bianconi  *
21dbcd2088SLorenzo Bianconi  * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC/LSM6DS3TR-C:
22290a6ce1SLorenzo Bianconi  *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
23290a6ce1SLorenzo Bianconi  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
24290a6ce1SLorenzo Bianconi  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
25290a6ce1SLorenzo Bianconi  *   - FIFO size: 4KB
26290a6ce1SLorenzo Bianconi  *
2743901008SLorenzo Bianconi  * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR
28801a6e0aSLorenzo Bianconi  *   - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
29801a6e0aSLorenzo Bianconi  *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
30801a6e0aSLorenzo Bianconi  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
31801a6e0aSLorenzo Bianconi  *   - FIFO size: 3KB
32801a6e0aSLorenzo Bianconi  *
33290a6ce1SLorenzo Bianconi  * Copyright 2016 STMicroelectronics Inc.
34290a6ce1SLorenzo Bianconi  *
35290a6ce1SLorenzo Bianconi  * Lorenzo Bianconi <lorenzo.bianconi@st.com>
36290a6ce1SLorenzo Bianconi  * Denis Ciocca <denis.ciocca@st.com>
37290a6ce1SLorenzo Bianconi  */
38290a6ce1SLorenzo Bianconi 
39290a6ce1SLorenzo Bianconi #include <linux/kernel.h>
40290a6ce1SLorenzo Bianconi #include <linux/module.h>
41290a6ce1SLorenzo Bianconi #include <linux/delay.h>
42290a6ce1SLorenzo Bianconi #include <linux/iio/iio.h>
43290a6ce1SLorenzo Bianconi #include <linux/iio/sysfs.h>
44d3f77058SLorenzo Bianconi #include <linux/pm.h>
4551a8b707SLorenzo Bianconi #include <linux/regmap.h>
4651a8b707SLorenzo Bianconi #include <linux/bitfield.h>
47290a6ce1SLorenzo Bianconi 
48dba32904SLorenzo Bianconi #include <linux/platform_data/st_sensors_pdata.h>
49dba32904SLorenzo Bianconi 
50290a6ce1SLorenzo Bianconi #include "st_lsm6dsx.h"
51290a6ce1SLorenzo Bianconi 
52290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT1_ADDR		0x0d
53dba32904SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ADDR		0x0e
54290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK	BIT(3)
55290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_WHOAMI_ADDR		0x0f
56290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_ADDR		0x12
57290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_MASK		BIT(0)
5819435425SLorenzo Bianconi #define ST_LSM6DSX_REG_BOOT_MASK		BIT(7)
59290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_ADDR			0x12
60290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_MASK			BIT(6)
61290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR	0x13
62290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_MASK	BIT(5)
63290a6ce1SLorenzo Bianconi 
64290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR		0x28
65290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR		0x2a
66290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR		0x2c
67290a6ce1SLorenzo Bianconi 
68290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR	0x22
69290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR	0x24
70290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR	0x26
71290a6ce1SLorenzo Bianconi 
72290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
73290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_ACC] = {
74290a6ce1SLorenzo Bianconi 		.reg = {
75b9fedb0aSLorenzo Bianconi 			.addr = 0x10,
76b9fedb0aSLorenzo Bianconi 			.mask = GENMASK(7, 4),
77290a6ce1SLorenzo Bianconi 		},
78290a6ce1SLorenzo Bianconi 		.odr_avl[0] = {  13, 0x01 },
79290a6ce1SLorenzo Bianconi 		.odr_avl[1] = {  26, 0x02 },
80290a6ce1SLorenzo Bianconi 		.odr_avl[2] = {  52, 0x03 },
81290a6ce1SLorenzo Bianconi 		.odr_avl[3] = { 104, 0x04 },
82290a6ce1SLorenzo Bianconi 		.odr_avl[4] = { 208, 0x05 },
83290a6ce1SLorenzo Bianconi 		.odr_avl[5] = { 416, 0x06 },
84290a6ce1SLorenzo Bianconi 	},
85290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_GYRO] = {
86290a6ce1SLorenzo Bianconi 		.reg = {
87b9fedb0aSLorenzo Bianconi 			.addr = 0x11,
88b9fedb0aSLorenzo Bianconi 			.mask = GENMASK(7, 4),
89290a6ce1SLorenzo Bianconi 		},
90290a6ce1SLorenzo Bianconi 		.odr_avl[0] = {  13, 0x01 },
91290a6ce1SLorenzo Bianconi 		.odr_avl[1] = {  26, 0x02 },
92290a6ce1SLorenzo Bianconi 		.odr_avl[2] = {  52, 0x03 },
93290a6ce1SLorenzo Bianconi 		.odr_avl[3] = { 104, 0x04 },
94290a6ce1SLorenzo Bianconi 		.odr_avl[4] = { 208, 0x05 },
95290a6ce1SLorenzo Bianconi 		.odr_avl[5] = { 416, 0x06 },
96290a6ce1SLorenzo Bianconi 	}
97290a6ce1SLorenzo Bianconi };
98290a6ce1SLorenzo Bianconi 
99290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
100290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_ACC] = {
101290a6ce1SLorenzo Bianconi 		.reg = {
102b9fedb0aSLorenzo Bianconi 			.addr = 0x10,
103b9fedb0aSLorenzo Bianconi 			.mask = GENMASK(3, 2),
104290a6ce1SLorenzo Bianconi 		},
105b9fedb0aSLorenzo Bianconi 		.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
106b9fedb0aSLorenzo Bianconi 		.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
107b9fedb0aSLorenzo Bianconi 		.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
108b9fedb0aSLorenzo Bianconi 		.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
109290a6ce1SLorenzo Bianconi 	},
110290a6ce1SLorenzo Bianconi 	[ST_LSM6DSX_ID_GYRO] = {
111290a6ce1SLorenzo Bianconi 		.reg = {
112b9fedb0aSLorenzo Bianconi 			.addr = 0x11,
113b9fedb0aSLorenzo Bianconi 			.mask = GENMASK(3, 2),
114290a6ce1SLorenzo Bianconi 		},
115b9fedb0aSLorenzo Bianconi 		.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
116b9fedb0aSLorenzo Bianconi 		.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
117b9fedb0aSLorenzo Bianconi 		.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
118b9fedb0aSLorenzo Bianconi 		.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
119290a6ce1SLorenzo Bianconi 	}
120290a6ce1SLorenzo Bianconi };
121290a6ce1SLorenzo Bianconi 
122290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
123290a6ce1SLorenzo Bianconi 	{
124d068e4a0SLorenzo Bianconi 		.wai = 0x69,
1258f2a88a2SLorenzo Bianconi 		.max_fifo_size = 1365,
126d068e4a0SLorenzo Bianconi 		.id = {
12781956a93SLorenzo Bianconi 			{
12881956a93SLorenzo Bianconi 				.hw_id = ST_LSM6DS3_ID,
12981956a93SLorenzo Bianconi 				.name = ST_LSM6DS3_DEV_NAME,
13081956a93SLorenzo Bianconi 			},
131d068e4a0SLorenzo Bianconi 		},
1327ca3ac9eSLorenzo Bianconi 		.decimator = {
1337ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
1347ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
1357ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(2, 0),
1367ca3ac9eSLorenzo Bianconi 			},
1377ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
1387ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
1397ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(5, 3),
1407ca3ac9eSLorenzo Bianconi 			},
1417ca3ac9eSLorenzo Bianconi 		},
14292617c15SLorenzo Bianconi 		.fifo_ops = {
14350ff457dSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_fifo,
14492617c15SLorenzo Bianconi 			.fifo_th = {
14592617c15SLorenzo Bianconi 				.addr = 0x06,
14692617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
14792617c15SLorenzo Bianconi 			},
14892617c15SLorenzo Bianconi 			.fifo_diff = {
14992617c15SLorenzo Bianconi 				.addr = 0x3a,
15092617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
15192617c15SLorenzo Bianconi 			},
15292617c15SLorenzo Bianconi 			.th_wl = 3, /* 1LSB = 2B */
15392617c15SLorenzo Bianconi 		},
15421345107SLorenzo Bianconi 		.ts_settings = {
15521345107SLorenzo Bianconi 			.timer_en = {
15621345107SLorenzo Bianconi 				.addr = 0x58,
15721345107SLorenzo Bianconi 				.mask = BIT(7),
15821345107SLorenzo Bianconi 			},
15921345107SLorenzo Bianconi 			.hr_timer = {
16021345107SLorenzo Bianconi 				.addr = 0x5c,
16121345107SLorenzo Bianconi 				.mask = BIT(4),
16221345107SLorenzo Bianconi 			},
16321345107SLorenzo Bianconi 			.fifo_en = {
16421345107SLorenzo Bianconi 				.addr = 0x07,
16521345107SLorenzo Bianconi 				.mask = BIT(7),
16621345107SLorenzo Bianconi 			},
16721345107SLorenzo Bianconi 			.decimator = {
16821345107SLorenzo Bianconi 				.addr = 0x09,
16921345107SLorenzo Bianconi 				.mask = GENMASK(5, 3),
17021345107SLorenzo Bianconi 			},
17121345107SLorenzo Bianconi 		},
172290a6ce1SLorenzo Bianconi 	},
173290a6ce1SLorenzo Bianconi 	{
174df47710aSLorenzo Bianconi 		.wai = 0x69,
1758f2a88a2SLorenzo Bianconi 		.max_fifo_size = 682,
176df47710aSLorenzo Bianconi 		.id = {
17781956a93SLorenzo Bianconi 			{
17881956a93SLorenzo Bianconi 				.hw_id = ST_LSM6DS3H_ID,
17981956a93SLorenzo Bianconi 				.name = ST_LSM6DS3H_DEV_NAME,
18081956a93SLorenzo Bianconi 			},
181df47710aSLorenzo Bianconi 		},
1827ca3ac9eSLorenzo Bianconi 		.decimator = {
1837ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
1847ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
1857ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(2, 0),
1867ca3ac9eSLorenzo Bianconi 			},
1877ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
1887ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
1897ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(5, 3),
1907ca3ac9eSLorenzo Bianconi 			},
1917ca3ac9eSLorenzo Bianconi 		},
19292617c15SLorenzo Bianconi 		.fifo_ops = {
19350ff457dSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_fifo,
19492617c15SLorenzo Bianconi 			.fifo_th = {
19592617c15SLorenzo Bianconi 				.addr = 0x06,
19692617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
19792617c15SLorenzo Bianconi 			},
19892617c15SLorenzo Bianconi 			.fifo_diff = {
19992617c15SLorenzo Bianconi 				.addr = 0x3a,
20092617c15SLorenzo Bianconi 				.mask = GENMASK(11, 0),
20192617c15SLorenzo Bianconi 			},
20292617c15SLorenzo Bianconi 			.th_wl = 3, /* 1LSB = 2B */
20392617c15SLorenzo Bianconi 		},
20421345107SLorenzo Bianconi 		.ts_settings = {
20521345107SLorenzo Bianconi 			.timer_en = {
20621345107SLorenzo Bianconi 				.addr = 0x58,
20721345107SLorenzo Bianconi 				.mask = BIT(7),
20821345107SLorenzo Bianconi 			},
20921345107SLorenzo Bianconi 			.hr_timer = {
21021345107SLorenzo Bianconi 				.addr = 0x5c,
21121345107SLorenzo Bianconi 				.mask = BIT(4),
21221345107SLorenzo Bianconi 			},
21321345107SLorenzo Bianconi 			.fifo_en = {
21421345107SLorenzo Bianconi 				.addr = 0x07,
21521345107SLorenzo Bianconi 				.mask = BIT(7),
21621345107SLorenzo Bianconi 			},
21721345107SLorenzo Bianconi 			.decimator = {
21821345107SLorenzo Bianconi 				.addr = 0x09,
21921345107SLorenzo Bianconi 				.mask = GENMASK(5, 3),
22021345107SLorenzo Bianconi 			},
22121345107SLorenzo Bianconi 		},
222df47710aSLorenzo Bianconi 	},
223df47710aSLorenzo Bianconi 	{
224d068e4a0SLorenzo Bianconi 		.wai = 0x6a,
2258f2a88a2SLorenzo Bianconi 		.max_fifo_size = 682,
226d068e4a0SLorenzo Bianconi 		.id = {
22781956a93SLorenzo Bianconi 			{
22881956a93SLorenzo Bianconi 				.hw_id = ST_LSM6DSL_ID,
22981956a93SLorenzo Bianconi 				.name = ST_LSM6DSL_DEV_NAME,
23081956a93SLorenzo Bianconi 			}, {
23181956a93SLorenzo Bianconi 				.hw_id = ST_LSM6DSM_ID,
23281956a93SLorenzo Bianconi 				.name = ST_LSM6DSM_DEV_NAME,
23381956a93SLorenzo Bianconi 			}, {
23481956a93SLorenzo Bianconi 				.hw_id = ST_ISM330DLC_ID,
23581956a93SLorenzo Bianconi 				.name = ST_ISM330DLC_DEV_NAME,
236dbcd2088SLorenzo Bianconi 			}, {
237dbcd2088SLorenzo Bianconi 				.hw_id = ST_LSM6DS3TRC_ID,
238dbcd2088SLorenzo Bianconi 				.name = ST_LSM6DS3TRC_DEV_NAME,
23981956a93SLorenzo Bianconi 			},
240d068e4a0SLorenzo Bianconi 		},
2417ca3ac9eSLorenzo Bianconi 		.decimator = {
2427ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
2437ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
2447ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(2, 0),
2457ca3ac9eSLorenzo Bianconi 			},
2467ca3ac9eSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
2477ca3ac9eSLorenzo Bianconi 				.addr = 0x08,
2487ca3ac9eSLorenzo Bianconi 				.mask = GENMASK(5, 3),
2497ca3ac9eSLorenzo Bianconi 			},
2507ca3ac9eSLorenzo Bianconi 		},
25192617c15SLorenzo Bianconi 		.fifo_ops = {
25250ff457dSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_fifo,
25392617c15SLorenzo Bianconi 			.fifo_th = {
25492617c15SLorenzo Bianconi 				.addr = 0x06,
255be75eb86SLorenzo Bianconi 				.mask = GENMASK(10, 0),
25692617c15SLorenzo Bianconi 			},
25792617c15SLorenzo Bianconi 			.fifo_diff = {
25892617c15SLorenzo Bianconi 				.addr = 0x3a,
259be75eb86SLorenzo Bianconi 				.mask = GENMASK(10, 0),
26092617c15SLorenzo Bianconi 			},
26192617c15SLorenzo Bianconi 			.th_wl = 3, /* 1LSB = 2B */
26292617c15SLorenzo Bianconi 		},
26321345107SLorenzo Bianconi 		.ts_settings = {
26421345107SLorenzo Bianconi 			.timer_en = {
26521345107SLorenzo Bianconi 				.addr = 0x19,
26621345107SLorenzo Bianconi 				.mask = BIT(5),
26721345107SLorenzo Bianconi 			},
26821345107SLorenzo Bianconi 			.hr_timer = {
26921345107SLorenzo Bianconi 				.addr = 0x5c,
27021345107SLorenzo Bianconi 				.mask = BIT(4),
27121345107SLorenzo Bianconi 			},
27221345107SLorenzo Bianconi 			.fifo_en = {
27321345107SLorenzo Bianconi 				.addr = 0x07,
27421345107SLorenzo Bianconi 				.mask = BIT(7),
27521345107SLorenzo Bianconi 			},
27621345107SLorenzo Bianconi 			.decimator = {
27721345107SLorenzo Bianconi 				.addr = 0x09,
27821345107SLorenzo Bianconi 				.mask = GENMASK(5, 3),
27921345107SLorenzo Bianconi 			},
28021345107SLorenzo Bianconi 		},
281290a6ce1SLorenzo Bianconi 	},
282801a6e0aSLorenzo Bianconi 	{
283801a6e0aSLorenzo Bianconi 		.wai = 0x6c,
284801a6e0aSLorenzo Bianconi 		.max_fifo_size = 512,
285801a6e0aSLorenzo Bianconi 		.id = {
28681956a93SLorenzo Bianconi 			{
28781956a93SLorenzo Bianconi 				.hw_id = ST_LSM6DSO_ID,
28881956a93SLorenzo Bianconi 				.name = ST_LSM6DSO_DEV_NAME,
28981956a93SLorenzo Bianconi 			}, {
29081956a93SLorenzo Bianconi 				.hw_id = ST_LSM6DSOX_ID,
29181956a93SLorenzo Bianconi 				.name = ST_LSM6DSOX_DEV_NAME,
29281956a93SLorenzo Bianconi 			},
293801a6e0aSLorenzo Bianconi 		},
294801a6e0aSLorenzo Bianconi 		.batch = {
295801a6e0aSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
296801a6e0aSLorenzo Bianconi 				.addr = 0x09,
297801a6e0aSLorenzo Bianconi 				.mask = GENMASK(3, 0),
298801a6e0aSLorenzo Bianconi 			},
299801a6e0aSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
300801a6e0aSLorenzo Bianconi 				.addr = 0x09,
301801a6e0aSLorenzo Bianconi 				.mask = GENMASK(7, 4),
302801a6e0aSLorenzo Bianconi 			},
303801a6e0aSLorenzo Bianconi 		},
304801a6e0aSLorenzo Bianconi 		.fifo_ops = {
305801a6e0aSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_tagged_fifo,
306801a6e0aSLorenzo Bianconi 			.fifo_th = {
307801a6e0aSLorenzo Bianconi 				.addr = 0x07,
308801a6e0aSLorenzo Bianconi 				.mask = GENMASK(8, 0),
309801a6e0aSLorenzo Bianconi 			},
310801a6e0aSLorenzo Bianconi 			.fifo_diff = {
311801a6e0aSLorenzo Bianconi 				.addr = 0x3a,
312801a6e0aSLorenzo Bianconi 				.mask = GENMASK(8, 0),
313801a6e0aSLorenzo Bianconi 			},
314801a6e0aSLorenzo Bianconi 			.th_wl = 1,
315801a6e0aSLorenzo Bianconi 		},
316801a6e0aSLorenzo Bianconi 		.ts_settings = {
317801a6e0aSLorenzo Bianconi 			.timer_en = {
318801a6e0aSLorenzo Bianconi 				.addr = 0x19,
319801a6e0aSLorenzo Bianconi 				.mask = BIT(5),
320801a6e0aSLorenzo Bianconi 			},
321801a6e0aSLorenzo Bianconi 			.decimator = {
322801a6e0aSLorenzo Bianconi 				.addr = 0x0a,
323801a6e0aSLorenzo Bianconi 				.mask = GENMASK(7, 6),
324801a6e0aSLorenzo Bianconi 			},
325801a6e0aSLorenzo Bianconi 		},
326c91c1c84SLorenzo Bianconi 		.shub_settings = {
327c91c1c84SLorenzo Bianconi 			.page_mux = {
328c91c1c84SLorenzo Bianconi 				.addr = 0x01,
329c91c1c84SLorenzo Bianconi 				.mask = BIT(6),
330c91c1c84SLorenzo Bianconi 			},
331c91c1c84SLorenzo Bianconi 			.master_en = {
332c91c1c84SLorenzo Bianconi 				.addr = 0x14,
333c91c1c84SLorenzo Bianconi 				.mask = BIT(2),
334c91c1c84SLorenzo Bianconi 			},
335c91c1c84SLorenzo Bianconi 			.pullup_en = {
336c91c1c84SLorenzo Bianconi 				.addr = 0x14,
337c91c1c84SLorenzo Bianconi 				.mask = BIT(3),
338c91c1c84SLorenzo Bianconi 			},
339c91c1c84SLorenzo Bianconi 			.aux_sens = {
340c91c1c84SLorenzo Bianconi 				.addr = 0x14,
341c91c1c84SLorenzo Bianconi 				.mask = GENMASK(1, 0),
342c91c1c84SLorenzo Bianconi 			},
3436d0205fdSLorenzo Bianconi 			.wr_once = {
3446d0205fdSLorenzo Bianconi 				.addr = 0x14,
3456d0205fdSLorenzo Bianconi 				.mask = BIT(6),
3466d0205fdSLorenzo Bianconi 			},
347c91c1c84SLorenzo Bianconi 			.shub_out = 0x02,
348c91c1c84SLorenzo Bianconi 			.slv0_addr = 0x15,
349c91c1c84SLorenzo Bianconi 			.dw_slv0_addr = 0x21,
3506d0205fdSLorenzo Bianconi 			.batch_en = BIT(3),
351c91c1c84SLorenzo Bianconi 		}
352801a6e0aSLorenzo Bianconi 	},
3533054c4ffSLorenzo Bianconi 	{
3543054c4ffSLorenzo Bianconi 		.wai = 0x6b,
3553054c4ffSLorenzo Bianconi 		.max_fifo_size = 512,
3563054c4ffSLorenzo Bianconi 		.id = {
35781956a93SLorenzo Bianconi 			{
35881956a93SLorenzo Bianconi 				.hw_id = ST_ASM330LHH_ID,
35981956a93SLorenzo Bianconi 				.name = ST_ASM330LHH_DEV_NAME,
36081956a93SLorenzo Bianconi 			},
3613054c4ffSLorenzo Bianconi 		},
3623054c4ffSLorenzo Bianconi 		.batch = {
3633054c4ffSLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
3643054c4ffSLorenzo Bianconi 				.addr = 0x09,
3653054c4ffSLorenzo Bianconi 				.mask = GENMASK(3, 0),
3663054c4ffSLorenzo Bianconi 			},
3673054c4ffSLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
3683054c4ffSLorenzo Bianconi 				.addr = 0x09,
3693054c4ffSLorenzo Bianconi 				.mask = GENMASK(7, 4),
3703054c4ffSLorenzo Bianconi 			},
3713054c4ffSLorenzo Bianconi 		},
3723054c4ffSLorenzo Bianconi 		.fifo_ops = {
3733054c4ffSLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_tagged_fifo,
3743054c4ffSLorenzo Bianconi 			.fifo_th = {
3753054c4ffSLorenzo Bianconi 				.addr = 0x07,
3763054c4ffSLorenzo Bianconi 				.mask = GENMASK(8, 0),
3773054c4ffSLorenzo Bianconi 			},
3783054c4ffSLorenzo Bianconi 			.fifo_diff = {
3793054c4ffSLorenzo Bianconi 				.addr = 0x3a,
3803054c4ffSLorenzo Bianconi 				.mask = GENMASK(8, 0),
3813054c4ffSLorenzo Bianconi 			},
3823054c4ffSLorenzo Bianconi 			.th_wl = 1,
3833054c4ffSLorenzo Bianconi 		},
3843054c4ffSLorenzo Bianconi 		.ts_settings = {
3853054c4ffSLorenzo Bianconi 			.timer_en = {
3863054c4ffSLorenzo Bianconi 				.addr = 0x19,
3873054c4ffSLorenzo Bianconi 				.mask = BIT(5),
3883054c4ffSLorenzo Bianconi 			},
3893054c4ffSLorenzo Bianconi 			.decimator = {
3903054c4ffSLorenzo Bianconi 				.addr = 0x0a,
3913054c4ffSLorenzo Bianconi 				.mask = GENMASK(7, 6),
3923054c4ffSLorenzo Bianconi 			},
3933054c4ffSLorenzo Bianconi 		},
3943054c4ffSLorenzo Bianconi 	},
39543901008SLorenzo Bianconi 	{
39643901008SLorenzo Bianconi 		.wai = 0x6b,
39743901008SLorenzo Bianconi 		.max_fifo_size = 512,
39843901008SLorenzo Bianconi 		.id = {
39981956a93SLorenzo Bianconi 			{
40081956a93SLorenzo Bianconi 				.hw_id = ST_LSM6DSR_ID,
40181956a93SLorenzo Bianconi 				.name = ST_LSM6DSR_DEV_NAME,
40281956a93SLorenzo Bianconi 			},
40343901008SLorenzo Bianconi 		},
40443901008SLorenzo Bianconi 		.batch = {
40543901008SLorenzo Bianconi 			[ST_LSM6DSX_ID_ACC] = {
40643901008SLorenzo Bianconi 				.addr = 0x09,
40743901008SLorenzo Bianconi 				.mask = GENMASK(3, 0),
40843901008SLorenzo Bianconi 			},
40943901008SLorenzo Bianconi 			[ST_LSM6DSX_ID_GYRO] = {
41043901008SLorenzo Bianconi 				.addr = 0x09,
41143901008SLorenzo Bianconi 				.mask = GENMASK(7, 4),
41243901008SLorenzo Bianconi 			},
41343901008SLorenzo Bianconi 		},
41443901008SLorenzo Bianconi 		.fifo_ops = {
41543901008SLorenzo Bianconi 			.read_fifo = st_lsm6dsx_read_tagged_fifo,
41643901008SLorenzo Bianconi 			.fifo_th = {
41743901008SLorenzo Bianconi 				.addr = 0x07,
41843901008SLorenzo Bianconi 				.mask = GENMASK(8, 0),
41943901008SLorenzo Bianconi 			},
42043901008SLorenzo Bianconi 			.fifo_diff = {
42143901008SLorenzo Bianconi 				.addr = 0x3a,
42243901008SLorenzo Bianconi 				.mask = GENMASK(8, 0),
42343901008SLorenzo Bianconi 			},
42443901008SLorenzo Bianconi 			.th_wl = 1,
42543901008SLorenzo Bianconi 		},
42643901008SLorenzo Bianconi 		.ts_settings = {
42743901008SLorenzo Bianconi 			.timer_en = {
42843901008SLorenzo Bianconi 				.addr = 0x19,
42943901008SLorenzo Bianconi 				.mask = BIT(5),
43043901008SLorenzo Bianconi 			},
43143901008SLorenzo Bianconi 			.decimator = {
43243901008SLorenzo Bianconi 				.addr = 0x0a,
43343901008SLorenzo Bianconi 				.mask = GENMASK(7, 6),
43443901008SLorenzo Bianconi 			},
43543901008SLorenzo Bianconi 		},
43643901008SLorenzo Bianconi 		.shub_settings = {
43743901008SLorenzo Bianconi 			.page_mux = {
43843901008SLorenzo Bianconi 				.addr = 0x01,
43943901008SLorenzo Bianconi 				.mask = BIT(6),
44043901008SLorenzo Bianconi 			},
44143901008SLorenzo Bianconi 			.master_en = {
44243901008SLorenzo Bianconi 				.addr = 0x14,
44343901008SLorenzo Bianconi 				.mask = BIT(2),
44443901008SLorenzo Bianconi 			},
44543901008SLorenzo Bianconi 			.pullup_en = {
44643901008SLorenzo Bianconi 				.addr = 0x14,
44743901008SLorenzo Bianconi 				.mask = BIT(3),
44843901008SLorenzo Bianconi 			},
44943901008SLorenzo Bianconi 			.aux_sens = {
45043901008SLorenzo Bianconi 				.addr = 0x14,
45143901008SLorenzo Bianconi 				.mask = GENMASK(1, 0),
45243901008SLorenzo Bianconi 			},
45343901008SLorenzo Bianconi 			.wr_once = {
45443901008SLorenzo Bianconi 				.addr = 0x14,
45543901008SLorenzo Bianconi 				.mask = BIT(6),
45643901008SLorenzo Bianconi 			},
45743901008SLorenzo Bianconi 			.shub_out = 0x02,
45843901008SLorenzo Bianconi 			.slv0_addr = 0x15,
45943901008SLorenzo Bianconi 			.dw_slv0_addr = 0x21,
46043901008SLorenzo Bianconi 			.batch_en = BIT(3),
46143901008SLorenzo Bianconi 		}
46243901008SLorenzo Bianconi 	},
463290a6ce1SLorenzo Bianconi };
464290a6ce1SLorenzo Bianconi 
465290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
466290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
467290a6ce1SLorenzo Bianconi 			   IIO_MOD_X, 0),
468290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
469290a6ce1SLorenzo Bianconi 			   IIO_MOD_Y, 1),
470290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
471290a6ce1SLorenzo Bianconi 			   IIO_MOD_Z, 2),
472290a6ce1SLorenzo Bianconi 	IIO_CHAN_SOFT_TIMESTAMP(3),
473290a6ce1SLorenzo Bianconi };
474290a6ce1SLorenzo Bianconi 
475290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
476290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR,
477290a6ce1SLorenzo Bianconi 			   IIO_MOD_X, 0),
478290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR,
479290a6ce1SLorenzo Bianconi 			   IIO_MOD_Y, 1),
480290a6ce1SLorenzo Bianconi 	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR,
481290a6ce1SLorenzo Bianconi 			   IIO_MOD_Z, 2),
482290a6ce1SLorenzo Bianconi 	IIO_CHAN_SOFT_TIMESTAMP(3),
483290a6ce1SLorenzo Bianconi };
484290a6ce1SLorenzo Bianconi 
485c91c1c84SLorenzo Bianconi int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
486c91c1c84SLorenzo Bianconi {
487c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
488c91c1c84SLorenzo Bianconi 	unsigned int data;
489c91c1c84SLorenzo Bianconi 	int err;
490c91c1c84SLorenzo Bianconi 
491c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
492c91c1c84SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->page_mux.mask);
493c91c1c84SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, hub_settings->page_mux.addr,
494c91c1c84SLorenzo Bianconi 				 hub_settings->page_mux.mask, data);
495c91c1c84SLorenzo Bianconi 	usleep_range(100, 150);
496c91c1c84SLorenzo Bianconi 
497c91c1c84SLorenzo Bianconi 	return err;
498c91c1c84SLorenzo Bianconi }
499c91c1c84SLorenzo Bianconi 
50081956a93SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
50181956a93SLorenzo Bianconi 				   const char **name)
502290a6ce1SLorenzo Bianconi {
50351a8b707SLorenzo Bianconi 	int err, i, j, data;
504290a6ce1SLorenzo Bianconi 
505290a6ce1SLorenzo Bianconi 	for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
506d068e4a0SLorenzo Bianconi 		for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) {
50781956a93SLorenzo Bianconi 			if (id == st_lsm6dsx_sensor_settings[i].id[j].hw_id)
508d068e4a0SLorenzo Bianconi 				break;
509d068e4a0SLorenzo Bianconi 		}
510d068e4a0SLorenzo Bianconi 		if (j < ST_LSM6DSX_MAX_ID)
511290a6ce1SLorenzo Bianconi 			break;
512290a6ce1SLorenzo Bianconi 	}
513290a6ce1SLorenzo Bianconi 
514290a6ce1SLorenzo Bianconi 	if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) {
515290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "unsupported hw id [%02x]\n", id);
516290a6ce1SLorenzo Bianconi 		return -ENODEV;
517290a6ce1SLorenzo Bianconi 	}
518290a6ce1SLorenzo Bianconi 
51951a8b707SLorenzo Bianconi 	err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data);
520290a6ce1SLorenzo Bianconi 	if (err < 0) {
521290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "failed to read whoami register\n");
522290a6ce1SLorenzo Bianconi 		return err;
523290a6ce1SLorenzo Bianconi 	}
524290a6ce1SLorenzo Bianconi 
525290a6ce1SLorenzo Bianconi 	if (data != st_lsm6dsx_sensor_settings[i].wai) {
526290a6ce1SLorenzo Bianconi 		dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
527290a6ce1SLorenzo Bianconi 		return -ENODEV;
528290a6ce1SLorenzo Bianconi 	}
529290a6ce1SLorenzo Bianconi 
53081956a93SLorenzo Bianconi 	*name = st_lsm6dsx_sensor_settings[i].id[j].name;
531290a6ce1SLorenzo Bianconi 	hw->settings = &st_lsm6dsx_sensor_settings[i];
532290a6ce1SLorenzo Bianconi 
533290a6ce1SLorenzo Bianconi 	return 0;
534290a6ce1SLorenzo Bianconi }
535290a6ce1SLorenzo Bianconi 
536290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
537290a6ce1SLorenzo Bianconi 				     u32 gain)
538290a6ce1SLorenzo Bianconi {
53951a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
54051a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
541739aff87SLorenzo Bianconi 	unsigned int data;
542290a6ce1SLorenzo Bianconi 	int i, err;
543290a6ce1SLorenzo Bianconi 	u8 val;
544290a6ce1SLorenzo Bianconi 
545290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
54651a8b707SLorenzo Bianconi 		if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain)
547290a6ce1SLorenzo Bianconi 			break;
548290a6ce1SLorenzo Bianconi 
549290a6ce1SLorenzo Bianconi 	if (i == ST_LSM6DSX_FS_LIST_SIZE)
550290a6ce1SLorenzo Bianconi 		return -EINVAL;
551290a6ce1SLorenzo Bianconi 
55251a8b707SLorenzo Bianconi 	val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val;
55351a8b707SLorenzo Bianconi 	reg = &st_lsm6dsx_fs_table[sensor->id].reg;
554739aff87SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
555739aff87SLorenzo Bianconi 	err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
556290a6ce1SLorenzo Bianconi 	if (err < 0)
557290a6ce1SLorenzo Bianconi 		return err;
558290a6ce1SLorenzo Bianconi 
559290a6ce1SLorenzo Bianconi 	sensor->gain = gain;
560290a6ce1SLorenzo Bianconi 
561290a6ce1SLorenzo Bianconi 	return 0;
562290a6ce1SLorenzo Bianconi }
563290a6ce1SLorenzo Bianconi 
56454a6d0c6SLorenzo Bianconi int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
565290a6ce1SLorenzo Bianconi {
5662ccc1503SLorenzo Bianconi 	int i;
567290a6ce1SLorenzo Bianconi 
568290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
5696ffb55e5SLorenzo Bianconi 		/*
5706ffb55e5SLorenzo Bianconi 		 * ext devices can run at different odr respect to
5716ffb55e5SLorenzo Bianconi 		 * accel sensor
5726ffb55e5SLorenzo Bianconi 		 */
5736ffb55e5SLorenzo Bianconi 		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
574290a6ce1SLorenzo Bianconi 			break;
575290a6ce1SLorenzo Bianconi 
576290a6ce1SLorenzo Bianconi 	if (i == ST_LSM6DSX_ODR_LIST_SIZE)
577290a6ce1SLorenzo Bianconi 		return -EINVAL;
578290a6ce1SLorenzo Bianconi 
5792ccc1503SLorenzo Bianconi 	*val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val;
580290a6ce1SLorenzo Bianconi 
581290a6ce1SLorenzo Bianconi 	return 0;
582290a6ce1SLorenzo Bianconi }
583290a6ce1SLorenzo Bianconi 
5846ffb55e5SLorenzo Bianconi static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr,
5856ffb55e5SLorenzo Bianconi 					   enum st_lsm6dsx_sensor_id id)
5862ccc1503SLorenzo Bianconi {
5876ffb55e5SLorenzo Bianconi 	struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]);
5886ffb55e5SLorenzo Bianconi 
5896ffb55e5SLorenzo Bianconi 	if (odr > 0) {
5906ffb55e5SLorenzo Bianconi 		if (hw->enable_mask & BIT(id))
5916ffb55e5SLorenzo Bianconi 			return max_t(u16, ref->odr, odr);
5926ffb55e5SLorenzo Bianconi 		else
5936ffb55e5SLorenzo Bianconi 			return odr;
5946ffb55e5SLorenzo Bianconi 	} else {
5956ffb55e5SLorenzo Bianconi 		return (hw->enable_mask & BIT(id)) ? ref->odr : 0;
5966ffb55e5SLorenzo Bianconi 	}
5976ffb55e5SLorenzo Bianconi }
5986ffb55e5SLorenzo Bianconi 
5996ffb55e5SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
6006ffb55e5SLorenzo Bianconi {
6016ffb55e5SLorenzo Bianconi 	struct st_lsm6dsx_sensor *ref_sensor = sensor;
60251a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
60351a8b707SLorenzo Bianconi 	const struct st_lsm6dsx_reg *reg;
604739aff87SLorenzo Bianconi 	unsigned int data;
6056ffb55e5SLorenzo Bianconi 	u8 val = 0;
6062ccc1503SLorenzo Bianconi 	int err;
6072ccc1503SLorenzo Bianconi 
6086ffb55e5SLorenzo Bianconi 	switch (sensor->id) {
6096ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT0:
6106ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT1:
6116ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_EXT2:
6126ffb55e5SLorenzo Bianconi 	case ST_LSM6DSX_ID_ACC: {
6136ffb55e5SLorenzo Bianconi 		u16 odr;
6146ffb55e5SLorenzo Bianconi 		int i;
6156ffb55e5SLorenzo Bianconi 
6166ffb55e5SLorenzo Bianconi 		/*
6176ffb55e5SLorenzo Bianconi 		 * i2c embedded controller relies on the accelerometer sensor as
6186ffb55e5SLorenzo Bianconi 		 * bus read/write trigger so we need to enable accel device
6196ffb55e5SLorenzo Bianconi 		 * at odr = max(accel_odr, ext_odr) in order to properly
6206ffb55e5SLorenzo Bianconi 		 * communicate with i2c slave devices
6216ffb55e5SLorenzo Bianconi 		 */
6226ffb55e5SLorenzo Bianconi 		ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
6236ffb55e5SLorenzo Bianconi 		for (i = ST_LSM6DSX_ID_ACC; i < ST_LSM6DSX_ID_MAX; i++) {
6246ffb55e5SLorenzo Bianconi 			if (!hw->iio_devs[i] || i == sensor->id)
6256ffb55e5SLorenzo Bianconi 				continue;
6266ffb55e5SLorenzo Bianconi 
6276ffb55e5SLorenzo Bianconi 			odr = st_lsm6dsx_check_odr_dependency(hw, req_odr, i);
6286ffb55e5SLorenzo Bianconi 			if (odr != req_odr)
6296ffb55e5SLorenzo Bianconi 				/* device already configured */
6306ffb55e5SLorenzo Bianconi 				return 0;
6316ffb55e5SLorenzo Bianconi 		}
6326ffb55e5SLorenzo Bianconi 		break;
6336ffb55e5SLorenzo Bianconi 	}
6346ffb55e5SLorenzo Bianconi 	default:
6356ffb55e5SLorenzo Bianconi 		break;
6366ffb55e5SLorenzo Bianconi 	}
6376ffb55e5SLorenzo Bianconi 
6386ffb55e5SLorenzo Bianconi 	if (req_odr > 0) {
6396ffb55e5SLorenzo Bianconi 		err = st_lsm6dsx_check_odr(ref_sensor, req_odr, &val);
6402ccc1503SLorenzo Bianconi 		if (err < 0)
6412ccc1503SLorenzo Bianconi 			return err;
6426ffb55e5SLorenzo Bianconi 	}
6432ccc1503SLorenzo Bianconi 
6446ffb55e5SLorenzo Bianconi 	reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg;
645739aff87SLorenzo Bianconi 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
646739aff87SLorenzo Bianconi 	return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
6472ccc1503SLorenzo Bianconi }
6482ccc1503SLorenzo Bianconi 
64917750443SLorenzo Bianconi int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,
65017750443SLorenzo Bianconi 				 bool enable)
651290a6ce1SLorenzo Bianconi {
65251a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
65317750443SLorenzo Bianconi 	u16 odr = enable ? sensor->odr : 0;
654290a6ce1SLorenzo Bianconi 	int err;
655290a6ce1SLorenzo Bianconi 
65617750443SLorenzo Bianconi 	err = st_lsm6dsx_set_odr(sensor, odr);
657290a6ce1SLorenzo Bianconi 	if (err < 0)
658290a6ce1SLorenzo Bianconi 		return err;
659290a6ce1SLorenzo Bianconi 
66017750443SLorenzo Bianconi 	if (enable)
66117750443SLorenzo Bianconi 		hw->enable_mask |= BIT(sensor->id);
66217750443SLorenzo Bianconi 	else
66317750443SLorenzo Bianconi 		hw->enable_mask &= ~BIT(sensor->id);
664290a6ce1SLorenzo Bianconi 
665290a6ce1SLorenzo Bianconi 	return 0;
666290a6ce1SLorenzo Bianconi }
667290a6ce1SLorenzo Bianconi 
668290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
669290a6ce1SLorenzo Bianconi 				   u8 addr, int *val)
670290a6ce1SLorenzo Bianconi {
67151a8b707SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
672290a6ce1SLorenzo Bianconi 	int err, delay;
673290a6ce1SLorenzo Bianconi 	__le16 data;
674290a6ce1SLorenzo Bianconi 
67517750443SLorenzo Bianconi 	err = st_lsm6dsx_sensor_set_enable(sensor, true);
676290a6ce1SLorenzo Bianconi 	if (err < 0)
677290a6ce1SLorenzo Bianconi 		return err;
678290a6ce1SLorenzo Bianconi 
679290a6ce1SLorenzo Bianconi 	delay = 1000000 / sensor->odr;
680290a6ce1SLorenzo Bianconi 	usleep_range(delay, 2 * delay);
681290a6ce1SLorenzo Bianconi 
682739aff87SLorenzo Bianconi 	err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data));
683290a6ce1SLorenzo Bianconi 	if (err < 0)
684290a6ce1SLorenzo Bianconi 		return err;
685290a6ce1SLorenzo Bianconi 
68617750443SLorenzo Bianconi 	st_lsm6dsx_sensor_set_enable(sensor, false);
687290a6ce1SLorenzo Bianconi 
6887b9ebe42SLorenzo Bianconi 	*val = (s16)le16_to_cpu(data);
689290a6ce1SLorenzo Bianconi 
690290a6ce1SLorenzo Bianconi 	return IIO_VAL_INT;
691290a6ce1SLorenzo Bianconi }
692290a6ce1SLorenzo Bianconi 
693290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
694290a6ce1SLorenzo Bianconi 			       struct iio_chan_spec const *ch,
695290a6ce1SLorenzo Bianconi 			       int *val, int *val2, long mask)
696290a6ce1SLorenzo Bianconi {
697290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
698290a6ce1SLorenzo Bianconi 	int ret;
699290a6ce1SLorenzo Bianconi 
700290a6ce1SLorenzo Bianconi 	switch (mask) {
701290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_RAW:
702290a6ce1SLorenzo Bianconi 		ret = iio_device_claim_direct_mode(iio_dev);
703290a6ce1SLorenzo Bianconi 		if (ret)
704290a6ce1SLorenzo Bianconi 			break;
705290a6ce1SLorenzo Bianconi 
706290a6ce1SLorenzo Bianconi 		ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val);
707290a6ce1SLorenzo Bianconi 		iio_device_release_direct_mode(iio_dev);
708290a6ce1SLorenzo Bianconi 		break;
709290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SAMP_FREQ:
710290a6ce1SLorenzo Bianconi 		*val = sensor->odr;
711290a6ce1SLorenzo Bianconi 		ret = IIO_VAL_INT;
712290a6ce1SLorenzo Bianconi 		break;
713290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SCALE:
714290a6ce1SLorenzo Bianconi 		*val = 0;
715290a6ce1SLorenzo Bianconi 		*val2 = sensor->gain;
716290a6ce1SLorenzo Bianconi 		ret = IIO_VAL_INT_PLUS_MICRO;
717290a6ce1SLorenzo Bianconi 		break;
718290a6ce1SLorenzo Bianconi 	default:
719290a6ce1SLorenzo Bianconi 		ret = -EINVAL;
720290a6ce1SLorenzo Bianconi 		break;
721290a6ce1SLorenzo Bianconi 	}
722290a6ce1SLorenzo Bianconi 
723290a6ce1SLorenzo Bianconi 	return ret;
724290a6ce1SLorenzo Bianconi }
725290a6ce1SLorenzo Bianconi 
726290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
727290a6ce1SLorenzo Bianconi 				struct iio_chan_spec const *chan,
728290a6ce1SLorenzo Bianconi 				int val, int val2, long mask)
729290a6ce1SLorenzo Bianconi {
730290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
731290a6ce1SLorenzo Bianconi 	int err;
732290a6ce1SLorenzo Bianconi 
733290a6ce1SLorenzo Bianconi 	err = iio_device_claim_direct_mode(iio_dev);
734290a6ce1SLorenzo Bianconi 	if (err)
735290a6ce1SLorenzo Bianconi 		return err;
736290a6ce1SLorenzo Bianconi 
737290a6ce1SLorenzo Bianconi 	switch (mask) {
738290a6ce1SLorenzo Bianconi 	case IIO_CHAN_INFO_SCALE:
739290a6ce1SLorenzo Bianconi 		err = st_lsm6dsx_set_full_scale(sensor, val2);
740290a6ce1SLorenzo Bianconi 		break;
7412ccc1503SLorenzo Bianconi 	case IIO_CHAN_INFO_SAMP_FREQ: {
7422ccc1503SLorenzo Bianconi 		u8 data;
7432ccc1503SLorenzo Bianconi 
7442ccc1503SLorenzo Bianconi 		err = st_lsm6dsx_check_odr(sensor, val, &data);
7455e3c3e33SLorenzo Bianconi 		if (!err)
7465e3c3e33SLorenzo Bianconi 			sensor->odr = val;
747290a6ce1SLorenzo Bianconi 		break;
7482ccc1503SLorenzo Bianconi 	}
749290a6ce1SLorenzo Bianconi 	default:
750290a6ce1SLorenzo Bianconi 		err = -EINVAL;
751290a6ce1SLorenzo Bianconi 		break;
752290a6ce1SLorenzo Bianconi 	}
753290a6ce1SLorenzo Bianconi 
754290a6ce1SLorenzo Bianconi 	iio_device_release_direct_mode(iio_dev);
755290a6ce1SLorenzo Bianconi 
756290a6ce1SLorenzo Bianconi 	return err;
757290a6ce1SLorenzo Bianconi }
758290a6ce1SLorenzo Bianconi 
759d40464f3SLorenzo Bianconi int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
760290a6ce1SLorenzo Bianconi {
761290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
762290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = sensor->hw;
7638f2a88a2SLorenzo Bianconi 	int err;
764290a6ce1SLorenzo Bianconi 
7658f2a88a2SLorenzo Bianconi 	if (val < 1 || val > hw->settings->max_fifo_size)
766290a6ce1SLorenzo Bianconi 		return -EINVAL;
767290a6ce1SLorenzo Bianconi 
768335eaedcSLorenzo Bianconi 	mutex_lock(&hw->conf_lock);
769335eaedcSLorenzo Bianconi 
770290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_update_watermark(sensor, val);
771335eaedcSLorenzo Bianconi 
772335eaedcSLorenzo Bianconi 	mutex_unlock(&hw->conf_lock);
773335eaedcSLorenzo Bianconi 
774290a6ce1SLorenzo Bianconi 	if (err < 0)
775290a6ce1SLorenzo Bianconi 		return err;
776290a6ce1SLorenzo Bianconi 
777290a6ce1SLorenzo Bianconi 	sensor->watermark = val;
778290a6ce1SLorenzo Bianconi 
779290a6ce1SLorenzo Bianconi 	return 0;
780290a6ce1SLorenzo Bianconi }
781290a6ce1SLorenzo Bianconi 
782290a6ce1SLorenzo Bianconi static ssize_t
783290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
784290a6ce1SLorenzo Bianconi 					  struct device_attribute *attr,
785290a6ce1SLorenzo Bianconi 					  char *buf)
786290a6ce1SLorenzo Bianconi {
787290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
788290a6ce1SLorenzo Bianconi 	enum st_lsm6dsx_sensor_id id = sensor->id;
789290a6ce1SLorenzo Bianconi 	int i, len = 0;
790290a6ce1SLorenzo Bianconi 
791290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
792290a6ce1SLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
793290a6ce1SLorenzo Bianconi 				 st_lsm6dsx_odr_table[id].odr_avl[i].hz);
794290a6ce1SLorenzo Bianconi 	buf[len - 1] = '\n';
795290a6ce1SLorenzo Bianconi 
796290a6ce1SLorenzo Bianconi 	return len;
797290a6ce1SLorenzo Bianconi }
798290a6ce1SLorenzo Bianconi 
799290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
800290a6ce1SLorenzo Bianconi 					    struct device_attribute *attr,
801290a6ce1SLorenzo Bianconi 					    char *buf)
802290a6ce1SLorenzo Bianconi {
803290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
804290a6ce1SLorenzo Bianconi 	enum st_lsm6dsx_sensor_id id = sensor->id;
805290a6ce1SLorenzo Bianconi 	int i, len = 0;
806290a6ce1SLorenzo Bianconi 
807290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
808290a6ce1SLorenzo Bianconi 		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
809290a6ce1SLorenzo Bianconi 				 st_lsm6dsx_fs_table[id].fs_avl[i].gain);
810290a6ce1SLorenzo Bianconi 	buf[len - 1] = '\n';
811290a6ce1SLorenzo Bianconi 
812290a6ce1SLorenzo Bianconi 	return len;
813290a6ce1SLorenzo Bianconi }
814290a6ce1SLorenzo Bianconi 
815290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail);
816290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
817290a6ce1SLorenzo Bianconi 		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
818290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444,
819290a6ce1SLorenzo Bianconi 		       st_lsm6dsx_sysfs_scale_avail, NULL, 0);
820290a6ce1SLorenzo Bianconi 
821290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = {
822290a6ce1SLorenzo Bianconi 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
823290a6ce1SLorenzo Bianconi 	&iio_dev_attr_in_accel_scale_available.dev_attr.attr,
824290a6ce1SLorenzo Bianconi 	NULL,
825290a6ce1SLorenzo Bianconi };
826290a6ce1SLorenzo Bianconi 
827290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = {
828290a6ce1SLorenzo Bianconi 	.attrs = st_lsm6dsx_acc_attributes,
829290a6ce1SLorenzo Bianconi };
830290a6ce1SLorenzo Bianconi 
831290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = {
832290a6ce1SLorenzo Bianconi 	.attrs = &st_lsm6dsx_acc_attribute_group,
833290a6ce1SLorenzo Bianconi 	.read_raw = st_lsm6dsx_read_raw,
834290a6ce1SLorenzo Bianconi 	.write_raw = st_lsm6dsx_write_raw,
835290a6ce1SLorenzo Bianconi 	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
836290a6ce1SLorenzo Bianconi };
837290a6ce1SLorenzo Bianconi 
838290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = {
839290a6ce1SLorenzo Bianconi 	&iio_dev_attr_sampling_frequency_available.dev_attr.attr,
840290a6ce1SLorenzo Bianconi 	&iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
841290a6ce1SLorenzo Bianconi 	NULL,
842290a6ce1SLorenzo Bianconi };
843290a6ce1SLorenzo Bianconi 
844290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = {
845290a6ce1SLorenzo Bianconi 	.attrs = st_lsm6dsx_gyro_attributes,
846290a6ce1SLorenzo Bianconi };
847290a6ce1SLorenzo Bianconi 
848290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = {
849290a6ce1SLorenzo Bianconi 	.attrs = &st_lsm6dsx_gyro_attribute_group,
850290a6ce1SLorenzo Bianconi 	.read_raw = st_lsm6dsx_read_raw,
851290a6ce1SLorenzo Bianconi 	.write_raw = st_lsm6dsx_write_raw,
852290a6ce1SLorenzo Bianconi 	.hwfifo_set_watermark = st_lsm6dsx_set_watermark,
853290a6ce1SLorenzo Bianconi };
854290a6ce1SLorenzo Bianconi 
855dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
856dba32904SLorenzo Bianconi {
857dba32904SLorenzo Bianconi 	struct device_node *np = hw->dev->of_node;
858dba32904SLorenzo Bianconi 
859dba32904SLorenzo Bianconi 	if (!np)
860dba32904SLorenzo Bianconi 		return -EINVAL;
861dba32904SLorenzo Bianconi 
862bf235277SLorenzo Bianconi 	return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
863dba32904SLorenzo Bianconi }
864dba32904SLorenzo Bianconi 
865dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
866dba32904SLorenzo Bianconi {
867dba32904SLorenzo Bianconi 	int err = 0, drdy_pin;
868dba32904SLorenzo Bianconi 
869dba32904SLorenzo Bianconi 	if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) {
870dba32904SLorenzo Bianconi 		struct st_sensors_platform_data *pdata;
871dba32904SLorenzo Bianconi 		struct device *dev = hw->dev;
872dba32904SLorenzo Bianconi 
873dba32904SLorenzo Bianconi 		pdata = (struct st_sensors_platform_data *)dev->platform_data;
874dba32904SLorenzo Bianconi 		drdy_pin = pdata ? pdata->drdy_int_pin : 1;
875dba32904SLorenzo Bianconi 	}
876dba32904SLorenzo Bianconi 
877dba32904SLorenzo Bianconi 	switch (drdy_pin) {
878dba32904SLorenzo Bianconi 	case 1:
879dba32904SLorenzo Bianconi 		*drdy_reg = ST_LSM6DSX_REG_INT1_ADDR;
880dba32904SLorenzo Bianconi 		break;
881dba32904SLorenzo Bianconi 	case 2:
882dba32904SLorenzo Bianconi 		*drdy_reg = ST_LSM6DSX_REG_INT2_ADDR;
883dba32904SLorenzo Bianconi 		break;
884dba32904SLorenzo Bianconi 	default:
885dba32904SLorenzo Bianconi 		dev_err(hw->dev, "unsupported data ready pin\n");
886dba32904SLorenzo Bianconi 		err = -EINVAL;
887dba32904SLorenzo Bianconi 		break;
888dba32904SLorenzo Bianconi 	}
889dba32904SLorenzo Bianconi 
890dba32904SLorenzo Bianconi 	return err;
891dba32904SLorenzo Bianconi }
892dba32904SLorenzo Bianconi 
893c91c1c84SLorenzo Bianconi static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw)
894c91c1c84SLorenzo Bianconi {
895c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
896c91c1c84SLorenzo Bianconi 	struct device_node *np = hw->dev->of_node;
897c91c1c84SLorenzo Bianconi 	struct st_sensors_platform_data *pdata;
898c91c1c84SLorenzo Bianconi 	unsigned int data;
899c91c1c84SLorenzo Bianconi 	int err = 0;
900c91c1c84SLorenzo Bianconi 
901c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
902c91c1c84SLorenzo Bianconi 
903c91c1c84SLorenzo Bianconi 	pdata = (struct st_sensors_platform_data *)hw->dev->platform_data;
904c91c1c84SLorenzo Bianconi 	if ((np && of_property_read_bool(np, "st,pullups")) ||
905c91c1c84SLorenzo Bianconi 	    (pdata && pdata->pullups)) {
906c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_set_page(hw, true);
907c91c1c84SLorenzo Bianconi 		if (err < 0)
908c91c1c84SLorenzo Bianconi 			return err;
909c91c1c84SLorenzo Bianconi 
910c91c1c84SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->pullup_en.mask);
911c91c1c84SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
912c91c1c84SLorenzo Bianconi 					 hub_settings->pullup_en.addr,
913c91c1c84SLorenzo Bianconi 					 hub_settings->pullup_en.mask, data);
914c91c1c84SLorenzo Bianconi 
915c91c1c84SLorenzo Bianconi 		st_lsm6dsx_set_page(hw, false);
916c91c1c84SLorenzo Bianconi 
917c91c1c84SLorenzo Bianconi 		if (err < 0)
918c91c1c84SLorenzo Bianconi 			return err;
919c91c1c84SLorenzo Bianconi 	}
920c91c1c84SLorenzo Bianconi 
921c91c1c84SLorenzo Bianconi 	if (hub_settings->aux_sens.addr) {
922c91c1c84SLorenzo Bianconi 		/* configure aux sensors */
923c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_set_page(hw, true);
924c91c1c84SLorenzo Bianconi 		if (err < 0)
925c91c1c84SLorenzo Bianconi 			return err;
926c91c1c84SLorenzo Bianconi 
927c91c1c84SLorenzo Bianconi 		data = ST_LSM6DSX_SHIFT_VAL(3, hub_settings->aux_sens.mask);
928c91c1c84SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
929c91c1c84SLorenzo Bianconi 					 hub_settings->aux_sens.addr,
930c91c1c84SLorenzo Bianconi 					 hub_settings->aux_sens.mask, data);
931c91c1c84SLorenzo Bianconi 
932c91c1c84SLorenzo Bianconi 		st_lsm6dsx_set_page(hw, false);
933c91c1c84SLorenzo Bianconi 	}
934c91c1c84SLorenzo Bianconi 
935c91c1c84SLorenzo Bianconi 	return err;
936c91c1c84SLorenzo Bianconi }
937c91c1c84SLorenzo Bianconi 
93821345107SLorenzo Bianconi static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw)
93921345107SLorenzo Bianconi {
94021345107SLorenzo Bianconi 	const struct st_lsm6dsx_hw_ts_settings *ts_settings;
94121345107SLorenzo Bianconi 	int err, val;
94221345107SLorenzo Bianconi 
94321345107SLorenzo Bianconi 	ts_settings = &hw->settings->ts_settings;
94421345107SLorenzo Bianconi 	/* enable hw timestamp generation if necessary */
94521345107SLorenzo Bianconi 	if (ts_settings->timer_en.addr) {
94621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask);
94721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
94821345107SLorenzo Bianconi 					 ts_settings->timer_en.addr,
94921345107SLorenzo Bianconi 					 ts_settings->timer_en.mask, val);
95021345107SLorenzo Bianconi 		if (err < 0)
95121345107SLorenzo Bianconi 			return err;
95221345107SLorenzo Bianconi 	}
95321345107SLorenzo Bianconi 
95421345107SLorenzo Bianconi 	/* enable high resolution for hw ts timer if necessary */
95521345107SLorenzo Bianconi 	if (ts_settings->hr_timer.addr) {
95621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask);
95721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
95821345107SLorenzo Bianconi 					 ts_settings->hr_timer.addr,
95921345107SLorenzo Bianconi 					 ts_settings->hr_timer.mask, val);
96021345107SLorenzo Bianconi 		if (err < 0)
96121345107SLorenzo Bianconi 			return err;
96221345107SLorenzo Bianconi 	}
96321345107SLorenzo Bianconi 
96421345107SLorenzo Bianconi 	/* enable ts queueing in FIFO if necessary */
96521345107SLorenzo Bianconi 	if (ts_settings->fifo_en.addr) {
96621345107SLorenzo Bianconi 		val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask);
96721345107SLorenzo Bianconi 		err = regmap_update_bits(hw->regmap,
96821345107SLorenzo Bianconi 					 ts_settings->fifo_en.addr,
96921345107SLorenzo Bianconi 					 ts_settings->fifo_en.mask, val);
97021345107SLorenzo Bianconi 		if (err < 0)
97121345107SLorenzo Bianconi 			return err;
97221345107SLorenzo Bianconi 	}
97321345107SLorenzo Bianconi 	return 0;
97421345107SLorenzo Bianconi }
97521345107SLorenzo Bianconi 
976290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
977290a6ce1SLorenzo Bianconi {
97851a8b707SLorenzo Bianconi 	u8 drdy_int_reg;
979290a6ce1SLorenzo Bianconi 	int err;
980290a6ce1SLorenzo Bianconi 
98119435425SLorenzo Bianconi 	/* device sw reset */
98219435425SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
98319435425SLorenzo Bianconi 				 ST_LSM6DSX_REG_RESET_MASK,
98419435425SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1));
985290a6ce1SLorenzo Bianconi 	if (err < 0)
986290a6ce1SLorenzo Bianconi 		return err;
987290a6ce1SLorenzo Bianconi 
98819435425SLorenzo Bianconi 	msleep(50);
98919435425SLorenzo Bianconi 
99019435425SLorenzo Bianconi 	/* reload trimming parameter */
99119435425SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
99219435425SLorenzo Bianconi 				 ST_LSM6DSX_REG_BOOT_MASK,
99319435425SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1));
99419435425SLorenzo Bianconi 	if (err < 0)
99519435425SLorenzo Bianconi 		return err;
99619435425SLorenzo Bianconi 
99719435425SLorenzo Bianconi 	msleep(50);
998290a6ce1SLorenzo Bianconi 
999290a6ce1SLorenzo Bianconi 	/* enable Block Data Update */
100051a8b707SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR,
100151a8b707SLorenzo Bianconi 				 ST_LSM6DSX_REG_BDU_MASK,
100251a8b707SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1));
1003290a6ce1SLorenzo Bianconi 	if (err < 0)
1004290a6ce1SLorenzo Bianconi 		return err;
1005290a6ce1SLorenzo Bianconi 
1006290a6ce1SLorenzo Bianconi 	/* enable FIFO watermak interrupt */
1007dba32904SLorenzo Bianconi 	err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg);
1008290a6ce1SLorenzo Bianconi 	if (err < 0)
1009290a6ce1SLorenzo Bianconi 		return err;
1010290a6ce1SLorenzo Bianconi 
101121345107SLorenzo Bianconi 	err = regmap_update_bits(hw->regmap, drdy_int_reg,
101251a8b707SLorenzo Bianconi 				 ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
101351a8b707SLorenzo Bianconi 				 FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK,
101451a8b707SLorenzo Bianconi 					    1));
101521345107SLorenzo Bianconi 	if (err < 0)
101621345107SLorenzo Bianconi 		return err;
101721345107SLorenzo Bianconi 
1018c91c1c84SLorenzo Bianconi 	err = st_lsm6dsx_init_shub(hw);
1019c91c1c84SLorenzo Bianconi 	if (err < 0)
1020c91c1c84SLorenzo Bianconi 		return err;
1021c91c1c84SLorenzo Bianconi 
102221345107SLorenzo Bianconi 	return st_lsm6dsx_init_hw_timer(hw);
1023290a6ce1SLorenzo Bianconi }
1024290a6ce1SLorenzo Bianconi 
1025290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
1026510c0106SLorenzo Bianconi 					       enum st_lsm6dsx_sensor_id id,
1027510c0106SLorenzo Bianconi 					       const char *name)
1028290a6ce1SLorenzo Bianconi {
1029290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
1030290a6ce1SLorenzo Bianconi 	struct iio_dev *iio_dev;
1031290a6ce1SLorenzo Bianconi 
1032290a6ce1SLorenzo Bianconi 	iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
1033290a6ce1SLorenzo Bianconi 	if (!iio_dev)
1034290a6ce1SLorenzo Bianconi 		return NULL;
1035290a6ce1SLorenzo Bianconi 
1036290a6ce1SLorenzo Bianconi 	iio_dev->modes = INDIO_DIRECT_MODE;
1037290a6ce1SLorenzo Bianconi 	iio_dev->dev.parent = hw->dev;
1038290a6ce1SLorenzo Bianconi 	iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
1039290a6ce1SLorenzo Bianconi 
1040290a6ce1SLorenzo Bianconi 	sensor = iio_priv(iio_dev);
1041290a6ce1SLorenzo Bianconi 	sensor->id = id;
1042290a6ce1SLorenzo Bianconi 	sensor->hw = hw;
1043290a6ce1SLorenzo Bianconi 	sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
1044290a6ce1SLorenzo Bianconi 	sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
1045290a6ce1SLorenzo Bianconi 	sensor->watermark = 1;
1046290a6ce1SLorenzo Bianconi 
1047290a6ce1SLorenzo Bianconi 	switch (id) {
1048290a6ce1SLorenzo Bianconi 	case ST_LSM6DSX_ID_ACC:
1049290a6ce1SLorenzo Bianconi 		iio_dev->channels = st_lsm6dsx_acc_channels;
1050290a6ce1SLorenzo Bianconi 		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
1051290a6ce1SLorenzo Bianconi 		iio_dev->info = &st_lsm6dsx_acc_info;
1052290a6ce1SLorenzo Bianconi 
1053510c0106SLorenzo Bianconi 		scnprintf(sensor->name, sizeof(sensor->name), "%s_accel",
1054510c0106SLorenzo Bianconi 			  name);
1055290a6ce1SLorenzo Bianconi 		break;
1056290a6ce1SLorenzo Bianconi 	case ST_LSM6DSX_ID_GYRO:
1057290a6ce1SLorenzo Bianconi 		iio_dev->channels = st_lsm6dsx_gyro_channels;
1058290a6ce1SLorenzo Bianconi 		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
1059290a6ce1SLorenzo Bianconi 		iio_dev->info = &st_lsm6dsx_gyro_info;
1060290a6ce1SLorenzo Bianconi 
1061510c0106SLorenzo Bianconi 		scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
1062510c0106SLorenzo Bianconi 			  name);
1063290a6ce1SLorenzo Bianconi 		break;
1064290a6ce1SLorenzo Bianconi 	default:
1065290a6ce1SLorenzo Bianconi 		return NULL;
1066290a6ce1SLorenzo Bianconi 	}
1067510c0106SLorenzo Bianconi 	iio_dev->name = sensor->name;
1068290a6ce1SLorenzo Bianconi 
1069290a6ce1SLorenzo Bianconi 	return iio_dev;
1070290a6ce1SLorenzo Bianconi }
1071290a6ce1SLorenzo Bianconi 
107281956a93SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
107351a8b707SLorenzo Bianconi 		     struct regmap *regmap)
1074290a6ce1SLorenzo Bianconi {
1075c91c1c84SLorenzo Bianconi 	const struct st_lsm6dsx_shub_settings *hub_settings;
1076290a6ce1SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw;
107781956a93SLorenzo Bianconi 	const char *name = NULL;
1078290a6ce1SLorenzo Bianconi 	int i, err;
1079290a6ce1SLorenzo Bianconi 
1080290a6ce1SLorenzo Bianconi 	hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
1081290a6ce1SLorenzo Bianconi 	if (!hw)
1082290a6ce1SLorenzo Bianconi 		return -ENOMEM;
1083290a6ce1SLorenzo Bianconi 
1084290a6ce1SLorenzo Bianconi 	dev_set_drvdata(dev, (void *)hw);
1085290a6ce1SLorenzo Bianconi 
1086290a6ce1SLorenzo Bianconi 	mutex_init(&hw->fifo_lock);
1087335eaedcSLorenzo Bianconi 	mutex_init(&hw->conf_lock);
1088739aff87SLorenzo Bianconi 	mutex_init(&hw->page_lock);
1089290a6ce1SLorenzo Bianconi 
109091a6b841SLorenzo Bianconi 	hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL);
109191a6b841SLorenzo Bianconi 	if (!hw->buff)
109291a6b841SLorenzo Bianconi 		return -ENOMEM;
109391a6b841SLorenzo Bianconi 
1094290a6ce1SLorenzo Bianconi 	hw->dev = dev;
1095290a6ce1SLorenzo Bianconi 	hw->irq = irq;
109651a8b707SLorenzo Bianconi 	hw->regmap = regmap;
1097290a6ce1SLorenzo Bianconi 
109881956a93SLorenzo Bianconi 	err = st_lsm6dsx_check_whoami(hw, hw_id, &name);
1099290a6ce1SLorenzo Bianconi 	if (err < 0)
1100290a6ce1SLorenzo Bianconi 		return err;
1101290a6ce1SLorenzo Bianconi 
11026ffb55e5SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) {
1103510c0106SLorenzo Bianconi 		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
1104290a6ce1SLorenzo Bianconi 		if (!hw->iio_devs[i])
1105290a6ce1SLorenzo Bianconi 			return -ENOMEM;
1106290a6ce1SLorenzo Bianconi 	}
1107290a6ce1SLorenzo Bianconi 
1108290a6ce1SLorenzo Bianconi 	err = st_lsm6dsx_init_device(hw);
1109290a6ce1SLorenzo Bianconi 	if (err < 0)
1110290a6ce1SLorenzo Bianconi 		return err;
1111290a6ce1SLorenzo Bianconi 
1112c91c1c84SLorenzo Bianconi 	hub_settings = &hw->settings->shub_settings;
1113c91c1c84SLorenzo Bianconi 	if (hub_settings->master_en.addr) {
1114c91c1c84SLorenzo Bianconi 		err = st_lsm6dsx_shub_probe(hw, name);
1115c91c1c84SLorenzo Bianconi 		if (err < 0)
1116c91c1c84SLorenzo Bianconi 			return err;
1117c91c1c84SLorenzo Bianconi 	}
1118c91c1c84SLorenzo Bianconi 
1119290a6ce1SLorenzo Bianconi 	if (hw->irq > 0) {
1120290a6ce1SLorenzo Bianconi 		err = st_lsm6dsx_fifo_setup(hw);
1121290a6ce1SLorenzo Bianconi 		if (err < 0)
1122290a6ce1SLorenzo Bianconi 			return err;
1123290a6ce1SLorenzo Bianconi 	}
1124290a6ce1SLorenzo Bianconi 
1125290a6ce1SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
11266ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
11276ffb55e5SLorenzo Bianconi 			continue;
11286ffb55e5SLorenzo Bianconi 
1129290a6ce1SLorenzo Bianconi 		err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
1130290a6ce1SLorenzo Bianconi 		if (err)
1131290a6ce1SLorenzo Bianconi 			return err;
1132290a6ce1SLorenzo Bianconi 	}
1133290a6ce1SLorenzo Bianconi 
1134290a6ce1SLorenzo Bianconi 	return 0;
1135290a6ce1SLorenzo Bianconi }
1136290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe);
1137290a6ce1SLorenzo Bianconi 
11383cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev)
1139d3f77058SLorenzo Bianconi {
1140d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
1141d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
1142d3f77058SLorenzo Bianconi 	int i, err = 0;
1143d3f77058SLorenzo Bianconi 
1144d3f77058SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
11456ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
11466ffb55e5SLorenzo Bianconi 			continue;
11476ffb55e5SLorenzo Bianconi 
1148d3f77058SLorenzo Bianconi 		sensor = iio_priv(hw->iio_devs[i]);
1149d3f77058SLorenzo Bianconi 		if (!(hw->enable_mask & BIT(sensor->id)))
1150d3f77058SLorenzo Bianconi 			continue;
1151d3f77058SLorenzo Bianconi 
1152bce0d57dSLorenzo Bianconi 		if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
1153bce0d57dSLorenzo Bianconi 		    sensor->id == ST_LSM6DSX_ID_EXT1 ||
1154bce0d57dSLorenzo Bianconi 		    sensor->id == ST_LSM6DSX_ID_EXT2)
1155bce0d57dSLorenzo Bianconi 			err = st_lsm6dsx_shub_set_enable(sensor, false);
1156bce0d57dSLorenzo Bianconi 		else
1157bce0d57dSLorenzo Bianconi 			err = st_lsm6dsx_sensor_set_enable(sensor, false);
1158d3f77058SLorenzo Bianconi 		if (err < 0)
1159d3f77058SLorenzo Bianconi 			return err;
1160bce0d57dSLorenzo Bianconi 
1161bce0d57dSLorenzo Bianconi 		hw->suspend_mask |= BIT(sensor->id);
1162d3f77058SLorenzo Bianconi 	}
1163d3f77058SLorenzo Bianconi 
1164d3f77058SLorenzo Bianconi 	if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS)
1165d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_flush_fifo(hw);
1166d3f77058SLorenzo Bianconi 
1167d3f77058SLorenzo Bianconi 	return err;
1168d3f77058SLorenzo Bianconi }
1169d3f77058SLorenzo Bianconi 
11703cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev)
1171d3f77058SLorenzo Bianconi {
1172d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev);
1173d3f77058SLorenzo Bianconi 	struct st_lsm6dsx_sensor *sensor;
1174d3f77058SLorenzo Bianconi 	int i, err = 0;
1175d3f77058SLorenzo Bianconi 
1176d3f77058SLorenzo Bianconi 	for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
11776ffb55e5SLorenzo Bianconi 		if (!hw->iio_devs[i])
11786ffb55e5SLorenzo Bianconi 			continue;
11796ffb55e5SLorenzo Bianconi 
1180d3f77058SLorenzo Bianconi 		sensor = iio_priv(hw->iio_devs[i]);
1181bce0d57dSLorenzo Bianconi 		if (!(hw->suspend_mask & BIT(sensor->id)))
1182d3f77058SLorenzo Bianconi 			continue;
1183d3f77058SLorenzo Bianconi 
1184bce0d57dSLorenzo Bianconi 		if (sensor->id == ST_LSM6DSX_ID_EXT0 ||
1185bce0d57dSLorenzo Bianconi 		    sensor->id == ST_LSM6DSX_ID_EXT1 ||
1186bce0d57dSLorenzo Bianconi 		    sensor->id == ST_LSM6DSX_ID_EXT2)
1187bce0d57dSLorenzo Bianconi 			err = st_lsm6dsx_shub_set_enable(sensor, true);
1188bce0d57dSLorenzo Bianconi 		else
1189bce0d57dSLorenzo Bianconi 			err = st_lsm6dsx_sensor_set_enable(sensor, true);
1190d3f77058SLorenzo Bianconi 		if (err < 0)
1191d3f77058SLorenzo Bianconi 			return err;
1192bce0d57dSLorenzo Bianconi 
1193bce0d57dSLorenzo Bianconi 		hw->suspend_mask &= ~BIT(sensor->id);
1194d3f77058SLorenzo Bianconi 	}
1195d3f77058SLorenzo Bianconi 
1196d3f77058SLorenzo Bianconi 	if (hw->enable_mask)
1197d3f77058SLorenzo Bianconi 		err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
1198d3f77058SLorenzo Bianconi 
1199d3f77058SLorenzo Bianconi 	return err;
1200d3f77058SLorenzo Bianconi }
1201d3f77058SLorenzo Bianconi 
1202d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = {
1203d3f77058SLorenzo Bianconi 	SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume)
1204d3f77058SLorenzo Bianconi };
1205d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops);
1206d3f77058SLorenzo Bianconi 
1207290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
1208290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
1209290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
1210290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2");
1211