1290a6ce1SLorenzo Bianconi /* 2290a6ce1SLorenzo Bianconi * STMicroelectronics st_lsm6dsx sensor driver 3290a6ce1SLorenzo Bianconi * 4290a6ce1SLorenzo Bianconi * The ST LSM6DSx IMU MEMS series consists of 3D digital accelerometer 5290a6ce1SLorenzo Bianconi * and 3D digital gyroscope system-in-package with a digital I2C/SPI serial 6290a6ce1SLorenzo Bianconi * interface standard output. 7290a6ce1SLorenzo Bianconi * LSM6DSx IMU MEMS series has a dynamic user-selectable full-scale 8290a6ce1SLorenzo Bianconi * acceleration range of +-2/+-4/+-8/+-16 g and an angular rate range of 9290a6ce1SLorenzo Bianconi * +-125/+-245/+-500/+-1000/+-2000 dps 10290a6ce1SLorenzo Bianconi * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer 11290a6ce1SLorenzo Bianconi * allowing dynamic batching of sensor data. 12290a6ce1SLorenzo Bianconi * 13290a6ce1SLorenzo Bianconi * Supported sensors: 14290a6ce1SLorenzo Bianconi * - LSM6DS3: 15290a6ce1SLorenzo Bianconi * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 16290a6ce1SLorenzo Bianconi * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 17290a6ce1SLorenzo Bianconi * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 18290a6ce1SLorenzo Bianconi * - FIFO size: 8KB 19290a6ce1SLorenzo Bianconi * 20179c8d60SLorenzo Bianconi * - LSM6DS3H/LSM6DSL/LSM6DSM/ISM330DLC: 21290a6ce1SLorenzo Bianconi * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 22290a6ce1SLorenzo Bianconi * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 23290a6ce1SLorenzo Bianconi * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 24290a6ce1SLorenzo Bianconi * - FIFO size: 4KB 25290a6ce1SLorenzo Bianconi * 26801a6e0aSLorenzo Bianconi * - LSM6DSO 27801a6e0aSLorenzo Bianconi * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416 28801a6e0aSLorenzo Bianconi * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 29801a6e0aSLorenzo Bianconi * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 30801a6e0aSLorenzo Bianconi * - FIFO size: 3KB 31801a6e0aSLorenzo Bianconi * 32290a6ce1SLorenzo Bianconi * Copyright 2016 STMicroelectronics Inc. 33290a6ce1SLorenzo Bianconi * 34290a6ce1SLorenzo Bianconi * Lorenzo Bianconi <lorenzo.bianconi@st.com> 35290a6ce1SLorenzo Bianconi * Denis Ciocca <denis.ciocca@st.com> 36290a6ce1SLorenzo Bianconi * 37290a6ce1SLorenzo Bianconi * Licensed under the GPL-2. 38290a6ce1SLorenzo Bianconi */ 39290a6ce1SLorenzo Bianconi 40290a6ce1SLorenzo Bianconi #include <linux/kernel.h> 41290a6ce1SLorenzo Bianconi #include <linux/module.h> 42290a6ce1SLorenzo Bianconi #include <linux/delay.h> 43290a6ce1SLorenzo Bianconi #include <linux/iio/iio.h> 44290a6ce1SLorenzo Bianconi #include <linux/iio/sysfs.h> 45d3f77058SLorenzo Bianconi #include <linux/pm.h> 4651a8b707SLorenzo Bianconi #include <linux/regmap.h> 4751a8b707SLorenzo Bianconi #include <linux/bitfield.h> 48290a6ce1SLorenzo Bianconi 49dba32904SLorenzo Bianconi #include <linux/platform_data/st_sensors_pdata.h> 50dba32904SLorenzo Bianconi 51290a6ce1SLorenzo Bianconi #include "st_lsm6dsx.h" 52290a6ce1SLorenzo Bianconi 53290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT1_ADDR 0x0d 54dba32904SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ADDR 0x0e 55290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3) 56290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f 57290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_ADDR 0x12 58290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_MASK BIT(0) 5919435425SLorenzo Bianconi #define ST_LSM6DSX_REG_BOOT_MASK BIT(7) 60290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_ADDR 0x12 61290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_MASK BIT(6) 62290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13 63290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5) 64290a6ce1SLorenzo Bianconi 65290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_ADDR 0x10 66290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_MASK GENMASK(7, 4) 67290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_ADDR 0x10 68290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_MASK GENMASK(3, 2) 69290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28 70290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a 71290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c 72290a6ce1SLorenzo Bianconi 73290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_ADDR 0x11 74290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_MASK GENMASK(7, 4) 75290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_ADDR 0x11 76290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_MASK GENMASK(3, 2) 77290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22 78290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 79290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 80290a6ce1SLorenzo Bianconi 81290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61) 82290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122) 83290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244) 84290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488) 85290a6ce1SLorenzo Bianconi 86dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_245_GAIN IIO_DEGREE_TO_RAD(8750) 87dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(17500) 88dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(35000) 89290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000) 90290a6ce1SLorenzo Bianconi 91290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { 92290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 93290a6ce1SLorenzo Bianconi .reg = { 94290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_ACC_ODR_ADDR, 95290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_ACC_ODR_MASK, 96290a6ce1SLorenzo Bianconi }, 97290a6ce1SLorenzo Bianconi .odr_avl[0] = { 13, 0x01 }, 98290a6ce1SLorenzo Bianconi .odr_avl[1] = { 26, 0x02 }, 99290a6ce1SLorenzo Bianconi .odr_avl[2] = { 52, 0x03 }, 100290a6ce1SLorenzo Bianconi .odr_avl[3] = { 104, 0x04 }, 101290a6ce1SLorenzo Bianconi .odr_avl[4] = { 208, 0x05 }, 102290a6ce1SLorenzo Bianconi .odr_avl[5] = { 416, 0x06 }, 103290a6ce1SLorenzo Bianconi }, 104290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 105290a6ce1SLorenzo Bianconi .reg = { 106290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR, 107290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_GYRO_ODR_MASK, 108290a6ce1SLorenzo Bianconi }, 109290a6ce1SLorenzo Bianconi .odr_avl[0] = { 13, 0x01 }, 110290a6ce1SLorenzo Bianconi .odr_avl[1] = { 26, 0x02 }, 111290a6ce1SLorenzo Bianconi .odr_avl[2] = { 52, 0x03 }, 112290a6ce1SLorenzo Bianconi .odr_avl[3] = { 104, 0x04 }, 113290a6ce1SLorenzo Bianconi .odr_avl[4] = { 208, 0x05 }, 114290a6ce1SLorenzo Bianconi .odr_avl[5] = { 416, 0x06 }, 115290a6ce1SLorenzo Bianconi } 116290a6ce1SLorenzo Bianconi }; 117290a6ce1SLorenzo Bianconi 118290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { 119290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 120290a6ce1SLorenzo Bianconi .reg = { 121290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_ACC_FS_ADDR, 122290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_ACC_FS_MASK, 123290a6ce1SLorenzo Bianconi }, 124290a6ce1SLorenzo Bianconi .fs_avl[0] = { ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 }, 125290a6ce1SLorenzo Bianconi .fs_avl[1] = { ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 }, 126290a6ce1SLorenzo Bianconi .fs_avl[2] = { ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 }, 127290a6ce1SLorenzo Bianconi .fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 }, 128290a6ce1SLorenzo Bianconi }, 129290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 130290a6ce1SLorenzo Bianconi .reg = { 131290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_GYRO_FS_ADDR, 132290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_GYRO_FS_MASK, 133290a6ce1SLorenzo Bianconi }, 134290a6ce1SLorenzo Bianconi .fs_avl[0] = { ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 }, 135290a6ce1SLorenzo Bianconi .fs_avl[1] = { ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 }, 136290a6ce1SLorenzo Bianconi .fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 }, 137290a6ce1SLorenzo Bianconi .fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 }, 138290a6ce1SLorenzo Bianconi } 139290a6ce1SLorenzo Bianconi }; 140290a6ce1SLorenzo Bianconi 141290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { 142290a6ce1SLorenzo Bianconi { 143d068e4a0SLorenzo Bianconi .wai = 0x69, 1448f2a88a2SLorenzo Bianconi .max_fifo_size = 1365, 145d068e4a0SLorenzo Bianconi .id = { 146d068e4a0SLorenzo Bianconi [0] = ST_LSM6DS3_ID, 147d068e4a0SLorenzo Bianconi }, 1487ca3ac9eSLorenzo Bianconi .decimator = { 1497ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 1507ca3ac9eSLorenzo Bianconi .addr = 0x08, 1517ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 1527ca3ac9eSLorenzo Bianconi }, 1537ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 1547ca3ac9eSLorenzo Bianconi .addr = 0x08, 1557ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 1567ca3ac9eSLorenzo Bianconi }, 1577ca3ac9eSLorenzo Bianconi }, 15892617c15SLorenzo Bianconi .fifo_ops = { 15950ff457dSLorenzo Bianconi .read_fifo = st_lsm6dsx_read_fifo, 16092617c15SLorenzo Bianconi .fifo_th = { 16192617c15SLorenzo Bianconi .addr = 0x06, 16292617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 16392617c15SLorenzo Bianconi }, 16492617c15SLorenzo Bianconi .fifo_diff = { 16592617c15SLorenzo Bianconi .addr = 0x3a, 16692617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 16792617c15SLorenzo Bianconi }, 16892617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 16992617c15SLorenzo Bianconi }, 17021345107SLorenzo Bianconi .ts_settings = { 17121345107SLorenzo Bianconi .timer_en = { 17221345107SLorenzo Bianconi .addr = 0x58, 17321345107SLorenzo Bianconi .mask = BIT(7), 17421345107SLorenzo Bianconi }, 17521345107SLorenzo Bianconi .hr_timer = { 17621345107SLorenzo Bianconi .addr = 0x5c, 17721345107SLorenzo Bianconi .mask = BIT(4), 17821345107SLorenzo Bianconi }, 17921345107SLorenzo Bianconi .fifo_en = { 18021345107SLorenzo Bianconi .addr = 0x07, 18121345107SLorenzo Bianconi .mask = BIT(7), 18221345107SLorenzo Bianconi }, 18321345107SLorenzo Bianconi .decimator = { 18421345107SLorenzo Bianconi .addr = 0x09, 18521345107SLorenzo Bianconi .mask = GENMASK(5, 3), 18621345107SLorenzo Bianconi }, 18721345107SLorenzo Bianconi }, 188290a6ce1SLorenzo Bianconi }, 189290a6ce1SLorenzo Bianconi { 190df47710aSLorenzo Bianconi .wai = 0x69, 1918f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 192df47710aSLorenzo Bianconi .id = { 193df47710aSLorenzo Bianconi [0] = ST_LSM6DS3H_ID, 194df47710aSLorenzo Bianconi }, 1957ca3ac9eSLorenzo Bianconi .decimator = { 1967ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 1977ca3ac9eSLorenzo Bianconi .addr = 0x08, 1987ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 1997ca3ac9eSLorenzo Bianconi }, 2007ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 2017ca3ac9eSLorenzo Bianconi .addr = 0x08, 2027ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 2037ca3ac9eSLorenzo Bianconi }, 2047ca3ac9eSLorenzo Bianconi }, 20592617c15SLorenzo Bianconi .fifo_ops = { 20650ff457dSLorenzo Bianconi .read_fifo = st_lsm6dsx_read_fifo, 20792617c15SLorenzo Bianconi .fifo_th = { 20892617c15SLorenzo Bianconi .addr = 0x06, 20992617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 21092617c15SLorenzo Bianconi }, 21192617c15SLorenzo Bianconi .fifo_diff = { 21292617c15SLorenzo Bianconi .addr = 0x3a, 21392617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 21492617c15SLorenzo Bianconi }, 21592617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 21692617c15SLorenzo Bianconi }, 21721345107SLorenzo Bianconi .ts_settings = { 21821345107SLorenzo Bianconi .timer_en = { 21921345107SLorenzo Bianconi .addr = 0x58, 22021345107SLorenzo Bianconi .mask = BIT(7), 22121345107SLorenzo Bianconi }, 22221345107SLorenzo Bianconi .hr_timer = { 22321345107SLorenzo Bianconi .addr = 0x5c, 22421345107SLorenzo Bianconi .mask = BIT(4), 22521345107SLorenzo Bianconi }, 22621345107SLorenzo Bianconi .fifo_en = { 22721345107SLorenzo Bianconi .addr = 0x07, 22821345107SLorenzo Bianconi .mask = BIT(7), 22921345107SLorenzo Bianconi }, 23021345107SLorenzo Bianconi .decimator = { 23121345107SLorenzo Bianconi .addr = 0x09, 23221345107SLorenzo Bianconi .mask = GENMASK(5, 3), 23321345107SLorenzo Bianconi }, 23421345107SLorenzo Bianconi }, 235df47710aSLorenzo Bianconi }, 236df47710aSLorenzo Bianconi { 237d068e4a0SLorenzo Bianconi .wai = 0x6a, 2388f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 239d068e4a0SLorenzo Bianconi .id = { 2400b2a3e5fSLorenzo Bianconi [0] = ST_LSM6DSL_ID, 2410b2a3e5fSLorenzo Bianconi [1] = ST_LSM6DSM_ID, 242179c8d60SLorenzo Bianconi [2] = ST_ISM330DLC_ID, 243d068e4a0SLorenzo Bianconi }, 2447ca3ac9eSLorenzo Bianconi .decimator = { 2457ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 2467ca3ac9eSLorenzo Bianconi .addr = 0x08, 2477ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 2487ca3ac9eSLorenzo Bianconi }, 2497ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 2507ca3ac9eSLorenzo Bianconi .addr = 0x08, 2517ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 2527ca3ac9eSLorenzo Bianconi }, 2537ca3ac9eSLorenzo Bianconi }, 25492617c15SLorenzo Bianconi .fifo_ops = { 25550ff457dSLorenzo Bianconi .read_fifo = st_lsm6dsx_read_fifo, 25692617c15SLorenzo Bianconi .fifo_th = { 25792617c15SLorenzo Bianconi .addr = 0x06, 258be75eb86SLorenzo Bianconi .mask = GENMASK(10, 0), 25992617c15SLorenzo Bianconi }, 26092617c15SLorenzo Bianconi .fifo_diff = { 26192617c15SLorenzo Bianconi .addr = 0x3a, 262be75eb86SLorenzo Bianconi .mask = GENMASK(10, 0), 26392617c15SLorenzo Bianconi }, 26492617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 26592617c15SLorenzo Bianconi }, 26621345107SLorenzo Bianconi .ts_settings = { 26721345107SLorenzo Bianconi .timer_en = { 26821345107SLorenzo Bianconi .addr = 0x19, 26921345107SLorenzo Bianconi .mask = BIT(5), 27021345107SLorenzo Bianconi }, 27121345107SLorenzo Bianconi .hr_timer = { 27221345107SLorenzo Bianconi .addr = 0x5c, 27321345107SLorenzo Bianconi .mask = BIT(4), 27421345107SLorenzo Bianconi }, 27521345107SLorenzo Bianconi .fifo_en = { 27621345107SLorenzo Bianconi .addr = 0x07, 27721345107SLorenzo Bianconi .mask = BIT(7), 27821345107SLorenzo Bianconi }, 27921345107SLorenzo Bianconi .decimator = { 28021345107SLorenzo Bianconi .addr = 0x09, 28121345107SLorenzo Bianconi .mask = GENMASK(5, 3), 28221345107SLorenzo Bianconi }, 28321345107SLorenzo Bianconi }, 284290a6ce1SLorenzo Bianconi }, 285801a6e0aSLorenzo Bianconi { 286801a6e0aSLorenzo Bianconi .wai = 0x6c, 287801a6e0aSLorenzo Bianconi .max_fifo_size = 512, 288801a6e0aSLorenzo Bianconi .id = { 289801a6e0aSLorenzo Bianconi [0] = ST_LSM6DSO_ID, 290801a6e0aSLorenzo Bianconi }, 291801a6e0aSLorenzo Bianconi .batch = { 292801a6e0aSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 293801a6e0aSLorenzo Bianconi .addr = 0x09, 294801a6e0aSLorenzo Bianconi .mask = GENMASK(3, 0), 295801a6e0aSLorenzo Bianconi }, 296801a6e0aSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 297801a6e0aSLorenzo Bianconi .addr = 0x09, 298801a6e0aSLorenzo Bianconi .mask = GENMASK(7, 4), 299801a6e0aSLorenzo Bianconi }, 300801a6e0aSLorenzo Bianconi }, 301801a6e0aSLorenzo Bianconi .fifo_ops = { 302801a6e0aSLorenzo Bianconi .read_fifo = st_lsm6dsx_read_tagged_fifo, 303801a6e0aSLorenzo Bianconi .fifo_th = { 304801a6e0aSLorenzo Bianconi .addr = 0x07, 305801a6e0aSLorenzo Bianconi .mask = GENMASK(8, 0), 306801a6e0aSLorenzo Bianconi }, 307801a6e0aSLorenzo Bianconi .fifo_diff = { 308801a6e0aSLorenzo Bianconi .addr = 0x3a, 309801a6e0aSLorenzo Bianconi .mask = GENMASK(8, 0), 310801a6e0aSLorenzo Bianconi }, 311801a6e0aSLorenzo Bianconi .th_wl = 1, 312801a6e0aSLorenzo Bianconi }, 313801a6e0aSLorenzo Bianconi .ts_settings = { 314801a6e0aSLorenzo Bianconi .timer_en = { 315801a6e0aSLorenzo Bianconi .addr = 0x19, 316801a6e0aSLorenzo Bianconi .mask = BIT(5), 317801a6e0aSLorenzo Bianconi }, 318801a6e0aSLorenzo Bianconi .decimator = { 319801a6e0aSLorenzo Bianconi .addr = 0x0a, 320801a6e0aSLorenzo Bianconi .mask = GENMASK(7, 6), 321801a6e0aSLorenzo Bianconi }, 322801a6e0aSLorenzo Bianconi }, 323c91c1c84SLorenzo Bianconi .shub_settings = { 324c91c1c84SLorenzo Bianconi .page_mux = { 325c91c1c84SLorenzo Bianconi .addr = 0x01, 326c91c1c84SLorenzo Bianconi .mask = BIT(6), 327c91c1c84SLorenzo Bianconi }, 328c91c1c84SLorenzo Bianconi .master_en = { 329c91c1c84SLorenzo Bianconi .addr = 0x14, 330c91c1c84SLorenzo Bianconi .mask = BIT(2), 331c91c1c84SLorenzo Bianconi }, 332c91c1c84SLorenzo Bianconi .pullup_en = { 333c91c1c84SLorenzo Bianconi .addr = 0x14, 334c91c1c84SLorenzo Bianconi .mask = BIT(3), 335c91c1c84SLorenzo Bianconi }, 336c91c1c84SLorenzo Bianconi .aux_sens = { 337c91c1c84SLorenzo Bianconi .addr = 0x14, 338c91c1c84SLorenzo Bianconi .mask = GENMASK(1, 0), 339c91c1c84SLorenzo Bianconi }, 340c91c1c84SLorenzo Bianconi .shub_out = 0x02, 341c91c1c84SLorenzo Bianconi .slv0_addr = 0x15, 342c91c1c84SLorenzo Bianconi .dw_slv0_addr = 0x21, 343c91c1c84SLorenzo Bianconi } 344801a6e0aSLorenzo Bianconi }, 345290a6ce1SLorenzo Bianconi }; 346290a6ce1SLorenzo Bianconi 347290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { 348290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR, 349290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 350290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR, 351290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 352290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR, 353290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 354290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 355290a6ce1SLorenzo Bianconi }; 356290a6ce1SLorenzo Bianconi 357290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { 358290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR, 359290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 360290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR, 361290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 362290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR, 363290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 364290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 365290a6ce1SLorenzo Bianconi }; 366290a6ce1SLorenzo Bianconi 367c91c1c84SLorenzo Bianconi int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable) 368c91c1c84SLorenzo Bianconi { 369c91c1c84SLorenzo Bianconi const struct st_lsm6dsx_shub_settings *hub_settings; 370c91c1c84SLorenzo Bianconi unsigned int data; 371c91c1c84SLorenzo Bianconi int err; 372c91c1c84SLorenzo Bianconi 373c91c1c84SLorenzo Bianconi hub_settings = &hw->settings->shub_settings; 374c91c1c84SLorenzo Bianconi data = ST_LSM6DSX_SHIFT_VAL(enable, hub_settings->page_mux.mask); 375c91c1c84SLorenzo Bianconi err = regmap_update_bits(hw->regmap, hub_settings->page_mux.addr, 376c91c1c84SLorenzo Bianconi hub_settings->page_mux.mask, data); 377c91c1c84SLorenzo Bianconi usleep_range(100, 150); 378c91c1c84SLorenzo Bianconi 379c91c1c84SLorenzo Bianconi return err; 380c91c1c84SLorenzo Bianconi } 381c91c1c84SLorenzo Bianconi 382290a6ce1SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id) 383290a6ce1SLorenzo Bianconi { 38451a8b707SLorenzo Bianconi int err, i, j, data; 385290a6ce1SLorenzo Bianconi 386290a6ce1SLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) { 387d068e4a0SLorenzo Bianconi for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) { 388d068e4a0SLorenzo Bianconi if (id == st_lsm6dsx_sensor_settings[i].id[j]) 389d068e4a0SLorenzo Bianconi break; 390d068e4a0SLorenzo Bianconi } 391d068e4a0SLorenzo Bianconi if (j < ST_LSM6DSX_MAX_ID) 392290a6ce1SLorenzo Bianconi break; 393290a6ce1SLorenzo Bianconi } 394290a6ce1SLorenzo Bianconi 395290a6ce1SLorenzo Bianconi if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) { 396290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported hw id [%02x]\n", id); 397290a6ce1SLorenzo Bianconi return -ENODEV; 398290a6ce1SLorenzo Bianconi } 399290a6ce1SLorenzo Bianconi 40051a8b707SLorenzo Bianconi err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data); 401290a6ce1SLorenzo Bianconi if (err < 0) { 402290a6ce1SLorenzo Bianconi dev_err(hw->dev, "failed to read whoami register\n"); 403290a6ce1SLorenzo Bianconi return err; 404290a6ce1SLorenzo Bianconi } 405290a6ce1SLorenzo Bianconi 406290a6ce1SLorenzo Bianconi if (data != st_lsm6dsx_sensor_settings[i].wai) { 407290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported whoami [%02x]\n", data); 408290a6ce1SLorenzo Bianconi return -ENODEV; 409290a6ce1SLorenzo Bianconi } 410290a6ce1SLorenzo Bianconi 411290a6ce1SLorenzo Bianconi hw->settings = &st_lsm6dsx_sensor_settings[i]; 412290a6ce1SLorenzo Bianconi 413290a6ce1SLorenzo Bianconi return 0; 414290a6ce1SLorenzo Bianconi } 415290a6ce1SLorenzo Bianconi 416290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, 417290a6ce1SLorenzo Bianconi u32 gain) 418290a6ce1SLorenzo Bianconi { 41951a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 42051a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 421739aff87SLorenzo Bianconi unsigned int data; 422290a6ce1SLorenzo Bianconi int i, err; 423290a6ce1SLorenzo Bianconi u8 val; 424290a6ce1SLorenzo Bianconi 425290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 42651a8b707SLorenzo Bianconi if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain) 427290a6ce1SLorenzo Bianconi break; 428290a6ce1SLorenzo Bianconi 429290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_FS_LIST_SIZE) 430290a6ce1SLorenzo Bianconi return -EINVAL; 431290a6ce1SLorenzo Bianconi 43251a8b707SLorenzo Bianconi val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val; 43351a8b707SLorenzo Bianconi reg = &st_lsm6dsx_fs_table[sensor->id].reg; 434739aff87SLorenzo Bianconi data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); 435739aff87SLorenzo Bianconi err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data); 436290a6ce1SLorenzo Bianconi if (err < 0) 437290a6ce1SLorenzo Bianconi return err; 438290a6ce1SLorenzo Bianconi 439290a6ce1SLorenzo Bianconi sensor->gain = gain; 440290a6ce1SLorenzo Bianconi 441290a6ce1SLorenzo Bianconi return 0; 442290a6ce1SLorenzo Bianconi } 443290a6ce1SLorenzo Bianconi 44454a6d0c6SLorenzo Bianconi int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) 445290a6ce1SLorenzo Bianconi { 4462ccc1503SLorenzo Bianconi int i; 447290a6ce1SLorenzo Bianconi 448290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 4496ffb55e5SLorenzo Bianconi /* 4506ffb55e5SLorenzo Bianconi * ext devices can run at different odr respect to 4516ffb55e5SLorenzo Bianconi * accel sensor 4526ffb55e5SLorenzo Bianconi */ 4536ffb55e5SLorenzo Bianconi if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr) 454290a6ce1SLorenzo Bianconi break; 455290a6ce1SLorenzo Bianconi 456290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_ODR_LIST_SIZE) 457290a6ce1SLorenzo Bianconi return -EINVAL; 458290a6ce1SLorenzo Bianconi 4592ccc1503SLorenzo Bianconi *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; 460290a6ce1SLorenzo Bianconi 461290a6ce1SLorenzo Bianconi return 0; 462290a6ce1SLorenzo Bianconi } 463290a6ce1SLorenzo Bianconi 4646ffb55e5SLorenzo Bianconi static u16 st_lsm6dsx_check_odr_dependency(struct st_lsm6dsx_hw *hw, u16 odr, 4656ffb55e5SLorenzo Bianconi enum st_lsm6dsx_sensor_id id) 4662ccc1503SLorenzo Bianconi { 4676ffb55e5SLorenzo Bianconi struct st_lsm6dsx_sensor *ref = iio_priv(hw->iio_devs[id]); 4686ffb55e5SLorenzo Bianconi 4696ffb55e5SLorenzo Bianconi if (odr > 0) { 4706ffb55e5SLorenzo Bianconi if (hw->enable_mask & BIT(id)) 4716ffb55e5SLorenzo Bianconi return max_t(u16, ref->odr, odr); 4726ffb55e5SLorenzo Bianconi else 4736ffb55e5SLorenzo Bianconi return odr; 4746ffb55e5SLorenzo Bianconi } else { 4756ffb55e5SLorenzo Bianconi return (hw->enable_mask & BIT(id)) ? ref->odr : 0; 4766ffb55e5SLorenzo Bianconi } 4776ffb55e5SLorenzo Bianconi } 4786ffb55e5SLorenzo Bianconi 4796ffb55e5SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr) 4806ffb55e5SLorenzo Bianconi { 4816ffb55e5SLorenzo Bianconi struct st_lsm6dsx_sensor *ref_sensor = sensor; 48251a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 48351a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 484739aff87SLorenzo Bianconi unsigned int data; 4856ffb55e5SLorenzo Bianconi u8 val = 0; 4862ccc1503SLorenzo Bianconi int err; 4872ccc1503SLorenzo Bianconi 4886ffb55e5SLorenzo Bianconi switch (sensor->id) { 4896ffb55e5SLorenzo Bianconi case ST_LSM6DSX_ID_EXT0: 4906ffb55e5SLorenzo Bianconi case ST_LSM6DSX_ID_EXT1: 4916ffb55e5SLorenzo Bianconi case ST_LSM6DSX_ID_EXT2: 4926ffb55e5SLorenzo Bianconi case ST_LSM6DSX_ID_ACC: { 4936ffb55e5SLorenzo Bianconi u16 odr; 4946ffb55e5SLorenzo Bianconi int i; 4956ffb55e5SLorenzo Bianconi 4966ffb55e5SLorenzo Bianconi /* 4976ffb55e5SLorenzo Bianconi * i2c embedded controller relies on the accelerometer sensor as 4986ffb55e5SLorenzo Bianconi * bus read/write trigger so we need to enable accel device 4996ffb55e5SLorenzo Bianconi * at odr = max(accel_odr, ext_odr) in order to properly 5006ffb55e5SLorenzo Bianconi * communicate with i2c slave devices 5016ffb55e5SLorenzo Bianconi */ 5026ffb55e5SLorenzo Bianconi ref_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]); 5036ffb55e5SLorenzo Bianconi for (i = ST_LSM6DSX_ID_ACC; i < ST_LSM6DSX_ID_MAX; i++) { 5046ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i] || i == sensor->id) 5056ffb55e5SLorenzo Bianconi continue; 5066ffb55e5SLorenzo Bianconi 5076ffb55e5SLorenzo Bianconi odr = st_lsm6dsx_check_odr_dependency(hw, req_odr, i); 5086ffb55e5SLorenzo Bianconi if (odr != req_odr) 5096ffb55e5SLorenzo Bianconi /* device already configured */ 5106ffb55e5SLorenzo Bianconi return 0; 5116ffb55e5SLorenzo Bianconi } 5126ffb55e5SLorenzo Bianconi break; 5136ffb55e5SLorenzo Bianconi } 5146ffb55e5SLorenzo Bianconi default: 5156ffb55e5SLorenzo Bianconi break; 5166ffb55e5SLorenzo Bianconi } 5176ffb55e5SLorenzo Bianconi 5186ffb55e5SLorenzo Bianconi if (req_odr > 0) { 5196ffb55e5SLorenzo Bianconi err = st_lsm6dsx_check_odr(ref_sensor, req_odr, &val); 5202ccc1503SLorenzo Bianconi if (err < 0) 5212ccc1503SLorenzo Bianconi return err; 5226ffb55e5SLorenzo Bianconi } 5232ccc1503SLorenzo Bianconi 5246ffb55e5SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg; 525739aff87SLorenzo Bianconi data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); 526739aff87SLorenzo Bianconi return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data); 5272ccc1503SLorenzo Bianconi } 5282ccc1503SLorenzo Bianconi 52917750443SLorenzo Bianconi int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor, 53017750443SLorenzo Bianconi bool enable) 531290a6ce1SLorenzo Bianconi { 53251a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 53317750443SLorenzo Bianconi u16 odr = enable ? sensor->odr : 0; 534290a6ce1SLorenzo Bianconi int err; 535290a6ce1SLorenzo Bianconi 53617750443SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, odr); 537290a6ce1SLorenzo Bianconi if (err < 0) 538290a6ce1SLorenzo Bianconi return err; 539290a6ce1SLorenzo Bianconi 54017750443SLorenzo Bianconi if (enable) 54117750443SLorenzo Bianconi hw->enable_mask |= BIT(sensor->id); 54217750443SLorenzo Bianconi else 54317750443SLorenzo Bianconi hw->enable_mask &= ~BIT(sensor->id); 544290a6ce1SLorenzo Bianconi 545290a6ce1SLorenzo Bianconi return 0; 546290a6ce1SLorenzo Bianconi } 547290a6ce1SLorenzo Bianconi 548290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, 549290a6ce1SLorenzo Bianconi u8 addr, int *val) 550290a6ce1SLorenzo Bianconi { 55151a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 552290a6ce1SLorenzo Bianconi int err, delay; 553290a6ce1SLorenzo Bianconi __le16 data; 554290a6ce1SLorenzo Bianconi 55517750443SLorenzo Bianconi err = st_lsm6dsx_sensor_set_enable(sensor, true); 556290a6ce1SLorenzo Bianconi if (err < 0) 557290a6ce1SLorenzo Bianconi return err; 558290a6ce1SLorenzo Bianconi 559290a6ce1SLorenzo Bianconi delay = 1000000 / sensor->odr; 560290a6ce1SLorenzo Bianconi usleep_range(delay, 2 * delay); 561290a6ce1SLorenzo Bianconi 562739aff87SLorenzo Bianconi err = st_lsm6dsx_read_locked(hw, addr, &data, sizeof(data)); 563290a6ce1SLorenzo Bianconi if (err < 0) 564290a6ce1SLorenzo Bianconi return err; 565290a6ce1SLorenzo Bianconi 56617750443SLorenzo Bianconi st_lsm6dsx_sensor_set_enable(sensor, false); 567290a6ce1SLorenzo Bianconi 5687b9ebe42SLorenzo Bianconi *val = (s16)le16_to_cpu(data); 569290a6ce1SLorenzo Bianconi 570290a6ce1SLorenzo Bianconi return IIO_VAL_INT; 571290a6ce1SLorenzo Bianconi } 572290a6ce1SLorenzo Bianconi 573290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, 574290a6ce1SLorenzo Bianconi struct iio_chan_spec const *ch, 575290a6ce1SLorenzo Bianconi int *val, int *val2, long mask) 576290a6ce1SLorenzo Bianconi { 577290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 578290a6ce1SLorenzo Bianconi int ret; 579290a6ce1SLorenzo Bianconi 580290a6ce1SLorenzo Bianconi switch (mask) { 581290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_RAW: 582290a6ce1SLorenzo Bianconi ret = iio_device_claim_direct_mode(iio_dev); 583290a6ce1SLorenzo Bianconi if (ret) 584290a6ce1SLorenzo Bianconi break; 585290a6ce1SLorenzo Bianconi 586290a6ce1SLorenzo Bianconi ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val); 587290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 588290a6ce1SLorenzo Bianconi break; 589290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: 590290a6ce1SLorenzo Bianconi *val = sensor->odr; 591290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT; 592290a6ce1SLorenzo Bianconi break; 593290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 594290a6ce1SLorenzo Bianconi *val = 0; 595290a6ce1SLorenzo Bianconi *val2 = sensor->gain; 596290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT_PLUS_MICRO; 597290a6ce1SLorenzo Bianconi break; 598290a6ce1SLorenzo Bianconi default: 599290a6ce1SLorenzo Bianconi ret = -EINVAL; 600290a6ce1SLorenzo Bianconi break; 601290a6ce1SLorenzo Bianconi } 602290a6ce1SLorenzo Bianconi 603290a6ce1SLorenzo Bianconi return ret; 604290a6ce1SLorenzo Bianconi } 605290a6ce1SLorenzo Bianconi 606290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, 607290a6ce1SLorenzo Bianconi struct iio_chan_spec const *chan, 608290a6ce1SLorenzo Bianconi int val, int val2, long mask) 609290a6ce1SLorenzo Bianconi { 610290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 611290a6ce1SLorenzo Bianconi int err; 612290a6ce1SLorenzo Bianconi 613290a6ce1SLorenzo Bianconi err = iio_device_claim_direct_mode(iio_dev); 614290a6ce1SLorenzo Bianconi if (err) 615290a6ce1SLorenzo Bianconi return err; 616290a6ce1SLorenzo Bianconi 617290a6ce1SLorenzo Bianconi switch (mask) { 618290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 619290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_full_scale(sensor, val2); 620290a6ce1SLorenzo Bianconi break; 6212ccc1503SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: { 6222ccc1503SLorenzo Bianconi u8 data; 6232ccc1503SLorenzo Bianconi 6242ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, val, &data); 6255e3c3e33SLorenzo Bianconi if (!err) 6265e3c3e33SLorenzo Bianconi sensor->odr = val; 627290a6ce1SLorenzo Bianconi break; 6282ccc1503SLorenzo Bianconi } 629290a6ce1SLorenzo Bianconi default: 630290a6ce1SLorenzo Bianconi err = -EINVAL; 631290a6ce1SLorenzo Bianconi break; 632290a6ce1SLorenzo Bianconi } 633290a6ce1SLorenzo Bianconi 634290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 635290a6ce1SLorenzo Bianconi 636290a6ce1SLorenzo Bianconi return err; 637290a6ce1SLorenzo Bianconi } 638290a6ce1SLorenzo Bianconi 639d40464f3SLorenzo Bianconi int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val) 640290a6ce1SLorenzo Bianconi { 641290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 642290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 6438f2a88a2SLorenzo Bianconi int err; 644290a6ce1SLorenzo Bianconi 6458f2a88a2SLorenzo Bianconi if (val < 1 || val > hw->settings->max_fifo_size) 646290a6ce1SLorenzo Bianconi return -EINVAL; 647290a6ce1SLorenzo Bianconi 648335eaedcSLorenzo Bianconi mutex_lock(&hw->conf_lock); 649335eaedcSLorenzo Bianconi 650290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_watermark(sensor, val); 651335eaedcSLorenzo Bianconi 652335eaedcSLorenzo Bianconi mutex_unlock(&hw->conf_lock); 653335eaedcSLorenzo Bianconi 654290a6ce1SLorenzo Bianconi if (err < 0) 655290a6ce1SLorenzo Bianconi return err; 656290a6ce1SLorenzo Bianconi 657290a6ce1SLorenzo Bianconi sensor->watermark = val; 658290a6ce1SLorenzo Bianconi 659290a6ce1SLorenzo Bianconi return 0; 660290a6ce1SLorenzo Bianconi } 661290a6ce1SLorenzo Bianconi 662290a6ce1SLorenzo Bianconi static ssize_t 663290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, 664290a6ce1SLorenzo Bianconi struct device_attribute *attr, 665290a6ce1SLorenzo Bianconi char *buf) 666290a6ce1SLorenzo Bianconi { 667290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 668290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 669290a6ce1SLorenzo Bianconi int i, len = 0; 670290a6ce1SLorenzo Bianconi 671290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 672290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", 673290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].odr_avl[i].hz); 674290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 675290a6ce1SLorenzo Bianconi 676290a6ce1SLorenzo Bianconi return len; 677290a6ce1SLorenzo Bianconi } 678290a6ce1SLorenzo Bianconi 679290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, 680290a6ce1SLorenzo Bianconi struct device_attribute *attr, 681290a6ce1SLorenzo Bianconi char *buf) 682290a6ce1SLorenzo Bianconi { 683290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 684290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 685290a6ce1SLorenzo Bianconi int i, len = 0; 686290a6ce1SLorenzo Bianconi 687290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 688290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", 689290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].fs_avl[i].gain); 690290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 691290a6ce1SLorenzo Bianconi 692290a6ce1SLorenzo Bianconi return len; 693290a6ce1SLorenzo Bianconi } 694290a6ce1SLorenzo Bianconi 695290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail); 696290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 697290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 698290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444, 699290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 700290a6ce1SLorenzo Bianconi 701290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = { 702290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 703290a6ce1SLorenzo Bianconi &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 704290a6ce1SLorenzo Bianconi NULL, 705290a6ce1SLorenzo Bianconi }; 706290a6ce1SLorenzo Bianconi 707290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = { 708290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_acc_attributes, 709290a6ce1SLorenzo Bianconi }; 710290a6ce1SLorenzo Bianconi 711290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = { 712290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_acc_attribute_group, 713290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 714290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 715290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 716290a6ce1SLorenzo Bianconi }; 717290a6ce1SLorenzo Bianconi 718290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = { 719290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 720290a6ce1SLorenzo Bianconi &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, 721290a6ce1SLorenzo Bianconi NULL, 722290a6ce1SLorenzo Bianconi }; 723290a6ce1SLorenzo Bianconi 724290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = { 725290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_gyro_attributes, 726290a6ce1SLorenzo Bianconi }; 727290a6ce1SLorenzo Bianconi 728290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = { 729290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_gyro_attribute_group, 730290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 731290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 732290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 733290a6ce1SLorenzo Bianconi }; 734290a6ce1SLorenzo Bianconi 735dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) 736dba32904SLorenzo Bianconi { 737dba32904SLorenzo Bianconi struct device_node *np = hw->dev->of_node; 738dba32904SLorenzo Bianconi 739dba32904SLorenzo Bianconi if (!np) 740dba32904SLorenzo Bianconi return -EINVAL; 741dba32904SLorenzo Bianconi 742bf235277SLorenzo Bianconi return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); 743dba32904SLorenzo Bianconi } 744dba32904SLorenzo Bianconi 745dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) 746dba32904SLorenzo Bianconi { 747dba32904SLorenzo Bianconi int err = 0, drdy_pin; 748dba32904SLorenzo Bianconi 749dba32904SLorenzo Bianconi if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) { 750dba32904SLorenzo Bianconi struct st_sensors_platform_data *pdata; 751dba32904SLorenzo Bianconi struct device *dev = hw->dev; 752dba32904SLorenzo Bianconi 753dba32904SLorenzo Bianconi pdata = (struct st_sensors_platform_data *)dev->platform_data; 754dba32904SLorenzo Bianconi drdy_pin = pdata ? pdata->drdy_int_pin : 1; 755dba32904SLorenzo Bianconi } 756dba32904SLorenzo Bianconi 757dba32904SLorenzo Bianconi switch (drdy_pin) { 758dba32904SLorenzo Bianconi case 1: 759dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; 760dba32904SLorenzo Bianconi break; 761dba32904SLorenzo Bianconi case 2: 762dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; 763dba32904SLorenzo Bianconi break; 764dba32904SLorenzo Bianconi default: 765dba32904SLorenzo Bianconi dev_err(hw->dev, "unsupported data ready pin\n"); 766dba32904SLorenzo Bianconi err = -EINVAL; 767dba32904SLorenzo Bianconi break; 768dba32904SLorenzo Bianconi } 769dba32904SLorenzo Bianconi 770dba32904SLorenzo Bianconi return err; 771dba32904SLorenzo Bianconi } 772dba32904SLorenzo Bianconi 773c91c1c84SLorenzo Bianconi static int st_lsm6dsx_init_shub(struct st_lsm6dsx_hw *hw) 774c91c1c84SLorenzo Bianconi { 775c91c1c84SLorenzo Bianconi const struct st_lsm6dsx_shub_settings *hub_settings; 776c91c1c84SLorenzo Bianconi struct device_node *np = hw->dev->of_node; 777c91c1c84SLorenzo Bianconi struct st_sensors_platform_data *pdata; 778c91c1c84SLorenzo Bianconi unsigned int data; 779c91c1c84SLorenzo Bianconi int err = 0; 780c91c1c84SLorenzo Bianconi 781c91c1c84SLorenzo Bianconi hub_settings = &hw->settings->shub_settings; 782c91c1c84SLorenzo Bianconi 783c91c1c84SLorenzo Bianconi pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; 784c91c1c84SLorenzo Bianconi if ((np && of_property_read_bool(np, "st,pullups")) || 785c91c1c84SLorenzo Bianconi (pdata && pdata->pullups)) { 786c91c1c84SLorenzo Bianconi err = st_lsm6dsx_set_page(hw, true); 787c91c1c84SLorenzo Bianconi if (err < 0) 788c91c1c84SLorenzo Bianconi return err; 789c91c1c84SLorenzo Bianconi 790c91c1c84SLorenzo Bianconi data = ST_LSM6DSX_SHIFT_VAL(1, hub_settings->pullup_en.mask); 791c91c1c84SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 792c91c1c84SLorenzo Bianconi hub_settings->pullup_en.addr, 793c91c1c84SLorenzo Bianconi hub_settings->pullup_en.mask, data); 794c91c1c84SLorenzo Bianconi 795c91c1c84SLorenzo Bianconi st_lsm6dsx_set_page(hw, false); 796c91c1c84SLorenzo Bianconi 797c91c1c84SLorenzo Bianconi if (err < 0) 798c91c1c84SLorenzo Bianconi return err; 799c91c1c84SLorenzo Bianconi } 800c91c1c84SLorenzo Bianconi 801c91c1c84SLorenzo Bianconi if (hub_settings->aux_sens.addr) { 802c91c1c84SLorenzo Bianconi /* configure aux sensors */ 803c91c1c84SLorenzo Bianconi err = st_lsm6dsx_set_page(hw, true); 804c91c1c84SLorenzo Bianconi if (err < 0) 805c91c1c84SLorenzo Bianconi return err; 806c91c1c84SLorenzo Bianconi 807c91c1c84SLorenzo Bianconi data = ST_LSM6DSX_SHIFT_VAL(3, hub_settings->aux_sens.mask); 808c91c1c84SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 809c91c1c84SLorenzo Bianconi hub_settings->aux_sens.addr, 810c91c1c84SLorenzo Bianconi hub_settings->aux_sens.mask, data); 811c91c1c84SLorenzo Bianconi 812c91c1c84SLorenzo Bianconi st_lsm6dsx_set_page(hw, false); 813c91c1c84SLorenzo Bianconi } 814c91c1c84SLorenzo Bianconi 815c91c1c84SLorenzo Bianconi return err; 816c91c1c84SLorenzo Bianconi } 817c91c1c84SLorenzo Bianconi 81821345107SLorenzo Bianconi static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) 81921345107SLorenzo Bianconi { 82021345107SLorenzo Bianconi const struct st_lsm6dsx_hw_ts_settings *ts_settings; 82121345107SLorenzo Bianconi int err, val; 82221345107SLorenzo Bianconi 82321345107SLorenzo Bianconi ts_settings = &hw->settings->ts_settings; 82421345107SLorenzo Bianconi /* enable hw timestamp generation if necessary */ 82521345107SLorenzo Bianconi if (ts_settings->timer_en.addr) { 82621345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask); 82721345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 82821345107SLorenzo Bianconi ts_settings->timer_en.addr, 82921345107SLorenzo Bianconi ts_settings->timer_en.mask, val); 83021345107SLorenzo Bianconi if (err < 0) 83121345107SLorenzo Bianconi return err; 83221345107SLorenzo Bianconi } 83321345107SLorenzo Bianconi 83421345107SLorenzo Bianconi /* enable high resolution for hw ts timer if necessary */ 83521345107SLorenzo Bianconi if (ts_settings->hr_timer.addr) { 83621345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask); 83721345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 83821345107SLorenzo Bianconi ts_settings->hr_timer.addr, 83921345107SLorenzo Bianconi ts_settings->hr_timer.mask, val); 84021345107SLorenzo Bianconi if (err < 0) 84121345107SLorenzo Bianconi return err; 84221345107SLorenzo Bianconi } 84321345107SLorenzo Bianconi 84421345107SLorenzo Bianconi /* enable ts queueing in FIFO if necessary */ 84521345107SLorenzo Bianconi if (ts_settings->fifo_en.addr) { 84621345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask); 84721345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 84821345107SLorenzo Bianconi ts_settings->fifo_en.addr, 84921345107SLorenzo Bianconi ts_settings->fifo_en.mask, val); 85021345107SLorenzo Bianconi if (err < 0) 85121345107SLorenzo Bianconi return err; 85221345107SLorenzo Bianconi } 85321345107SLorenzo Bianconi return 0; 85421345107SLorenzo Bianconi } 85521345107SLorenzo Bianconi 856290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) 857290a6ce1SLorenzo Bianconi { 85851a8b707SLorenzo Bianconi u8 drdy_int_reg; 859290a6ce1SLorenzo Bianconi int err; 860290a6ce1SLorenzo Bianconi 86119435425SLorenzo Bianconi /* device sw reset */ 86219435425SLorenzo Bianconi err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, 86319435425SLorenzo Bianconi ST_LSM6DSX_REG_RESET_MASK, 86419435425SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1)); 865290a6ce1SLorenzo Bianconi if (err < 0) 866290a6ce1SLorenzo Bianconi return err; 867290a6ce1SLorenzo Bianconi 86819435425SLorenzo Bianconi msleep(50); 86919435425SLorenzo Bianconi 87019435425SLorenzo Bianconi /* reload trimming parameter */ 87119435425SLorenzo Bianconi err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, 87219435425SLorenzo Bianconi ST_LSM6DSX_REG_BOOT_MASK, 87319435425SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1)); 87419435425SLorenzo Bianconi if (err < 0) 87519435425SLorenzo Bianconi return err; 87619435425SLorenzo Bianconi 87719435425SLorenzo Bianconi msleep(50); 878290a6ce1SLorenzo Bianconi 879290a6ce1SLorenzo Bianconi /* enable Block Data Update */ 88051a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR, 88151a8b707SLorenzo Bianconi ST_LSM6DSX_REG_BDU_MASK, 88251a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1)); 883290a6ce1SLorenzo Bianconi if (err < 0) 884290a6ce1SLorenzo Bianconi return err; 885290a6ce1SLorenzo Bianconi 886290a6ce1SLorenzo Bianconi /* enable FIFO watermak interrupt */ 887dba32904SLorenzo Bianconi err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); 888290a6ce1SLorenzo Bianconi if (err < 0) 889290a6ce1SLorenzo Bianconi return err; 890290a6ce1SLorenzo Bianconi 89121345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, drdy_int_reg, 89251a8b707SLorenzo Bianconi ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 89351a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 89451a8b707SLorenzo Bianconi 1)); 89521345107SLorenzo Bianconi if (err < 0) 89621345107SLorenzo Bianconi return err; 89721345107SLorenzo Bianconi 898c91c1c84SLorenzo Bianconi err = st_lsm6dsx_init_shub(hw); 899c91c1c84SLorenzo Bianconi if (err < 0) 900c91c1c84SLorenzo Bianconi return err; 901c91c1c84SLorenzo Bianconi 90221345107SLorenzo Bianconi return st_lsm6dsx_init_hw_timer(hw); 903290a6ce1SLorenzo Bianconi } 904290a6ce1SLorenzo Bianconi 905290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, 906510c0106SLorenzo Bianconi enum st_lsm6dsx_sensor_id id, 907510c0106SLorenzo Bianconi const char *name) 908290a6ce1SLorenzo Bianconi { 909290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 910290a6ce1SLorenzo Bianconi struct iio_dev *iio_dev; 911290a6ce1SLorenzo Bianconi 912290a6ce1SLorenzo Bianconi iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); 913290a6ce1SLorenzo Bianconi if (!iio_dev) 914290a6ce1SLorenzo Bianconi return NULL; 915290a6ce1SLorenzo Bianconi 916290a6ce1SLorenzo Bianconi iio_dev->modes = INDIO_DIRECT_MODE; 917290a6ce1SLorenzo Bianconi iio_dev->dev.parent = hw->dev; 918290a6ce1SLorenzo Bianconi iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; 919290a6ce1SLorenzo Bianconi 920290a6ce1SLorenzo Bianconi sensor = iio_priv(iio_dev); 921290a6ce1SLorenzo Bianconi sensor->id = id; 922290a6ce1SLorenzo Bianconi sensor->hw = hw; 923290a6ce1SLorenzo Bianconi sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; 924290a6ce1SLorenzo Bianconi sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; 925290a6ce1SLorenzo Bianconi sensor->watermark = 1; 926290a6ce1SLorenzo Bianconi 927290a6ce1SLorenzo Bianconi switch (id) { 928290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_ACC: 929290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_acc_channels; 930290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); 931290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_acc_info; 932290a6ce1SLorenzo Bianconi 933510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", 934510c0106SLorenzo Bianconi name); 935290a6ce1SLorenzo Bianconi break; 936290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_GYRO: 937290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_gyro_channels; 938290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); 939290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_gyro_info; 940290a6ce1SLorenzo Bianconi 941510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", 942510c0106SLorenzo Bianconi name); 943290a6ce1SLorenzo Bianconi break; 944290a6ce1SLorenzo Bianconi default: 945290a6ce1SLorenzo Bianconi return NULL; 946290a6ce1SLorenzo Bianconi } 947510c0106SLorenzo Bianconi iio_dev->name = sensor->name; 948290a6ce1SLorenzo Bianconi 949290a6ce1SLorenzo Bianconi return iio_dev; 950290a6ce1SLorenzo Bianconi } 951290a6ce1SLorenzo Bianconi 952510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, 95351a8b707SLorenzo Bianconi struct regmap *regmap) 954290a6ce1SLorenzo Bianconi { 955c91c1c84SLorenzo Bianconi const struct st_lsm6dsx_shub_settings *hub_settings; 956290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw; 957290a6ce1SLorenzo Bianconi int i, err; 958290a6ce1SLorenzo Bianconi 959290a6ce1SLorenzo Bianconi hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 960290a6ce1SLorenzo Bianconi if (!hw) 961290a6ce1SLorenzo Bianconi return -ENOMEM; 962290a6ce1SLorenzo Bianconi 963290a6ce1SLorenzo Bianconi dev_set_drvdata(dev, (void *)hw); 964290a6ce1SLorenzo Bianconi 965290a6ce1SLorenzo Bianconi mutex_init(&hw->fifo_lock); 966335eaedcSLorenzo Bianconi mutex_init(&hw->conf_lock); 967739aff87SLorenzo Bianconi mutex_init(&hw->page_lock); 968290a6ce1SLorenzo Bianconi 96991a6b841SLorenzo Bianconi hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL); 97091a6b841SLorenzo Bianconi if (!hw->buff) 97191a6b841SLorenzo Bianconi return -ENOMEM; 97291a6b841SLorenzo Bianconi 973290a6ce1SLorenzo Bianconi hw->dev = dev; 974290a6ce1SLorenzo Bianconi hw->irq = irq; 97551a8b707SLorenzo Bianconi hw->regmap = regmap; 976290a6ce1SLorenzo Bianconi 977290a6ce1SLorenzo Bianconi err = st_lsm6dsx_check_whoami(hw, hw_id); 978290a6ce1SLorenzo Bianconi if (err < 0) 979290a6ce1SLorenzo Bianconi return err; 980290a6ce1SLorenzo Bianconi 9816ffb55e5SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) { 982510c0106SLorenzo Bianconi hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name); 983290a6ce1SLorenzo Bianconi if (!hw->iio_devs[i]) 984290a6ce1SLorenzo Bianconi return -ENOMEM; 985290a6ce1SLorenzo Bianconi } 986290a6ce1SLorenzo Bianconi 987290a6ce1SLorenzo Bianconi err = st_lsm6dsx_init_device(hw); 988290a6ce1SLorenzo Bianconi if (err < 0) 989290a6ce1SLorenzo Bianconi return err; 990290a6ce1SLorenzo Bianconi 991c91c1c84SLorenzo Bianconi hub_settings = &hw->settings->shub_settings; 992c91c1c84SLorenzo Bianconi if (hub_settings->master_en.addr) { 993c91c1c84SLorenzo Bianconi err = st_lsm6dsx_shub_probe(hw, name); 994c91c1c84SLorenzo Bianconi if (err < 0) 995c91c1c84SLorenzo Bianconi return err; 996c91c1c84SLorenzo Bianconi } 997c91c1c84SLorenzo Bianconi 998290a6ce1SLorenzo Bianconi if (hw->irq > 0) { 999290a6ce1SLorenzo Bianconi err = st_lsm6dsx_fifo_setup(hw); 1000290a6ce1SLorenzo Bianconi if (err < 0) 1001290a6ce1SLorenzo Bianconi return err; 1002290a6ce1SLorenzo Bianconi } 1003290a6ce1SLorenzo Bianconi 1004290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 10056ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i]) 10066ffb55e5SLorenzo Bianconi continue; 10076ffb55e5SLorenzo Bianconi 1008290a6ce1SLorenzo Bianconi err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); 1009290a6ce1SLorenzo Bianconi if (err) 1010290a6ce1SLorenzo Bianconi return err; 1011290a6ce1SLorenzo Bianconi } 1012290a6ce1SLorenzo Bianconi 1013290a6ce1SLorenzo Bianconi return 0; 1014290a6ce1SLorenzo Bianconi } 1015290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe); 1016290a6ce1SLorenzo Bianconi 10173cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) 1018d3f77058SLorenzo Bianconi { 1019d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 1020d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 102151a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 1022739aff87SLorenzo Bianconi unsigned int data; 1023d3f77058SLorenzo Bianconi int i, err = 0; 1024d3f77058SLorenzo Bianconi 1025d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 10266ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i]) 10276ffb55e5SLorenzo Bianconi continue; 10286ffb55e5SLorenzo Bianconi 1029d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 1030d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 1031d3f77058SLorenzo Bianconi continue; 1032d3f77058SLorenzo Bianconi 103351a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 1034739aff87SLorenzo Bianconi data = ST_LSM6DSX_SHIFT_VAL(0, reg->mask); 1035739aff87SLorenzo Bianconi err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, 1036739aff87SLorenzo Bianconi data); 1037d3f77058SLorenzo Bianconi if (err < 0) 1038d3f77058SLorenzo Bianconi return err; 1039d3f77058SLorenzo Bianconi } 1040d3f77058SLorenzo Bianconi 1041d3f77058SLorenzo Bianconi if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) 1042d3f77058SLorenzo Bianconi err = st_lsm6dsx_flush_fifo(hw); 1043d3f77058SLorenzo Bianconi 1044d3f77058SLorenzo Bianconi return err; 1045d3f77058SLorenzo Bianconi } 1046d3f77058SLorenzo Bianconi 10473cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev) 1048d3f77058SLorenzo Bianconi { 1049d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 1050d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 1051d3f77058SLorenzo Bianconi int i, err = 0; 1052d3f77058SLorenzo Bianconi 1053d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 10546ffb55e5SLorenzo Bianconi if (!hw->iio_devs[i]) 10556ffb55e5SLorenzo Bianconi continue; 10566ffb55e5SLorenzo Bianconi 1057d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 1058d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 1059d3f77058SLorenzo Bianconi continue; 1060d3f77058SLorenzo Bianconi 1061d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 1062d3f77058SLorenzo Bianconi if (err < 0) 1063d3f77058SLorenzo Bianconi return err; 1064d3f77058SLorenzo Bianconi } 1065d3f77058SLorenzo Bianconi 1066d3f77058SLorenzo Bianconi if (hw->enable_mask) 1067d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); 1068d3f77058SLorenzo Bianconi 1069d3f77058SLorenzo Bianconi return err; 1070d3f77058SLorenzo Bianconi } 1071d3f77058SLorenzo Bianconi 1072d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = { 1073d3f77058SLorenzo Bianconi SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume) 1074d3f77058SLorenzo Bianconi }; 1075d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops); 1076d3f77058SLorenzo Bianconi 1077290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); 1078290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); 1079290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); 1080290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2"); 1081