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 * 26290a6ce1SLorenzo Bianconi * Copyright 2016 STMicroelectronics Inc. 27290a6ce1SLorenzo Bianconi * 28290a6ce1SLorenzo Bianconi * Lorenzo Bianconi <lorenzo.bianconi@st.com> 29290a6ce1SLorenzo Bianconi * Denis Ciocca <denis.ciocca@st.com> 30290a6ce1SLorenzo Bianconi * 31290a6ce1SLorenzo Bianconi * Licensed under the GPL-2. 32290a6ce1SLorenzo Bianconi */ 33290a6ce1SLorenzo Bianconi 34290a6ce1SLorenzo Bianconi #include <linux/kernel.h> 35290a6ce1SLorenzo Bianconi #include <linux/module.h> 36290a6ce1SLorenzo Bianconi #include <linux/delay.h> 37290a6ce1SLorenzo Bianconi #include <linux/iio/iio.h> 38290a6ce1SLorenzo Bianconi #include <linux/iio/sysfs.h> 39d3f77058SLorenzo Bianconi #include <linux/pm.h> 4051a8b707SLorenzo Bianconi #include <linux/regmap.h> 4151a8b707SLorenzo Bianconi #include <linux/bitfield.h> 42290a6ce1SLorenzo Bianconi 43dba32904SLorenzo Bianconi #include <linux/platform_data/st_sensors_pdata.h> 44dba32904SLorenzo Bianconi 45290a6ce1SLorenzo Bianconi #include "st_lsm6dsx.h" 46290a6ce1SLorenzo Bianconi 47290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT1_ADDR 0x0d 48dba32904SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ADDR 0x0e 49290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3) 50290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f 51290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_ADDR 0x12 52290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_MASK BIT(0) 53290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_ADDR 0x12 54290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_MASK BIT(6) 55290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13 56290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5) 57290a6ce1SLorenzo Bianconi 58290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_ADDR 0x10 59290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_MASK GENMASK(7, 4) 60290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_ADDR 0x10 61290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_MASK GENMASK(3, 2) 62290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28 63290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a 64290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c 65290a6ce1SLorenzo Bianconi 66290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_ADDR 0x11 67290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_MASK GENMASK(7, 4) 68290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_ADDR 0x11 69290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_MASK GENMASK(3, 2) 70290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22 71290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 72290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 73290a6ce1SLorenzo Bianconi 74290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61) 75290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122) 76290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244) 77290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488) 78290a6ce1SLorenzo Bianconi 79dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_245_GAIN IIO_DEGREE_TO_RAD(8750) 80dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(17500) 81dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(35000) 82290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000) 83290a6ce1SLorenzo Bianconi 84290a6ce1SLorenzo Bianconi struct st_lsm6dsx_odr { 85290a6ce1SLorenzo Bianconi u16 hz; 86290a6ce1SLorenzo Bianconi u8 val; 87290a6ce1SLorenzo Bianconi }; 88290a6ce1SLorenzo Bianconi 89290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ODR_LIST_SIZE 6 90290a6ce1SLorenzo Bianconi struct st_lsm6dsx_odr_table_entry { 91290a6ce1SLorenzo Bianconi struct st_lsm6dsx_reg reg; 92290a6ce1SLorenzo Bianconi struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE]; 93290a6ce1SLorenzo Bianconi }; 94290a6ce1SLorenzo Bianconi 95290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { 96290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 97290a6ce1SLorenzo Bianconi .reg = { 98290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_ACC_ODR_ADDR, 99290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_ACC_ODR_MASK, 100290a6ce1SLorenzo Bianconi }, 101290a6ce1SLorenzo Bianconi .odr_avl[0] = { 13, 0x01 }, 102290a6ce1SLorenzo Bianconi .odr_avl[1] = { 26, 0x02 }, 103290a6ce1SLorenzo Bianconi .odr_avl[2] = { 52, 0x03 }, 104290a6ce1SLorenzo Bianconi .odr_avl[3] = { 104, 0x04 }, 105290a6ce1SLorenzo Bianconi .odr_avl[4] = { 208, 0x05 }, 106290a6ce1SLorenzo Bianconi .odr_avl[5] = { 416, 0x06 }, 107290a6ce1SLorenzo Bianconi }, 108290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 109290a6ce1SLorenzo Bianconi .reg = { 110290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR, 111290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_GYRO_ODR_MASK, 112290a6ce1SLorenzo Bianconi }, 113290a6ce1SLorenzo Bianconi .odr_avl[0] = { 13, 0x01 }, 114290a6ce1SLorenzo Bianconi .odr_avl[1] = { 26, 0x02 }, 115290a6ce1SLorenzo Bianconi .odr_avl[2] = { 52, 0x03 }, 116290a6ce1SLorenzo Bianconi .odr_avl[3] = { 104, 0x04 }, 117290a6ce1SLorenzo Bianconi .odr_avl[4] = { 208, 0x05 }, 118290a6ce1SLorenzo Bianconi .odr_avl[5] = { 416, 0x06 }, 119290a6ce1SLorenzo Bianconi } 120290a6ce1SLorenzo Bianconi }; 121290a6ce1SLorenzo Bianconi 122290a6ce1SLorenzo Bianconi struct st_lsm6dsx_fs { 123290a6ce1SLorenzo Bianconi u32 gain; 124290a6ce1SLorenzo Bianconi u8 val; 125290a6ce1SLorenzo Bianconi }; 126290a6ce1SLorenzo Bianconi 127290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_FS_LIST_SIZE 4 128290a6ce1SLorenzo Bianconi struct st_lsm6dsx_fs_table_entry { 129290a6ce1SLorenzo Bianconi struct st_lsm6dsx_reg reg; 130290a6ce1SLorenzo Bianconi struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE]; 131290a6ce1SLorenzo Bianconi }; 132290a6ce1SLorenzo Bianconi 133290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { 134290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 135290a6ce1SLorenzo Bianconi .reg = { 136290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_ACC_FS_ADDR, 137290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_ACC_FS_MASK, 138290a6ce1SLorenzo Bianconi }, 139290a6ce1SLorenzo Bianconi .fs_avl[0] = { ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 }, 140290a6ce1SLorenzo Bianconi .fs_avl[1] = { ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 }, 141290a6ce1SLorenzo Bianconi .fs_avl[2] = { ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 }, 142290a6ce1SLorenzo Bianconi .fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 }, 143290a6ce1SLorenzo Bianconi }, 144290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 145290a6ce1SLorenzo Bianconi .reg = { 146290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_GYRO_FS_ADDR, 147290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_GYRO_FS_MASK, 148290a6ce1SLorenzo Bianconi }, 149290a6ce1SLorenzo Bianconi .fs_avl[0] = { ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 }, 150290a6ce1SLorenzo Bianconi .fs_avl[1] = { ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 }, 151290a6ce1SLorenzo Bianconi .fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 }, 152290a6ce1SLorenzo Bianconi .fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 }, 153290a6ce1SLorenzo Bianconi } 154290a6ce1SLorenzo Bianconi }; 155290a6ce1SLorenzo Bianconi 156290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { 157290a6ce1SLorenzo Bianconi { 158d068e4a0SLorenzo Bianconi .wai = 0x69, 1598f2a88a2SLorenzo Bianconi .max_fifo_size = 1365, 160d068e4a0SLorenzo Bianconi .id = { 161d068e4a0SLorenzo Bianconi [0] = ST_LSM6DS3_ID, 162d068e4a0SLorenzo Bianconi }, 1637ca3ac9eSLorenzo Bianconi .decimator = { 1647ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 1657ca3ac9eSLorenzo Bianconi .addr = 0x08, 1667ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 1677ca3ac9eSLorenzo Bianconi }, 1687ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 1697ca3ac9eSLorenzo Bianconi .addr = 0x08, 1707ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 1717ca3ac9eSLorenzo Bianconi }, 1727ca3ac9eSLorenzo Bianconi }, 17392617c15SLorenzo Bianconi .fifo_ops = { 17450ff457dSLorenzo Bianconi .read_fifo = st_lsm6dsx_read_fifo, 17592617c15SLorenzo Bianconi .fifo_th = { 17692617c15SLorenzo Bianconi .addr = 0x06, 17792617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 17892617c15SLorenzo Bianconi }, 17992617c15SLorenzo Bianconi .fifo_diff = { 18092617c15SLorenzo Bianconi .addr = 0x3a, 18192617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 18292617c15SLorenzo Bianconi }, 18392617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 18492617c15SLorenzo Bianconi }, 18521345107SLorenzo Bianconi .ts_settings = { 18621345107SLorenzo Bianconi .timer_en = { 18721345107SLorenzo Bianconi .addr = 0x58, 18821345107SLorenzo Bianconi .mask = BIT(7), 18921345107SLorenzo Bianconi }, 19021345107SLorenzo Bianconi .hr_timer = { 19121345107SLorenzo Bianconi .addr = 0x5c, 19221345107SLorenzo Bianconi .mask = BIT(4), 19321345107SLorenzo Bianconi }, 19421345107SLorenzo Bianconi .fifo_en = { 19521345107SLorenzo Bianconi .addr = 0x07, 19621345107SLorenzo Bianconi .mask = BIT(7), 19721345107SLorenzo Bianconi }, 19821345107SLorenzo Bianconi .decimator = { 19921345107SLorenzo Bianconi .addr = 0x09, 20021345107SLorenzo Bianconi .mask = GENMASK(5, 3), 20121345107SLorenzo Bianconi }, 20221345107SLorenzo Bianconi }, 203290a6ce1SLorenzo Bianconi }, 204290a6ce1SLorenzo Bianconi { 205df47710aSLorenzo Bianconi .wai = 0x69, 2068f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 207df47710aSLorenzo Bianconi .id = { 208df47710aSLorenzo Bianconi [0] = ST_LSM6DS3H_ID, 209df47710aSLorenzo Bianconi }, 2107ca3ac9eSLorenzo Bianconi .decimator = { 2117ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 2127ca3ac9eSLorenzo Bianconi .addr = 0x08, 2137ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 2147ca3ac9eSLorenzo Bianconi }, 2157ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 2167ca3ac9eSLorenzo Bianconi .addr = 0x08, 2177ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 2187ca3ac9eSLorenzo Bianconi }, 2197ca3ac9eSLorenzo Bianconi }, 22092617c15SLorenzo Bianconi .fifo_ops = { 22150ff457dSLorenzo Bianconi .read_fifo = st_lsm6dsx_read_fifo, 22292617c15SLorenzo Bianconi .fifo_th = { 22392617c15SLorenzo Bianconi .addr = 0x06, 22492617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 22592617c15SLorenzo Bianconi }, 22692617c15SLorenzo Bianconi .fifo_diff = { 22792617c15SLorenzo Bianconi .addr = 0x3a, 22892617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 22992617c15SLorenzo Bianconi }, 23092617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 23192617c15SLorenzo Bianconi }, 23221345107SLorenzo Bianconi .ts_settings = { 23321345107SLorenzo Bianconi .timer_en = { 23421345107SLorenzo Bianconi .addr = 0x58, 23521345107SLorenzo Bianconi .mask = BIT(7), 23621345107SLorenzo Bianconi }, 23721345107SLorenzo Bianconi .hr_timer = { 23821345107SLorenzo Bianconi .addr = 0x5c, 23921345107SLorenzo Bianconi .mask = BIT(4), 24021345107SLorenzo Bianconi }, 24121345107SLorenzo Bianconi .fifo_en = { 24221345107SLorenzo Bianconi .addr = 0x07, 24321345107SLorenzo Bianconi .mask = BIT(7), 24421345107SLorenzo Bianconi }, 24521345107SLorenzo Bianconi .decimator = { 24621345107SLorenzo Bianconi .addr = 0x09, 24721345107SLorenzo Bianconi .mask = GENMASK(5, 3), 24821345107SLorenzo Bianconi }, 24921345107SLorenzo Bianconi }, 250df47710aSLorenzo Bianconi }, 251df47710aSLorenzo Bianconi { 252d068e4a0SLorenzo Bianconi .wai = 0x6a, 2538f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 254d068e4a0SLorenzo Bianconi .id = { 2550b2a3e5fSLorenzo Bianconi [0] = ST_LSM6DSL_ID, 2560b2a3e5fSLorenzo Bianconi [1] = ST_LSM6DSM_ID, 257179c8d60SLorenzo Bianconi [2] = ST_ISM330DLC_ID, 258d068e4a0SLorenzo Bianconi }, 2597ca3ac9eSLorenzo Bianconi .decimator = { 2607ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 2617ca3ac9eSLorenzo Bianconi .addr = 0x08, 2627ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 2637ca3ac9eSLorenzo Bianconi }, 2647ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 2657ca3ac9eSLorenzo Bianconi .addr = 0x08, 2667ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 2677ca3ac9eSLorenzo Bianconi }, 2687ca3ac9eSLorenzo Bianconi }, 26992617c15SLorenzo Bianconi .fifo_ops = { 27050ff457dSLorenzo Bianconi .read_fifo = st_lsm6dsx_read_fifo, 27192617c15SLorenzo Bianconi .fifo_th = { 27292617c15SLorenzo Bianconi .addr = 0x06, 273be75eb86SLorenzo Bianconi .mask = GENMASK(10, 0), 27492617c15SLorenzo Bianconi }, 27592617c15SLorenzo Bianconi .fifo_diff = { 27692617c15SLorenzo Bianconi .addr = 0x3a, 277be75eb86SLorenzo Bianconi .mask = GENMASK(10, 0), 27892617c15SLorenzo Bianconi }, 27992617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 28092617c15SLorenzo Bianconi }, 28121345107SLorenzo Bianconi .ts_settings = { 28221345107SLorenzo Bianconi .timer_en = { 28321345107SLorenzo Bianconi .addr = 0x19, 28421345107SLorenzo Bianconi .mask = BIT(5), 28521345107SLorenzo Bianconi }, 28621345107SLorenzo Bianconi .hr_timer = { 28721345107SLorenzo Bianconi .addr = 0x5c, 28821345107SLorenzo Bianconi .mask = BIT(4), 28921345107SLorenzo Bianconi }, 29021345107SLorenzo Bianconi .fifo_en = { 29121345107SLorenzo Bianconi .addr = 0x07, 29221345107SLorenzo Bianconi .mask = BIT(7), 29321345107SLorenzo Bianconi }, 29421345107SLorenzo Bianconi .decimator = { 29521345107SLorenzo Bianconi .addr = 0x09, 29621345107SLorenzo Bianconi .mask = GENMASK(5, 3), 29721345107SLorenzo Bianconi }, 29821345107SLorenzo Bianconi }, 299290a6ce1SLorenzo Bianconi }, 300290a6ce1SLorenzo Bianconi }; 301290a6ce1SLorenzo Bianconi 302290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \ 303290a6ce1SLorenzo Bianconi { \ 304290a6ce1SLorenzo Bianconi .type = chan_type, \ 305290a6ce1SLorenzo Bianconi .address = addr, \ 306290a6ce1SLorenzo Bianconi .modified = 1, \ 307290a6ce1SLorenzo Bianconi .channel2 = mod, \ 308290a6ce1SLorenzo Bianconi .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 309290a6ce1SLorenzo Bianconi BIT(IIO_CHAN_INFO_SCALE), \ 310290a6ce1SLorenzo Bianconi .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 311290a6ce1SLorenzo Bianconi .scan_index = scan_idx, \ 312290a6ce1SLorenzo Bianconi .scan_type = { \ 313290a6ce1SLorenzo Bianconi .sign = 's', \ 314290a6ce1SLorenzo Bianconi .realbits = 16, \ 315290a6ce1SLorenzo Bianconi .storagebits = 16, \ 316290a6ce1SLorenzo Bianconi .endianness = IIO_LE, \ 317290a6ce1SLorenzo Bianconi }, \ 318290a6ce1SLorenzo Bianconi } 319290a6ce1SLorenzo Bianconi 320290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { 321290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR, 322290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 323290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR, 324290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 325290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR, 326290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 327290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 328290a6ce1SLorenzo Bianconi }; 329290a6ce1SLorenzo Bianconi 330290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { 331290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR, 332290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 333290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR, 334290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 335290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR, 336290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 337290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 338290a6ce1SLorenzo Bianconi }; 339290a6ce1SLorenzo Bianconi 340290a6ce1SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id) 341290a6ce1SLorenzo Bianconi { 34251a8b707SLorenzo Bianconi int err, i, j, data; 343290a6ce1SLorenzo Bianconi 344290a6ce1SLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) { 345d068e4a0SLorenzo Bianconi for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) { 346d068e4a0SLorenzo Bianconi if (id == st_lsm6dsx_sensor_settings[i].id[j]) 347d068e4a0SLorenzo Bianconi break; 348d068e4a0SLorenzo Bianconi } 349d068e4a0SLorenzo Bianconi if (j < ST_LSM6DSX_MAX_ID) 350290a6ce1SLorenzo Bianconi break; 351290a6ce1SLorenzo Bianconi } 352290a6ce1SLorenzo Bianconi 353290a6ce1SLorenzo Bianconi if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) { 354290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported hw id [%02x]\n", id); 355290a6ce1SLorenzo Bianconi return -ENODEV; 356290a6ce1SLorenzo Bianconi } 357290a6ce1SLorenzo Bianconi 35851a8b707SLorenzo Bianconi err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data); 359290a6ce1SLorenzo Bianconi if (err < 0) { 360290a6ce1SLorenzo Bianconi dev_err(hw->dev, "failed to read whoami register\n"); 361290a6ce1SLorenzo Bianconi return err; 362290a6ce1SLorenzo Bianconi } 363290a6ce1SLorenzo Bianconi 364290a6ce1SLorenzo Bianconi if (data != st_lsm6dsx_sensor_settings[i].wai) { 365290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported whoami [%02x]\n", data); 366290a6ce1SLorenzo Bianconi return -ENODEV; 367290a6ce1SLorenzo Bianconi } 368290a6ce1SLorenzo Bianconi 369290a6ce1SLorenzo Bianconi hw->settings = &st_lsm6dsx_sensor_settings[i]; 370290a6ce1SLorenzo Bianconi 371290a6ce1SLorenzo Bianconi return 0; 372290a6ce1SLorenzo Bianconi } 373290a6ce1SLorenzo Bianconi 374290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, 375290a6ce1SLorenzo Bianconi u32 gain) 376290a6ce1SLorenzo Bianconi { 37751a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 37851a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 379290a6ce1SLorenzo Bianconi int i, err; 380290a6ce1SLorenzo Bianconi u8 val; 381290a6ce1SLorenzo Bianconi 382290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 38351a8b707SLorenzo Bianconi if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain) 384290a6ce1SLorenzo Bianconi break; 385290a6ce1SLorenzo Bianconi 386290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_FS_LIST_SIZE) 387290a6ce1SLorenzo Bianconi return -EINVAL; 388290a6ce1SLorenzo Bianconi 38951a8b707SLorenzo Bianconi val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val; 39051a8b707SLorenzo Bianconi reg = &st_lsm6dsx_fs_table[sensor->id].reg; 39151a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 39251a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(val, reg->mask)); 393290a6ce1SLorenzo Bianconi if (err < 0) 394290a6ce1SLorenzo Bianconi return err; 395290a6ce1SLorenzo Bianconi 396290a6ce1SLorenzo Bianconi sensor->gain = gain; 397290a6ce1SLorenzo Bianconi 398290a6ce1SLorenzo Bianconi return 0; 399290a6ce1SLorenzo Bianconi } 400290a6ce1SLorenzo Bianconi 40154a6d0c6SLorenzo Bianconi int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val) 402290a6ce1SLorenzo Bianconi { 4032ccc1503SLorenzo Bianconi int i; 404290a6ce1SLorenzo Bianconi 405290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 4062ccc1503SLorenzo Bianconi if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr) 407290a6ce1SLorenzo Bianconi break; 408290a6ce1SLorenzo Bianconi 409290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_ODR_LIST_SIZE) 410290a6ce1SLorenzo Bianconi return -EINVAL; 411290a6ce1SLorenzo Bianconi 4122ccc1503SLorenzo Bianconi *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; 413290a6ce1SLorenzo Bianconi 414290a6ce1SLorenzo Bianconi return 0; 415290a6ce1SLorenzo Bianconi } 416290a6ce1SLorenzo Bianconi 4172ccc1503SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr) 4182ccc1503SLorenzo Bianconi { 41951a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 42051a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 4212ccc1503SLorenzo Bianconi int err; 4222ccc1503SLorenzo Bianconi u8 val; 4232ccc1503SLorenzo Bianconi 4242ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, odr, &val); 4252ccc1503SLorenzo Bianconi if (err < 0) 4262ccc1503SLorenzo Bianconi return err; 4272ccc1503SLorenzo Bianconi 42851a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 42951a8b707SLorenzo Bianconi return regmap_update_bits(hw->regmap, reg->addr, reg->mask, 43051a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(val, reg->mask)); 4312ccc1503SLorenzo Bianconi } 4322ccc1503SLorenzo Bianconi 433290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor) 434290a6ce1SLorenzo Bianconi { 435290a6ce1SLorenzo Bianconi int err; 436290a6ce1SLorenzo Bianconi 437290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 438290a6ce1SLorenzo Bianconi if (err < 0) 439290a6ce1SLorenzo Bianconi return err; 440290a6ce1SLorenzo Bianconi 441290a6ce1SLorenzo Bianconi sensor->hw->enable_mask |= BIT(sensor->id); 442290a6ce1SLorenzo Bianconi 443290a6ce1SLorenzo Bianconi return 0; 444290a6ce1SLorenzo Bianconi } 445290a6ce1SLorenzo Bianconi 446290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor) 447290a6ce1SLorenzo Bianconi { 44851a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 44951a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 450290a6ce1SLorenzo Bianconi int err; 451290a6ce1SLorenzo Bianconi 45251a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 45351a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 45451a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 455290a6ce1SLorenzo Bianconi if (err < 0) 456290a6ce1SLorenzo Bianconi return err; 457290a6ce1SLorenzo Bianconi 45851a8b707SLorenzo Bianconi sensor->hw->enable_mask &= ~BIT(sensor->id); 459290a6ce1SLorenzo Bianconi 460290a6ce1SLorenzo Bianconi return 0; 461290a6ce1SLorenzo Bianconi } 462290a6ce1SLorenzo Bianconi 463290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, 464290a6ce1SLorenzo Bianconi u8 addr, int *val) 465290a6ce1SLorenzo Bianconi { 46651a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 467290a6ce1SLorenzo Bianconi int err, delay; 468290a6ce1SLorenzo Bianconi __le16 data; 469290a6ce1SLorenzo Bianconi 470290a6ce1SLorenzo Bianconi err = st_lsm6dsx_sensor_enable(sensor); 471290a6ce1SLorenzo Bianconi if (err < 0) 472290a6ce1SLorenzo Bianconi return err; 473290a6ce1SLorenzo Bianconi 474290a6ce1SLorenzo Bianconi delay = 1000000 / sensor->odr; 475290a6ce1SLorenzo Bianconi usleep_range(delay, 2 * delay); 476290a6ce1SLorenzo Bianconi 47751a8b707SLorenzo Bianconi err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data)); 478290a6ce1SLorenzo Bianconi if (err < 0) 479290a6ce1SLorenzo Bianconi return err; 480290a6ce1SLorenzo Bianconi 481290a6ce1SLorenzo Bianconi st_lsm6dsx_sensor_disable(sensor); 482290a6ce1SLorenzo Bianconi 4837b9ebe42SLorenzo Bianconi *val = (s16)le16_to_cpu(data); 484290a6ce1SLorenzo Bianconi 485290a6ce1SLorenzo Bianconi return IIO_VAL_INT; 486290a6ce1SLorenzo Bianconi } 487290a6ce1SLorenzo Bianconi 488290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, 489290a6ce1SLorenzo Bianconi struct iio_chan_spec const *ch, 490290a6ce1SLorenzo Bianconi int *val, int *val2, long mask) 491290a6ce1SLorenzo Bianconi { 492290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 493290a6ce1SLorenzo Bianconi int ret; 494290a6ce1SLorenzo Bianconi 495290a6ce1SLorenzo Bianconi switch (mask) { 496290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_RAW: 497290a6ce1SLorenzo Bianconi ret = iio_device_claim_direct_mode(iio_dev); 498290a6ce1SLorenzo Bianconi if (ret) 499290a6ce1SLorenzo Bianconi break; 500290a6ce1SLorenzo Bianconi 501290a6ce1SLorenzo Bianconi ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val); 502290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 503290a6ce1SLorenzo Bianconi break; 504290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: 505290a6ce1SLorenzo Bianconi *val = sensor->odr; 506290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT; 507290a6ce1SLorenzo Bianconi break; 508290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 509290a6ce1SLorenzo Bianconi *val = 0; 510290a6ce1SLorenzo Bianconi *val2 = sensor->gain; 511290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT_PLUS_MICRO; 512290a6ce1SLorenzo Bianconi break; 513290a6ce1SLorenzo Bianconi default: 514290a6ce1SLorenzo Bianconi ret = -EINVAL; 515290a6ce1SLorenzo Bianconi break; 516290a6ce1SLorenzo Bianconi } 517290a6ce1SLorenzo Bianconi 518290a6ce1SLorenzo Bianconi return ret; 519290a6ce1SLorenzo Bianconi } 520290a6ce1SLorenzo Bianconi 521290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, 522290a6ce1SLorenzo Bianconi struct iio_chan_spec const *chan, 523290a6ce1SLorenzo Bianconi int val, int val2, long mask) 524290a6ce1SLorenzo Bianconi { 525290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 526290a6ce1SLorenzo Bianconi int err; 527290a6ce1SLorenzo Bianconi 528290a6ce1SLorenzo Bianconi err = iio_device_claim_direct_mode(iio_dev); 529290a6ce1SLorenzo Bianconi if (err) 530290a6ce1SLorenzo Bianconi return err; 531290a6ce1SLorenzo Bianconi 532290a6ce1SLorenzo Bianconi switch (mask) { 533290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 534290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_full_scale(sensor, val2); 535290a6ce1SLorenzo Bianconi break; 5362ccc1503SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: { 5372ccc1503SLorenzo Bianconi u8 data; 5382ccc1503SLorenzo Bianconi 5392ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, val, &data); 5405e3c3e33SLorenzo Bianconi if (!err) 5415e3c3e33SLorenzo Bianconi sensor->odr = val; 542290a6ce1SLorenzo Bianconi break; 5432ccc1503SLorenzo Bianconi } 544290a6ce1SLorenzo Bianconi default: 545290a6ce1SLorenzo Bianconi err = -EINVAL; 546290a6ce1SLorenzo Bianconi break; 547290a6ce1SLorenzo Bianconi } 548290a6ce1SLorenzo Bianconi 549290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 550290a6ce1SLorenzo Bianconi 551290a6ce1SLorenzo Bianconi return err; 552290a6ce1SLorenzo Bianconi } 553290a6ce1SLorenzo Bianconi 554290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val) 555290a6ce1SLorenzo Bianconi { 556290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 557290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 5588f2a88a2SLorenzo Bianconi int err; 559290a6ce1SLorenzo Bianconi 5608f2a88a2SLorenzo Bianconi if (val < 1 || val > hw->settings->max_fifo_size) 561290a6ce1SLorenzo Bianconi return -EINVAL; 562290a6ce1SLorenzo Bianconi 563335eaedcSLorenzo Bianconi mutex_lock(&hw->conf_lock); 564335eaedcSLorenzo Bianconi 565290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_watermark(sensor, val); 566335eaedcSLorenzo Bianconi 567335eaedcSLorenzo Bianconi mutex_unlock(&hw->conf_lock); 568335eaedcSLorenzo Bianconi 569290a6ce1SLorenzo Bianconi if (err < 0) 570290a6ce1SLorenzo Bianconi return err; 571290a6ce1SLorenzo Bianconi 572290a6ce1SLorenzo Bianconi sensor->watermark = val; 573290a6ce1SLorenzo Bianconi 574290a6ce1SLorenzo Bianconi return 0; 575290a6ce1SLorenzo Bianconi } 576290a6ce1SLorenzo Bianconi 577290a6ce1SLorenzo Bianconi static ssize_t 578290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, 579290a6ce1SLorenzo Bianconi struct device_attribute *attr, 580290a6ce1SLorenzo Bianconi char *buf) 581290a6ce1SLorenzo Bianconi { 582290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 583290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 584290a6ce1SLorenzo Bianconi int i, len = 0; 585290a6ce1SLorenzo Bianconi 586290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 587290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", 588290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].odr_avl[i].hz); 589290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 590290a6ce1SLorenzo Bianconi 591290a6ce1SLorenzo Bianconi return len; 592290a6ce1SLorenzo Bianconi } 593290a6ce1SLorenzo Bianconi 594290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, 595290a6ce1SLorenzo Bianconi struct device_attribute *attr, 596290a6ce1SLorenzo Bianconi char *buf) 597290a6ce1SLorenzo Bianconi { 598290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 599290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 600290a6ce1SLorenzo Bianconi int i, len = 0; 601290a6ce1SLorenzo Bianconi 602290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 603290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", 604290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].fs_avl[i].gain); 605290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 606290a6ce1SLorenzo Bianconi 607290a6ce1SLorenzo Bianconi return len; 608290a6ce1SLorenzo Bianconi } 609290a6ce1SLorenzo Bianconi 610290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail); 611290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 612290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 613290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444, 614290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 615290a6ce1SLorenzo Bianconi 616290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = { 617290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 618290a6ce1SLorenzo Bianconi &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 619290a6ce1SLorenzo Bianconi NULL, 620290a6ce1SLorenzo Bianconi }; 621290a6ce1SLorenzo Bianconi 622290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = { 623290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_acc_attributes, 624290a6ce1SLorenzo Bianconi }; 625290a6ce1SLorenzo Bianconi 626290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = { 627290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_acc_attribute_group, 628290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 629290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 630290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 631290a6ce1SLorenzo Bianconi }; 632290a6ce1SLorenzo Bianconi 633290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = { 634290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 635290a6ce1SLorenzo Bianconi &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, 636290a6ce1SLorenzo Bianconi NULL, 637290a6ce1SLorenzo Bianconi }; 638290a6ce1SLorenzo Bianconi 639290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = { 640290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_gyro_attributes, 641290a6ce1SLorenzo Bianconi }; 642290a6ce1SLorenzo Bianconi 643290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = { 644290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_gyro_attribute_group, 645290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 646290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 647290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 648290a6ce1SLorenzo Bianconi }; 649290a6ce1SLorenzo Bianconi 650290a6ce1SLorenzo Bianconi static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; 651290a6ce1SLorenzo Bianconi 652dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) 653dba32904SLorenzo Bianconi { 654dba32904SLorenzo Bianconi struct device_node *np = hw->dev->of_node; 655dba32904SLorenzo Bianconi 656dba32904SLorenzo Bianconi if (!np) 657dba32904SLorenzo Bianconi return -EINVAL; 658dba32904SLorenzo Bianconi 659bf235277SLorenzo Bianconi return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); 660dba32904SLorenzo Bianconi } 661dba32904SLorenzo Bianconi 662dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) 663dba32904SLorenzo Bianconi { 664dba32904SLorenzo Bianconi int err = 0, drdy_pin; 665dba32904SLorenzo Bianconi 666dba32904SLorenzo Bianconi if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) { 667dba32904SLorenzo Bianconi struct st_sensors_platform_data *pdata; 668dba32904SLorenzo Bianconi struct device *dev = hw->dev; 669dba32904SLorenzo Bianconi 670dba32904SLorenzo Bianconi pdata = (struct st_sensors_platform_data *)dev->platform_data; 671dba32904SLorenzo Bianconi drdy_pin = pdata ? pdata->drdy_int_pin : 1; 672dba32904SLorenzo Bianconi } 673dba32904SLorenzo Bianconi 674dba32904SLorenzo Bianconi switch (drdy_pin) { 675dba32904SLorenzo Bianconi case 1: 676dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; 677dba32904SLorenzo Bianconi break; 678dba32904SLorenzo Bianconi case 2: 679dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; 680dba32904SLorenzo Bianconi break; 681dba32904SLorenzo Bianconi default: 682dba32904SLorenzo Bianconi dev_err(hw->dev, "unsupported data ready pin\n"); 683dba32904SLorenzo Bianconi err = -EINVAL; 684dba32904SLorenzo Bianconi break; 685dba32904SLorenzo Bianconi } 686dba32904SLorenzo Bianconi 687dba32904SLorenzo Bianconi return err; 688dba32904SLorenzo Bianconi } 689dba32904SLorenzo Bianconi 69021345107SLorenzo Bianconi static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) 69121345107SLorenzo Bianconi { 69221345107SLorenzo Bianconi const struct st_lsm6dsx_hw_ts_settings *ts_settings; 69321345107SLorenzo Bianconi int err, val; 69421345107SLorenzo Bianconi 69521345107SLorenzo Bianconi ts_settings = &hw->settings->ts_settings; 69621345107SLorenzo Bianconi /* enable hw timestamp generation if necessary */ 69721345107SLorenzo Bianconi if (ts_settings->timer_en.addr) { 69821345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask); 69921345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 70021345107SLorenzo Bianconi ts_settings->timer_en.addr, 70121345107SLorenzo Bianconi ts_settings->timer_en.mask, val); 70221345107SLorenzo Bianconi if (err < 0) 70321345107SLorenzo Bianconi return err; 70421345107SLorenzo Bianconi } 70521345107SLorenzo Bianconi 70621345107SLorenzo Bianconi /* enable high resolution for hw ts timer if necessary */ 70721345107SLorenzo Bianconi if (ts_settings->hr_timer.addr) { 70821345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask); 70921345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 71021345107SLorenzo Bianconi ts_settings->hr_timer.addr, 71121345107SLorenzo Bianconi ts_settings->hr_timer.mask, val); 71221345107SLorenzo Bianconi if (err < 0) 71321345107SLorenzo Bianconi return err; 71421345107SLorenzo Bianconi } 71521345107SLorenzo Bianconi 71621345107SLorenzo Bianconi /* enable ts queueing in FIFO if necessary */ 71721345107SLorenzo Bianconi if (ts_settings->fifo_en.addr) { 71821345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask); 71921345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 72021345107SLorenzo Bianconi ts_settings->fifo_en.addr, 72121345107SLorenzo Bianconi ts_settings->fifo_en.mask, val); 72221345107SLorenzo Bianconi if (err < 0) 72321345107SLorenzo Bianconi return err; 72421345107SLorenzo Bianconi } 72521345107SLorenzo Bianconi return 0; 72621345107SLorenzo Bianconi } 72721345107SLorenzo Bianconi 728290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) 729290a6ce1SLorenzo Bianconi { 73051a8b707SLorenzo Bianconi u8 drdy_int_reg; 731290a6ce1SLorenzo Bianconi int err; 732290a6ce1SLorenzo Bianconi 73351a8b707SLorenzo Bianconi err = regmap_write(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, 73451a8b707SLorenzo Bianconi ST_LSM6DSX_REG_RESET_MASK); 735290a6ce1SLorenzo Bianconi if (err < 0) 736290a6ce1SLorenzo Bianconi return err; 737290a6ce1SLorenzo Bianconi 738290a6ce1SLorenzo Bianconi msleep(200); 739290a6ce1SLorenzo Bianconi 740290a6ce1SLorenzo Bianconi /* enable Block Data Update */ 74151a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR, 74251a8b707SLorenzo Bianconi ST_LSM6DSX_REG_BDU_MASK, 74351a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1)); 744290a6ce1SLorenzo Bianconi if (err < 0) 745290a6ce1SLorenzo Bianconi return err; 746290a6ce1SLorenzo Bianconi 747290a6ce1SLorenzo Bianconi /* enable FIFO watermak interrupt */ 748dba32904SLorenzo Bianconi err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); 749290a6ce1SLorenzo Bianconi if (err < 0) 750290a6ce1SLorenzo Bianconi return err; 751290a6ce1SLorenzo Bianconi 75221345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, drdy_int_reg, 75351a8b707SLorenzo Bianconi ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 75451a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 75551a8b707SLorenzo Bianconi 1)); 75621345107SLorenzo Bianconi if (err < 0) 75721345107SLorenzo Bianconi return err; 75821345107SLorenzo Bianconi 75921345107SLorenzo Bianconi return st_lsm6dsx_init_hw_timer(hw); 760290a6ce1SLorenzo Bianconi } 761290a6ce1SLorenzo Bianconi 762290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, 763510c0106SLorenzo Bianconi enum st_lsm6dsx_sensor_id id, 764510c0106SLorenzo Bianconi const char *name) 765290a6ce1SLorenzo Bianconi { 766290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 767290a6ce1SLorenzo Bianconi struct iio_dev *iio_dev; 768290a6ce1SLorenzo Bianconi 769290a6ce1SLorenzo Bianconi iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); 770290a6ce1SLorenzo Bianconi if (!iio_dev) 771290a6ce1SLorenzo Bianconi return NULL; 772290a6ce1SLorenzo Bianconi 773290a6ce1SLorenzo Bianconi iio_dev->modes = INDIO_DIRECT_MODE; 774290a6ce1SLorenzo Bianconi iio_dev->dev.parent = hw->dev; 775290a6ce1SLorenzo Bianconi iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; 776290a6ce1SLorenzo Bianconi 777290a6ce1SLorenzo Bianconi sensor = iio_priv(iio_dev); 778290a6ce1SLorenzo Bianconi sensor->id = id; 779290a6ce1SLorenzo Bianconi sensor->hw = hw; 780290a6ce1SLorenzo Bianconi sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; 781290a6ce1SLorenzo Bianconi sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; 782290a6ce1SLorenzo Bianconi sensor->watermark = 1; 783290a6ce1SLorenzo Bianconi 784290a6ce1SLorenzo Bianconi switch (id) { 785290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_ACC: 786290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_acc_channels; 787290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); 788290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_acc_info; 789290a6ce1SLorenzo Bianconi 790510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", 791510c0106SLorenzo Bianconi name); 792290a6ce1SLorenzo Bianconi break; 793290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_GYRO: 794290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_gyro_channels; 795290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); 796290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_gyro_info; 797290a6ce1SLorenzo Bianconi 798510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", 799510c0106SLorenzo Bianconi name); 800290a6ce1SLorenzo Bianconi break; 801290a6ce1SLorenzo Bianconi default: 802290a6ce1SLorenzo Bianconi return NULL; 803290a6ce1SLorenzo Bianconi } 804510c0106SLorenzo Bianconi iio_dev->name = sensor->name; 805290a6ce1SLorenzo Bianconi 806290a6ce1SLorenzo Bianconi return iio_dev; 807290a6ce1SLorenzo Bianconi } 808290a6ce1SLorenzo Bianconi 809510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, 81051a8b707SLorenzo Bianconi struct regmap *regmap) 811290a6ce1SLorenzo Bianconi { 812290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw; 813290a6ce1SLorenzo Bianconi int i, err; 814290a6ce1SLorenzo Bianconi 815290a6ce1SLorenzo Bianconi hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 816290a6ce1SLorenzo Bianconi if (!hw) 817290a6ce1SLorenzo Bianconi return -ENOMEM; 818290a6ce1SLorenzo Bianconi 819290a6ce1SLorenzo Bianconi dev_set_drvdata(dev, (void *)hw); 820290a6ce1SLorenzo Bianconi 821290a6ce1SLorenzo Bianconi mutex_init(&hw->fifo_lock); 822335eaedcSLorenzo Bianconi mutex_init(&hw->conf_lock); 823290a6ce1SLorenzo Bianconi 82491a6b841SLorenzo Bianconi hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL); 82591a6b841SLorenzo Bianconi if (!hw->buff) 82691a6b841SLorenzo Bianconi return -ENOMEM; 82791a6b841SLorenzo Bianconi 828290a6ce1SLorenzo Bianconi hw->dev = dev; 829290a6ce1SLorenzo Bianconi hw->irq = irq; 83051a8b707SLorenzo Bianconi hw->regmap = regmap; 831290a6ce1SLorenzo Bianconi 832290a6ce1SLorenzo Bianconi err = st_lsm6dsx_check_whoami(hw, hw_id); 833290a6ce1SLorenzo Bianconi if (err < 0) 834290a6ce1SLorenzo Bianconi return err; 835290a6ce1SLorenzo Bianconi 836290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 837510c0106SLorenzo Bianconi hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name); 838290a6ce1SLorenzo Bianconi if (!hw->iio_devs[i]) 839290a6ce1SLorenzo Bianconi return -ENOMEM; 840290a6ce1SLorenzo Bianconi } 841290a6ce1SLorenzo Bianconi 842290a6ce1SLorenzo Bianconi err = st_lsm6dsx_init_device(hw); 843290a6ce1SLorenzo Bianconi if (err < 0) 844290a6ce1SLorenzo Bianconi return err; 845290a6ce1SLorenzo Bianconi 846290a6ce1SLorenzo Bianconi if (hw->irq > 0) { 847290a6ce1SLorenzo Bianconi err = st_lsm6dsx_fifo_setup(hw); 848290a6ce1SLorenzo Bianconi if (err < 0) 849290a6ce1SLorenzo Bianconi return err; 850290a6ce1SLorenzo Bianconi } 851290a6ce1SLorenzo Bianconi 852290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 853290a6ce1SLorenzo Bianconi err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); 854290a6ce1SLorenzo Bianconi if (err) 855290a6ce1SLorenzo Bianconi return err; 856290a6ce1SLorenzo Bianconi } 857290a6ce1SLorenzo Bianconi 858290a6ce1SLorenzo Bianconi return 0; 859290a6ce1SLorenzo Bianconi } 860290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe); 861290a6ce1SLorenzo Bianconi 8623cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) 863d3f77058SLorenzo Bianconi { 864d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 865d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 86651a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 867d3f77058SLorenzo Bianconi int i, err = 0; 868d3f77058SLorenzo Bianconi 869d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 870d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 871d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 872d3f77058SLorenzo Bianconi continue; 873d3f77058SLorenzo Bianconi 87451a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 87551a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 87651a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 877d3f77058SLorenzo Bianconi if (err < 0) 878d3f77058SLorenzo Bianconi return err; 879d3f77058SLorenzo Bianconi } 880d3f77058SLorenzo Bianconi 881d3f77058SLorenzo Bianconi if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) 882d3f77058SLorenzo Bianconi err = st_lsm6dsx_flush_fifo(hw); 883d3f77058SLorenzo Bianconi 884d3f77058SLorenzo Bianconi return err; 885d3f77058SLorenzo Bianconi } 886d3f77058SLorenzo Bianconi 8873cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev) 888d3f77058SLorenzo Bianconi { 889d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 890d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 891d3f77058SLorenzo Bianconi int i, err = 0; 892d3f77058SLorenzo Bianconi 893d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 894d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 895d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 896d3f77058SLorenzo Bianconi continue; 897d3f77058SLorenzo Bianconi 898d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 899d3f77058SLorenzo Bianconi if (err < 0) 900d3f77058SLorenzo Bianconi return err; 901d3f77058SLorenzo Bianconi } 902d3f77058SLorenzo Bianconi 903d3f77058SLorenzo Bianconi if (hw->enable_mask) 904d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); 905d3f77058SLorenzo Bianconi 906d3f77058SLorenzo Bianconi return err; 907d3f77058SLorenzo Bianconi } 908d3f77058SLorenzo Bianconi 909d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = { 910d3f77058SLorenzo Bianconi SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume) 911d3f77058SLorenzo Bianconi }; 912d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops); 913d3f77058SLorenzo Bianconi 914290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); 915290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); 916290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); 917290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2"); 918