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 4012ccc1503SLorenzo Bianconi static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, 4022ccc1503SLorenzo Bianconi u8 *val) 403290a6ce1SLorenzo Bianconi { 4042ccc1503SLorenzo Bianconi int i; 405290a6ce1SLorenzo Bianconi 406290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 4072ccc1503SLorenzo Bianconi if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr) 408290a6ce1SLorenzo Bianconi break; 409290a6ce1SLorenzo Bianconi 410290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_ODR_LIST_SIZE) 411290a6ce1SLorenzo Bianconi return -EINVAL; 412290a6ce1SLorenzo Bianconi 4132ccc1503SLorenzo Bianconi *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; 414290a6ce1SLorenzo Bianconi 415290a6ce1SLorenzo Bianconi return 0; 416290a6ce1SLorenzo Bianconi } 417290a6ce1SLorenzo Bianconi 4182ccc1503SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr) 4192ccc1503SLorenzo Bianconi { 42051a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 42151a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 4222ccc1503SLorenzo Bianconi int err; 4232ccc1503SLorenzo Bianconi u8 val; 4242ccc1503SLorenzo Bianconi 4252ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, odr, &val); 4262ccc1503SLorenzo Bianconi if (err < 0) 4272ccc1503SLorenzo Bianconi return err; 4282ccc1503SLorenzo Bianconi 42951a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 43051a8b707SLorenzo Bianconi return regmap_update_bits(hw->regmap, reg->addr, reg->mask, 43151a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(val, reg->mask)); 4322ccc1503SLorenzo Bianconi } 4332ccc1503SLorenzo Bianconi 434290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor) 435290a6ce1SLorenzo Bianconi { 436290a6ce1SLorenzo Bianconi int err; 437290a6ce1SLorenzo Bianconi 438290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 439290a6ce1SLorenzo Bianconi if (err < 0) 440290a6ce1SLorenzo Bianconi return err; 441290a6ce1SLorenzo Bianconi 442290a6ce1SLorenzo Bianconi sensor->hw->enable_mask |= BIT(sensor->id); 443290a6ce1SLorenzo Bianconi 444290a6ce1SLorenzo Bianconi return 0; 445290a6ce1SLorenzo Bianconi } 446290a6ce1SLorenzo Bianconi 447290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor) 448290a6ce1SLorenzo Bianconi { 44951a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 45051a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 451290a6ce1SLorenzo Bianconi int err; 452290a6ce1SLorenzo Bianconi 45351a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 45451a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 45551a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 456290a6ce1SLorenzo Bianconi if (err < 0) 457290a6ce1SLorenzo Bianconi return err; 458290a6ce1SLorenzo Bianconi 45951a8b707SLorenzo Bianconi sensor->hw->enable_mask &= ~BIT(sensor->id); 460290a6ce1SLorenzo Bianconi 461290a6ce1SLorenzo Bianconi return 0; 462290a6ce1SLorenzo Bianconi } 463290a6ce1SLorenzo Bianconi 464290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, 465290a6ce1SLorenzo Bianconi u8 addr, int *val) 466290a6ce1SLorenzo Bianconi { 46751a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 468290a6ce1SLorenzo Bianconi int err, delay; 469290a6ce1SLorenzo Bianconi __le16 data; 470290a6ce1SLorenzo Bianconi 471290a6ce1SLorenzo Bianconi err = st_lsm6dsx_sensor_enable(sensor); 472290a6ce1SLorenzo Bianconi if (err < 0) 473290a6ce1SLorenzo Bianconi return err; 474290a6ce1SLorenzo Bianconi 475290a6ce1SLorenzo Bianconi delay = 1000000 / sensor->odr; 476290a6ce1SLorenzo Bianconi usleep_range(delay, 2 * delay); 477290a6ce1SLorenzo Bianconi 47851a8b707SLorenzo Bianconi err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data)); 479290a6ce1SLorenzo Bianconi if (err < 0) 480290a6ce1SLorenzo Bianconi return err; 481290a6ce1SLorenzo Bianconi 482290a6ce1SLorenzo Bianconi st_lsm6dsx_sensor_disable(sensor); 483290a6ce1SLorenzo Bianconi 4847b9ebe42SLorenzo Bianconi *val = (s16)le16_to_cpu(data); 485290a6ce1SLorenzo Bianconi 486290a6ce1SLorenzo Bianconi return IIO_VAL_INT; 487290a6ce1SLorenzo Bianconi } 488290a6ce1SLorenzo Bianconi 489290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, 490290a6ce1SLorenzo Bianconi struct iio_chan_spec const *ch, 491290a6ce1SLorenzo Bianconi int *val, int *val2, long mask) 492290a6ce1SLorenzo Bianconi { 493290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 494290a6ce1SLorenzo Bianconi int ret; 495290a6ce1SLorenzo Bianconi 496290a6ce1SLorenzo Bianconi switch (mask) { 497290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_RAW: 498290a6ce1SLorenzo Bianconi ret = iio_device_claim_direct_mode(iio_dev); 499290a6ce1SLorenzo Bianconi if (ret) 500290a6ce1SLorenzo Bianconi break; 501290a6ce1SLorenzo Bianconi 502290a6ce1SLorenzo Bianconi ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val); 503290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 504290a6ce1SLorenzo Bianconi break; 505290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: 506290a6ce1SLorenzo Bianconi *val = sensor->odr; 507290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT; 508290a6ce1SLorenzo Bianconi break; 509290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 510290a6ce1SLorenzo Bianconi *val = 0; 511290a6ce1SLorenzo Bianconi *val2 = sensor->gain; 512290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT_PLUS_MICRO; 513290a6ce1SLorenzo Bianconi break; 514290a6ce1SLorenzo Bianconi default: 515290a6ce1SLorenzo Bianconi ret = -EINVAL; 516290a6ce1SLorenzo Bianconi break; 517290a6ce1SLorenzo Bianconi } 518290a6ce1SLorenzo Bianconi 519290a6ce1SLorenzo Bianconi return ret; 520290a6ce1SLorenzo Bianconi } 521290a6ce1SLorenzo Bianconi 522290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, 523290a6ce1SLorenzo Bianconi struct iio_chan_spec const *chan, 524290a6ce1SLorenzo Bianconi int val, int val2, long mask) 525290a6ce1SLorenzo Bianconi { 526290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 527290a6ce1SLorenzo Bianconi int err; 528290a6ce1SLorenzo Bianconi 529290a6ce1SLorenzo Bianconi err = iio_device_claim_direct_mode(iio_dev); 530290a6ce1SLorenzo Bianconi if (err) 531290a6ce1SLorenzo Bianconi return err; 532290a6ce1SLorenzo Bianconi 533290a6ce1SLorenzo Bianconi switch (mask) { 534290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 535290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_full_scale(sensor, val2); 536290a6ce1SLorenzo Bianconi break; 5372ccc1503SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: { 5382ccc1503SLorenzo Bianconi u8 data; 5392ccc1503SLorenzo Bianconi 5402ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, val, &data); 5415e3c3e33SLorenzo Bianconi if (!err) 5425e3c3e33SLorenzo Bianconi sensor->odr = val; 543290a6ce1SLorenzo Bianconi break; 5442ccc1503SLorenzo Bianconi } 545290a6ce1SLorenzo Bianconi default: 546290a6ce1SLorenzo Bianconi err = -EINVAL; 547290a6ce1SLorenzo Bianconi break; 548290a6ce1SLorenzo Bianconi } 549290a6ce1SLorenzo Bianconi 550290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 551290a6ce1SLorenzo Bianconi 552290a6ce1SLorenzo Bianconi return err; 553290a6ce1SLorenzo Bianconi } 554290a6ce1SLorenzo Bianconi 555290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val) 556290a6ce1SLorenzo Bianconi { 557290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 558290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 5598f2a88a2SLorenzo Bianconi int err; 560290a6ce1SLorenzo Bianconi 5618f2a88a2SLorenzo Bianconi if (val < 1 || val > hw->settings->max_fifo_size) 562290a6ce1SLorenzo Bianconi return -EINVAL; 563290a6ce1SLorenzo Bianconi 564335eaedcSLorenzo Bianconi mutex_lock(&hw->conf_lock); 565335eaedcSLorenzo Bianconi 566290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_watermark(sensor, val); 567335eaedcSLorenzo Bianconi 568335eaedcSLorenzo Bianconi mutex_unlock(&hw->conf_lock); 569335eaedcSLorenzo Bianconi 570290a6ce1SLorenzo Bianconi if (err < 0) 571290a6ce1SLorenzo Bianconi return err; 572290a6ce1SLorenzo Bianconi 573290a6ce1SLorenzo Bianconi sensor->watermark = val; 574290a6ce1SLorenzo Bianconi 575290a6ce1SLorenzo Bianconi return 0; 576290a6ce1SLorenzo Bianconi } 577290a6ce1SLorenzo Bianconi 578290a6ce1SLorenzo Bianconi static ssize_t 579290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, 580290a6ce1SLorenzo Bianconi struct device_attribute *attr, 581290a6ce1SLorenzo Bianconi char *buf) 582290a6ce1SLorenzo Bianconi { 583290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 584290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 585290a6ce1SLorenzo Bianconi int i, len = 0; 586290a6ce1SLorenzo Bianconi 587290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 588290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", 589290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].odr_avl[i].hz); 590290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 591290a6ce1SLorenzo Bianconi 592290a6ce1SLorenzo Bianconi return len; 593290a6ce1SLorenzo Bianconi } 594290a6ce1SLorenzo Bianconi 595290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, 596290a6ce1SLorenzo Bianconi struct device_attribute *attr, 597290a6ce1SLorenzo Bianconi char *buf) 598290a6ce1SLorenzo Bianconi { 599290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 600290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 601290a6ce1SLorenzo Bianconi int i, len = 0; 602290a6ce1SLorenzo Bianconi 603290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 604290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", 605290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].fs_avl[i].gain); 606290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 607290a6ce1SLorenzo Bianconi 608290a6ce1SLorenzo Bianconi return len; 609290a6ce1SLorenzo Bianconi } 610290a6ce1SLorenzo Bianconi 611290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail); 612290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 613290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 614290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444, 615290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 616290a6ce1SLorenzo Bianconi 617290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = { 618290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 619290a6ce1SLorenzo Bianconi &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 620290a6ce1SLorenzo Bianconi NULL, 621290a6ce1SLorenzo Bianconi }; 622290a6ce1SLorenzo Bianconi 623290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = { 624290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_acc_attributes, 625290a6ce1SLorenzo Bianconi }; 626290a6ce1SLorenzo Bianconi 627290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = { 628290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_acc_attribute_group, 629290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 630290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 631290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 632290a6ce1SLorenzo Bianconi }; 633290a6ce1SLorenzo Bianconi 634290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = { 635290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 636290a6ce1SLorenzo Bianconi &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, 637290a6ce1SLorenzo Bianconi NULL, 638290a6ce1SLorenzo Bianconi }; 639290a6ce1SLorenzo Bianconi 640290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = { 641290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_gyro_attributes, 642290a6ce1SLorenzo Bianconi }; 643290a6ce1SLorenzo Bianconi 644290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = { 645290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_gyro_attribute_group, 646290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 647290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 648290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 649290a6ce1SLorenzo Bianconi }; 650290a6ce1SLorenzo Bianconi 651290a6ce1SLorenzo Bianconi static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; 652290a6ce1SLorenzo Bianconi 653dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) 654dba32904SLorenzo Bianconi { 655dba32904SLorenzo Bianconi struct device_node *np = hw->dev->of_node; 656dba32904SLorenzo Bianconi 657dba32904SLorenzo Bianconi if (!np) 658dba32904SLorenzo Bianconi return -EINVAL; 659dba32904SLorenzo Bianconi 660bf235277SLorenzo Bianconi return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); 661dba32904SLorenzo Bianconi } 662dba32904SLorenzo Bianconi 663dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) 664dba32904SLorenzo Bianconi { 665dba32904SLorenzo Bianconi int err = 0, drdy_pin; 666dba32904SLorenzo Bianconi 667dba32904SLorenzo Bianconi if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) { 668dba32904SLorenzo Bianconi struct st_sensors_platform_data *pdata; 669dba32904SLorenzo Bianconi struct device *dev = hw->dev; 670dba32904SLorenzo Bianconi 671dba32904SLorenzo Bianconi pdata = (struct st_sensors_platform_data *)dev->platform_data; 672dba32904SLorenzo Bianconi drdy_pin = pdata ? pdata->drdy_int_pin : 1; 673dba32904SLorenzo Bianconi } 674dba32904SLorenzo Bianconi 675dba32904SLorenzo Bianconi switch (drdy_pin) { 676dba32904SLorenzo Bianconi case 1: 677dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; 678dba32904SLorenzo Bianconi break; 679dba32904SLorenzo Bianconi case 2: 680dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; 681dba32904SLorenzo Bianconi break; 682dba32904SLorenzo Bianconi default: 683dba32904SLorenzo Bianconi dev_err(hw->dev, "unsupported data ready pin\n"); 684dba32904SLorenzo Bianconi err = -EINVAL; 685dba32904SLorenzo Bianconi break; 686dba32904SLorenzo Bianconi } 687dba32904SLorenzo Bianconi 688dba32904SLorenzo Bianconi return err; 689dba32904SLorenzo Bianconi } 690dba32904SLorenzo Bianconi 69121345107SLorenzo Bianconi static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) 69221345107SLorenzo Bianconi { 69321345107SLorenzo Bianconi const struct st_lsm6dsx_hw_ts_settings *ts_settings; 69421345107SLorenzo Bianconi int err, val; 69521345107SLorenzo Bianconi 69621345107SLorenzo Bianconi ts_settings = &hw->settings->ts_settings; 69721345107SLorenzo Bianconi /* enable hw timestamp generation if necessary */ 69821345107SLorenzo Bianconi if (ts_settings->timer_en.addr) { 69921345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask); 70021345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 70121345107SLorenzo Bianconi ts_settings->timer_en.addr, 70221345107SLorenzo Bianconi ts_settings->timer_en.mask, val); 70321345107SLorenzo Bianconi if (err < 0) 70421345107SLorenzo Bianconi return err; 70521345107SLorenzo Bianconi } 70621345107SLorenzo Bianconi 70721345107SLorenzo Bianconi /* enable high resolution for hw ts timer if necessary */ 70821345107SLorenzo Bianconi if (ts_settings->hr_timer.addr) { 70921345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask); 71021345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 71121345107SLorenzo Bianconi ts_settings->hr_timer.addr, 71221345107SLorenzo Bianconi ts_settings->hr_timer.mask, val); 71321345107SLorenzo Bianconi if (err < 0) 71421345107SLorenzo Bianconi return err; 71521345107SLorenzo Bianconi } 71621345107SLorenzo Bianconi 71721345107SLorenzo Bianconi /* enable ts queueing in FIFO if necessary */ 71821345107SLorenzo Bianconi if (ts_settings->fifo_en.addr) { 71921345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask); 72021345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 72121345107SLorenzo Bianconi ts_settings->fifo_en.addr, 72221345107SLorenzo Bianconi ts_settings->fifo_en.mask, val); 72321345107SLorenzo Bianconi if (err < 0) 72421345107SLorenzo Bianconi return err; 72521345107SLorenzo Bianconi } 72621345107SLorenzo Bianconi return 0; 72721345107SLorenzo Bianconi } 72821345107SLorenzo Bianconi 729290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) 730290a6ce1SLorenzo Bianconi { 73151a8b707SLorenzo Bianconi u8 drdy_int_reg; 732290a6ce1SLorenzo Bianconi int err; 733290a6ce1SLorenzo Bianconi 73451a8b707SLorenzo Bianconi err = regmap_write(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, 73551a8b707SLorenzo Bianconi ST_LSM6DSX_REG_RESET_MASK); 736290a6ce1SLorenzo Bianconi if (err < 0) 737290a6ce1SLorenzo Bianconi return err; 738290a6ce1SLorenzo Bianconi 739290a6ce1SLorenzo Bianconi msleep(200); 740290a6ce1SLorenzo Bianconi 741290a6ce1SLorenzo Bianconi /* enable Block Data Update */ 74251a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR, 74351a8b707SLorenzo Bianconi ST_LSM6DSX_REG_BDU_MASK, 74451a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1)); 745290a6ce1SLorenzo Bianconi if (err < 0) 746290a6ce1SLorenzo Bianconi return err; 747290a6ce1SLorenzo Bianconi 748290a6ce1SLorenzo Bianconi /* enable FIFO watermak interrupt */ 749dba32904SLorenzo Bianconi err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); 750290a6ce1SLorenzo Bianconi if (err < 0) 751290a6ce1SLorenzo Bianconi return err; 752290a6ce1SLorenzo Bianconi 75321345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, drdy_int_reg, 75451a8b707SLorenzo Bianconi ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 75551a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 75651a8b707SLorenzo Bianconi 1)); 75721345107SLorenzo Bianconi if (err < 0) 75821345107SLorenzo Bianconi return err; 75921345107SLorenzo Bianconi 76021345107SLorenzo Bianconi return st_lsm6dsx_init_hw_timer(hw); 761290a6ce1SLorenzo Bianconi } 762290a6ce1SLorenzo Bianconi 763290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, 764510c0106SLorenzo Bianconi enum st_lsm6dsx_sensor_id id, 765510c0106SLorenzo Bianconi const char *name) 766290a6ce1SLorenzo Bianconi { 767290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 768290a6ce1SLorenzo Bianconi struct iio_dev *iio_dev; 769290a6ce1SLorenzo Bianconi 770290a6ce1SLorenzo Bianconi iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); 771290a6ce1SLorenzo Bianconi if (!iio_dev) 772290a6ce1SLorenzo Bianconi return NULL; 773290a6ce1SLorenzo Bianconi 774290a6ce1SLorenzo Bianconi iio_dev->modes = INDIO_DIRECT_MODE; 775290a6ce1SLorenzo Bianconi iio_dev->dev.parent = hw->dev; 776290a6ce1SLorenzo Bianconi iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; 777290a6ce1SLorenzo Bianconi 778290a6ce1SLorenzo Bianconi sensor = iio_priv(iio_dev); 779290a6ce1SLorenzo Bianconi sensor->id = id; 780290a6ce1SLorenzo Bianconi sensor->hw = hw; 781290a6ce1SLorenzo Bianconi sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; 782290a6ce1SLorenzo Bianconi sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; 783290a6ce1SLorenzo Bianconi sensor->watermark = 1; 784290a6ce1SLorenzo Bianconi 785290a6ce1SLorenzo Bianconi switch (id) { 786290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_ACC: 787290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_acc_channels; 788290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); 789290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_acc_info; 790290a6ce1SLorenzo Bianconi 791510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", 792510c0106SLorenzo Bianconi name); 793290a6ce1SLorenzo Bianconi break; 794290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_GYRO: 795290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_gyro_channels; 796290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); 797290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_gyro_info; 798290a6ce1SLorenzo Bianconi 799510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", 800510c0106SLorenzo Bianconi name); 801290a6ce1SLorenzo Bianconi break; 802290a6ce1SLorenzo Bianconi default: 803290a6ce1SLorenzo Bianconi return NULL; 804290a6ce1SLorenzo Bianconi } 805510c0106SLorenzo Bianconi iio_dev->name = sensor->name; 806290a6ce1SLorenzo Bianconi 807290a6ce1SLorenzo Bianconi return iio_dev; 808290a6ce1SLorenzo Bianconi } 809290a6ce1SLorenzo Bianconi 810510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, 81151a8b707SLorenzo Bianconi struct regmap *regmap) 812290a6ce1SLorenzo Bianconi { 813290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw; 814290a6ce1SLorenzo Bianconi int i, err; 815290a6ce1SLorenzo Bianconi 816290a6ce1SLorenzo Bianconi hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 817290a6ce1SLorenzo Bianconi if (!hw) 818290a6ce1SLorenzo Bianconi return -ENOMEM; 819290a6ce1SLorenzo Bianconi 820290a6ce1SLorenzo Bianconi dev_set_drvdata(dev, (void *)hw); 821290a6ce1SLorenzo Bianconi 822290a6ce1SLorenzo Bianconi mutex_init(&hw->fifo_lock); 823335eaedcSLorenzo Bianconi mutex_init(&hw->conf_lock); 824290a6ce1SLorenzo Bianconi 82591a6b841SLorenzo Bianconi hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL); 82691a6b841SLorenzo Bianconi if (!hw->buff) 82791a6b841SLorenzo Bianconi return -ENOMEM; 82891a6b841SLorenzo Bianconi 829290a6ce1SLorenzo Bianconi hw->dev = dev; 830290a6ce1SLorenzo Bianconi hw->irq = irq; 83151a8b707SLorenzo Bianconi hw->regmap = regmap; 832290a6ce1SLorenzo Bianconi 833290a6ce1SLorenzo Bianconi err = st_lsm6dsx_check_whoami(hw, hw_id); 834290a6ce1SLorenzo Bianconi if (err < 0) 835290a6ce1SLorenzo Bianconi return err; 836290a6ce1SLorenzo Bianconi 837290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 838510c0106SLorenzo Bianconi hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name); 839290a6ce1SLorenzo Bianconi if (!hw->iio_devs[i]) 840290a6ce1SLorenzo Bianconi return -ENOMEM; 841290a6ce1SLorenzo Bianconi } 842290a6ce1SLorenzo Bianconi 843290a6ce1SLorenzo Bianconi err = st_lsm6dsx_init_device(hw); 844290a6ce1SLorenzo Bianconi if (err < 0) 845290a6ce1SLorenzo Bianconi return err; 846290a6ce1SLorenzo Bianconi 847290a6ce1SLorenzo Bianconi if (hw->irq > 0) { 848290a6ce1SLorenzo Bianconi err = st_lsm6dsx_fifo_setup(hw); 849290a6ce1SLorenzo Bianconi if (err < 0) 850290a6ce1SLorenzo Bianconi return err; 851290a6ce1SLorenzo Bianconi } 852290a6ce1SLorenzo Bianconi 853290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 854290a6ce1SLorenzo Bianconi err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); 855290a6ce1SLorenzo Bianconi if (err) 856290a6ce1SLorenzo Bianconi return err; 857290a6ce1SLorenzo Bianconi } 858290a6ce1SLorenzo Bianconi 859290a6ce1SLorenzo Bianconi return 0; 860290a6ce1SLorenzo Bianconi } 861290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe); 862290a6ce1SLorenzo Bianconi 8633cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) 864d3f77058SLorenzo Bianconi { 865d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 866d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 86751a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 868d3f77058SLorenzo Bianconi int i, err = 0; 869d3f77058SLorenzo Bianconi 870d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 871d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 872d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 873d3f77058SLorenzo Bianconi continue; 874d3f77058SLorenzo Bianconi 87551a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 87651a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 87751a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 878d3f77058SLorenzo Bianconi if (err < 0) 879d3f77058SLorenzo Bianconi return err; 880d3f77058SLorenzo Bianconi } 881d3f77058SLorenzo Bianconi 882d3f77058SLorenzo Bianconi if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) 883d3f77058SLorenzo Bianconi err = st_lsm6dsx_flush_fifo(hw); 884d3f77058SLorenzo Bianconi 885d3f77058SLorenzo Bianconi return err; 886d3f77058SLorenzo Bianconi } 887d3f77058SLorenzo Bianconi 8883cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev) 889d3f77058SLorenzo Bianconi { 890d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 891d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 892d3f77058SLorenzo Bianconi int i, err = 0; 893d3f77058SLorenzo Bianconi 894d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 895d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 896d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 897d3f77058SLorenzo Bianconi continue; 898d3f77058SLorenzo Bianconi 899d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 900d3f77058SLorenzo Bianconi if (err < 0) 901d3f77058SLorenzo Bianconi return err; 902d3f77058SLorenzo Bianconi } 903d3f77058SLorenzo Bianconi 904d3f77058SLorenzo Bianconi if (hw->enable_mask) 905d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); 906d3f77058SLorenzo Bianconi 907d3f77058SLorenzo Bianconi return err; 908d3f77058SLorenzo Bianconi } 909d3f77058SLorenzo Bianconi 910d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = { 911d3f77058SLorenzo Bianconi SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume) 912d3f77058SLorenzo Bianconi }; 913d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops); 914d3f77058SLorenzo Bianconi 915290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); 916290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); 917290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); 918290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2"); 919