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