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