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 * 20df47710aSLorenzo Bianconi * - LSM6DS3H/LSM6DSL/LSM6DSM: 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 = { 17492617c15SLorenzo Bianconi .fifo_th = { 17592617c15SLorenzo Bianconi .addr = 0x06, 17692617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 17792617c15SLorenzo Bianconi }, 17892617c15SLorenzo Bianconi .fifo_diff = { 17992617c15SLorenzo Bianconi .addr = 0x3a, 18092617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 18192617c15SLorenzo Bianconi }, 18292617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 18392617c15SLorenzo Bianconi }, 18421345107SLorenzo Bianconi .ts_settings = { 18521345107SLorenzo Bianconi .timer_en = { 18621345107SLorenzo Bianconi .addr = 0x58, 18721345107SLorenzo Bianconi .mask = BIT(7), 18821345107SLorenzo Bianconi }, 18921345107SLorenzo Bianconi .hr_timer = { 19021345107SLorenzo Bianconi .addr = 0x5c, 19121345107SLorenzo Bianconi .mask = BIT(4), 19221345107SLorenzo Bianconi }, 19321345107SLorenzo Bianconi .fifo_en = { 19421345107SLorenzo Bianconi .addr = 0x07, 19521345107SLorenzo Bianconi .mask = BIT(7), 19621345107SLorenzo Bianconi }, 19721345107SLorenzo Bianconi .decimator = { 19821345107SLorenzo Bianconi .addr = 0x09, 19921345107SLorenzo Bianconi .mask = GENMASK(5, 3), 20021345107SLorenzo Bianconi }, 20121345107SLorenzo Bianconi }, 202290a6ce1SLorenzo Bianconi }, 203290a6ce1SLorenzo Bianconi { 204df47710aSLorenzo Bianconi .wai = 0x69, 2058f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 206df47710aSLorenzo Bianconi .id = { 207df47710aSLorenzo Bianconi [0] = ST_LSM6DS3H_ID, 208df47710aSLorenzo Bianconi }, 2097ca3ac9eSLorenzo Bianconi .decimator = { 2107ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 2117ca3ac9eSLorenzo Bianconi .addr = 0x08, 2127ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 2137ca3ac9eSLorenzo Bianconi }, 2147ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 2157ca3ac9eSLorenzo Bianconi .addr = 0x08, 2167ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 2177ca3ac9eSLorenzo Bianconi }, 2187ca3ac9eSLorenzo Bianconi }, 21992617c15SLorenzo Bianconi .fifo_ops = { 22092617c15SLorenzo Bianconi .fifo_th = { 22192617c15SLorenzo Bianconi .addr = 0x06, 22292617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 22392617c15SLorenzo Bianconi }, 22492617c15SLorenzo Bianconi .fifo_diff = { 22592617c15SLorenzo Bianconi .addr = 0x3a, 22692617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 22792617c15SLorenzo Bianconi }, 22892617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 22992617c15SLorenzo Bianconi }, 23021345107SLorenzo Bianconi .ts_settings = { 23121345107SLorenzo Bianconi .timer_en = { 23221345107SLorenzo Bianconi .addr = 0x58, 23321345107SLorenzo Bianconi .mask = BIT(7), 23421345107SLorenzo Bianconi }, 23521345107SLorenzo Bianconi .hr_timer = { 23621345107SLorenzo Bianconi .addr = 0x5c, 23721345107SLorenzo Bianconi .mask = BIT(4), 23821345107SLorenzo Bianconi }, 23921345107SLorenzo Bianconi .fifo_en = { 24021345107SLorenzo Bianconi .addr = 0x07, 24121345107SLorenzo Bianconi .mask = BIT(7), 24221345107SLorenzo Bianconi }, 24321345107SLorenzo Bianconi .decimator = { 24421345107SLorenzo Bianconi .addr = 0x09, 24521345107SLorenzo Bianconi .mask = GENMASK(5, 3), 24621345107SLorenzo Bianconi }, 24721345107SLorenzo Bianconi }, 248df47710aSLorenzo Bianconi }, 249df47710aSLorenzo Bianconi { 250d068e4a0SLorenzo Bianconi .wai = 0x6a, 2518f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 252d068e4a0SLorenzo Bianconi .id = { 2530b2a3e5fSLorenzo Bianconi [0] = ST_LSM6DSL_ID, 2540b2a3e5fSLorenzo Bianconi [1] = ST_LSM6DSM_ID, 255d068e4a0SLorenzo Bianconi }, 2567ca3ac9eSLorenzo Bianconi .decimator = { 2577ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 2587ca3ac9eSLorenzo Bianconi .addr = 0x08, 2597ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 2607ca3ac9eSLorenzo Bianconi }, 2617ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 2627ca3ac9eSLorenzo Bianconi .addr = 0x08, 2637ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 2647ca3ac9eSLorenzo Bianconi }, 2657ca3ac9eSLorenzo Bianconi }, 26692617c15SLorenzo Bianconi .fifo_ops = { 26792617c15SLorenzo Bianconi .fifo_th = { 26892617c15SLorenzo Bianconi .addr = 0x06, 26992617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 27092617c15SLorenzo Bianconi }, 27192617c15SLorenzo Bianconi .fifo_diff = { 27292617c15SLorenzo Bianconi .addr = 0x3a, 27392617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 27492617c15SLorenzo Bianconi }, 27592617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 27692617c15SLorenzo Bianconi }, 27721345107SLorenzo Bianconi .ts_settings = { 27821345107SLorenzo Bianconi .timer_en = { 27921345107SLorenzo Bianconi .addr = 0x19, 28021345107SLorenzo Bianconi .mask = BIT(5), 28121345107SLorenzo Bianconi }, 28221345107SLorenzo Bianconi .hr_timer = { 28321345107SLorenzo Bianconi .addr = 0x5c, 28421345107SLorenzo Bianconi .mask = BIT(4), 28521345107SLorenzo Bianconi }, 28621345107SLorenzo Bianconi .fifo_en = { 28721345107SLorenzo Bianconi .addr = 0x07, 28821345107SLorenzo Bianconi .mask = BIT(7), 28921345107SLorenzo Bianconi }, 29021345107SLorenzo Bianconi .decimator = { 29121345107SLorenzo Bianconi .addr = 0x09, 29221345107SLorenzo Bianconi .mask = GENMASK(5, 3), 29321345107SLorenzo Bianconi }, 29421345107SLorenzo Bianconi }, 295290a6ce1SLorenzo Bianconi }, 296290a6ce1SLorenzo Bianconi }; 297290a6ce1SLorenzo Bianconi 298290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \ 299290a6ce1SLorenzo Bianconi { \ 300290a6ce1SLorenzo Bianconi .type = chan_type, \ 301290a6ce1SLorenzo Bianconi .address = addr, \ 302290a6ce1SLorenzo Bianconi .modified = 1, \ 303290a6ce1SLorenzo Bianconi .channel2 = mod, \ 304290a6ce1SLorenzo Bianconi .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 305290a6ce1SLorenzo Bianconi BIT(IIO_CHAN_INFO_SCALE), \ 306290a6ce1SLorenzo Bianconi .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 307290a6ce1SLorenzo Bianconi .scan_index = scan_idx, \ 308290a6ce1SLorenzo Bianconi .scan_type = { \ 309290a6ce1SLorenzo Bianconi .sign = 's', \ 310290a6ce1SLorenzo Bianconi .realbits = 16, \ 311290a6ce1SLorenzo Bianconi .storagebits = 16, \ 312290a6ce1SLorenzo Bianconi .endianness = IIO_LE, \ 313290a6ce1SLorenzo Bianconi }, \ 314290a6ce1SLorenzo Bianconi } 315290a6ce1SLorenzo Bianconi 316290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { 317290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR, 318290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 319290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR, 320290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 321290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR, 322290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 323290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 324290a6ce1SLorenzo Bianconi }; 325290a6ce1SLorenzo Bianconi 326290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { 327290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR, 328290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 329290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR, 330290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 331290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR, 332290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 333290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 334290a6ce1SLorenzo Bianconi }; 335290a6ce1SLorenzo Bianconi 336290a6ce1SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id) 337290a6ce1SLorenzo Bianconi { 33851a8b707SLorenzo Bianconi int err, i, j, data; 339290a6ce1SLorenzo Bianconi 340290a6ce1SLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) { 341d068e4a0SLorenzo Bianconi for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) { 342d068e4a0SLorenzo Bianconi if (id == st_lsm6dsx_sensor_settings[i].id[j]) 343d068e4a0SLorenzo Bianconi break; 344d068e4a0SLorenzo Bianconi } 345d068e4a0SLorenzo Bianconi if (j < ST_LSM6DSX_MAX_ID) 346290a6ce1SLorenzo Bianconi break; 347290a6ce1SLorenzo Bianconi } 348290a6ce1SLorenzo Bianconi 349290a6ce1SLorenzo Bianconi if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) { 350290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported hw id [%02x]\n", id); 351290a6ce1SLorenzo Bianconi return -ENODEV; 352290a6ce1SLorenzo Bianconi } 353290a6ce1SLorenzo Bianconi 35451a8b707SLorenzo Bianconi err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data); 355290a6ce1SLorenzo Bianconi if (err < 0) { 356290a6ce1SLorenzo Bianconi dev_err(hw->dev, "failed to read whoami register\n"); 357290a6ce1SLorenzo Bianconi return err; 358290a6ce1SLorenzo Bianconi } 359290a6ce1SLorenzo Bianconi 360290a6ce1SLorenzo Bianconi if (data != st_lsm6dsx_sensor_settings[i].wai) { 361290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported whoami [%02x]\n", data); 362290a6ce1SLorenzo Bianconi return -ENODEV; 363290a6ce1SLorenzo Bianconi } 364290a6ce1SLorenzo Bianconi 365290a6ce1SLorenzo Bianconi hw->settings = &st_lsm6dsx_sensor_settings[i]; 366290a6ce1SLorenzo Bianconi 367290a6ce1SLorenzo Bianconi return 0; 368290a6ce1SLorenzo Bianconi } 369290a6ce1SLorenzo Bianconi 370290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, 371290a6ce1SLorenzo Bianconi u32 gain) 372290a6ce1SLorenzo Bianconi { 37351a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 37451a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 375290a6ce1SLorenzo Bianconi int i, err; 376290a6ce1SLorenzo Bianconi u8 val; 377290a6ce1SLorenzo Bianconi 378290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 37951a8b707SLorenzo Bianconi if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain) 380290a6ce1SLorenzo Bianconi break; 381290a6ce1SLorenzo Bianconi 382290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_FS_LIST_SIZE) 383290a6ce1SLorenzo Bianconi return -EINVAL; 384290a6ce1SLorenzo Bianconi 38551a8b707SLorenzo Bianconi val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val; 38651a8b707SLorenzo Bianconi reg = &st_lsm6dsx_fs_table[sensor->id].reg; 38751a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 38851a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(val, reg->mask)); 389290a6ce1SLorenzo Bianconi if (err < 0) 390290a6ce1SLorenzo Bianconi return err; 391290a6ce1SLorenzo Bianconi 392290a6ce1SLorenzo Bianconi sensor->gain = gain; 393290a6ce1SLorenzo Bianconi 394290a6ce1SLorenzo Bianconi return 0; 395290a6ce1SLorenzo Bianconi } 396290a6ce1SLorenzo Bianconi 3972ccc1503SLorenzo Bianconi static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, 3982ccc1503SLorenzo Bianconi u8 *val) 399290a6ce1SLorenzo Bianconi { 4002ccc1503SLorenzo Bianconi int i; 401290a6ce1SLorenzo Bianconi 402290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 4032ccc1503SLorenzo Bianconi if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr) 404290a6ce1SLorenzo Bianconi break; 405290a6ce1SLorenzo Bianconi 406290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_ODR_LIST_SIZE) 407290a6ce1SLorenzo Bianconi return -EINVAL; 408290a6ce1SLorenzo Bianconi 4092ccc1503SLorenzo Bianconi *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; 410290a6ce1SLorenzo Bianconi 411290a6ce1SLorenzo Bianconi return 0; 412290a6ce1SLorenzo Bianconi } 413290a6ce1SLorenzo Bianconi 4142ccc1503SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr) 4152ccc1503SLorenzo Bianconi { 41651a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 41751a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 4182ccc1503SLorenzo Bianconi int err; 4192ccc1503SLorenzo Bianconi u8 val; 4202ccc1503SLorenzo Bianconi 4212ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, odr, &val); 4222ccc1503SLorenzo Bianconi if (err < 0) 4232ccc1503SLorenzo Bianconi return err; 4242ccc1503SLorenzo Bianconi 42551a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 42651a8b707SLorenzo Bianconi return regmap_update_bits(hw->regmap, reg->addr, reg->mask, 42751a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(val, reg->mask)); 4282ccc1503SLorenzo Bianconi } 4292ccc1503SLorenzo Bianconi 430290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor) 431290a6ce1SLorenzo Bianconi { 432290a6ce1SLorenzo Bianconi int err; 433290a6ce1SLorenzo Bianconi 434290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 435290a6ce1SLorenzo Bianconi if (err < 0) 436290a6ce1SLorenzo Bianconi return err; 437290a6ce1SLorenzo Bianconi 438290a6ce1SLorenzo Bianconi sensor->hw->enable_mask |= BIT(sensor->id); 439290a6ce1SLorenzo Bianconi 440290a6ce1SLorenzo Bianconi return 0; 441290a6ce1SLorenzo Bianconi } 442290a6ce1SLorenzo Bianconi 443290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor) 444290a6ce1SLorenzo Bianconi { 44551a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 44651a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 447290a6ce1SLorenzo Bianconi int err; 448290a6ce1SLorenzo Bianconi 44951a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 45051a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 45151a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 452290a6ce1SLorenzo Bianconi if (err < 0) 453290a6ce1SLorenzo Bianconi return err; 454290a6ce1SLorenzo Bianconi 45551a8b707SLorenzo Bianconi sensor->hw->enable_mask &= ~BIT(sensor->id); 456290a6ce1SLorenzo Bianconi 457290a6ce1SLorenzo Bianconi return 0; 458290a6ce1SLorenzo Bianconi } 459290a6ce1SLorenzo Bianconi 460290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, 461290a6ce1SLorenzo Bianconi u8 addr, int *val) 462290a6ce1SLorenzo Bianconi { 46351a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 464290a6ce1SLorenzo Bianconi int err, delay; 465290a6ce1SLorenzo Bianconi __le16 data; 466290a6ce1SLorenzo Bianconi 467290a6ce1SLorenzo Bianconi err = st_lsm6dsx_sensor_enable(sensor); 468290a6ce1SLorenzo Bianconi if (err < 0) 469290a6ce1SLorenzo Bianconi return err; 470290a6ce1SLorenzo Bianconi 471290a6ce1SLorenzo Bianconi delay = 1000000 / sensor->odr; 472290a6ce1SLorenzo Bianconi usleep_range(delay, 2 * delay); 473290a6ce1SLorenzo Bianconi 47451a8b707SLorenzo Bianconi err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data)); 475290a6ce1SLorenzo Bianconi if (err < 0) 476290a6ce1SLorenzo Bianconi return err; 477290a6ce1SLorenzo Bianconi 478290a6ce1SLorenzo Bianconi st_lsm6dsx_sensor_disable(sensor); 479290a6ce1SLorenzo Bianconi 4807b9ebe42SLorenzo Bianconi *val = (s16)le16_to_cpu(data); 481290a6ce1SLorenzo Bianconi 482290a6ce1SLorenzo Bianconi return IIO_VAL_INT; 483290a6ce1SLorenzo Bianconi } 484290a6ce1SLorenzo Bianconi 485290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, 486290a6ce1SLorenzo Bianconi struct iio_chan_spec const *ch, 487290a6ce1SLorenzo Bianconi int *val, int *val2, long mask) 488290a6ce1SLorenzo Bianconi { 489290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 490290a6ce1SLorenzo Bianconi int ret; 491290a6ce1SLorenzo Bianconi 492290a6ce1SLorenzo Bianconi switch (mask) { 493290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_RAW: 494290a6ce1SLorenzo Bianconi ret = iio_device_claim_direct_mode(iio_dev); 495290a6ce1SLorenzo Bianconi if (ret) 496290a6ce1SLorenzo Bianconi break; 497290a6ce1SLorenzo Bianconi 498290a6ce1SLorenzo Bianconi ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val); 499290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 500290a6ce1SLorenzo Bianconi break; 501290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: 502290a6ce1SLorenzo Bianconi *val = sensor->odr; 503290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT; 504290a6ce1SLorenzo Bianconi break; 505290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 506290a6ce1SLorenzo Bianconi *val = 0; 507290a6ce1SLorenzo Bianconi *val2 = sensor->gain; 508290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT_PLUS_MICRO; 509290a6ce1SLorenzo Bianconi break; 510290a6ce1SLorenzo Bianconi default: 511290a6ce1SLorenzo Bianconi ret = -EINVAL; 512290a6ce1SLorenzo Bianconi break; 513290a6ce1SLorenzo Bianconi } 514290a6ce1SLorenzo Bianconi 515290a6ce1SLorenzo Bianconi return ret; 516290a6ce1SLorenzo Bianconi } 517290a6ce1SLorenzo Bianconi 518290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, 519290a6ce1SLorenzo Bianconi struct iio_chan_spec const *chan, 520290a6ce1SLorenzo Bianconi int val, int val2, long mask) 521290a6ce1SLorenzo Bianconi { 522290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 523290a6ce1SLorenzo Bianconi int err; 524290a6ce1SLorenzo Bianconi 525290a6ce1SLorenzo Bianconi err = iio_device_claim_direct_mode(iio_dev); 526290a6ce1SLorenzo Bianconi if (err) 527290a6ce1SLorenzo Bianconi return err; 528290a6ce1SLorenzo Bianconi 529290a6ce1SLorenzo Bianconi switch (mask) { 530290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 531290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_full_scale(sensor, val2); 532290a6ce1SLorenzo Bianconi break; 5332ccc1503SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: { 5342ccc1503SLorenzo Bianconi u8 data; 5352ccc1503SLorenzo Bianconi 5362ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, val, &data); 5375e3c3e33SLorenzo Bianconi if (!err) 5385e3c3e33SLorenzo Bianconi sensor->odr = val; 539290a6ce1SLorenzo Bianconi break; 5402ccc1503SLorenzo Bianconi } 541290a6ce1SLorenzo Bianconi default: 542290a6ce1SLorenzo Bianconi err = -EINVAL; 543290a6ce1SLorenzo Bianconi break; 544290a6ce1SLorenzo Bianconi } 545290a6ce1SLorenzo Bianconi 546290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 547290a6ce1SLorenzo Bianconi 548290a6ce1SLorenzo Bianconi return err; 549290a6ce1SLorenzo Bianconi } 550290a6ce1SLorenzo Bianconi 551290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val) 552290a6ce1SLorenzo Bianconi { 553290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 554290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 5558f2a88a2SLorenzo Bianconi int err; 556290a6ce1SLorenzo Bianconi 5578f2a88a2SLorenzo Bianconi if (val < 1 || val > hw->settings->max_fifo_size) 558290a6ce1SLorenzo Bianconi return -EINVAL; 559290a6ce1SLorenzo Bianconi 560335eaedcSLorenzo Bianconi mutex_lock(&hw->conf_lock); 561335eaedcSLorenzo Bianconi 562290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_watermark(sensor, val); 563335eaedcSLorenzo Bianconi 564335eaedcSLorenzo Bianconi mutex_unlock(&hw->conf_lock); 565335eaedcSLorenzo Bianconi 566290a6ce1SLorenzo Bianconi if (err < 0) 567290a6ce1SLorenzo Bianconi return err; 568290a6ce1SLorenzo Bianconi 569290a6ce1SLorenzo Bianconi sensor->watermark = val; 570290a6ce1SLorenzo Bianconi 571290a6ce1SLorenzo Bianconi return 0; 572290a6ce1SLorenzo Bianconi } 573290a6ce1SLorenzo Bianconi 574290a6ce1SLorenzo Bianconi static ssize_t 575290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, 576290a6ce1SLorenzo Bianconi struct device_attribute *attr, 577290a6ce1SLorenzo Bianconi char *buf) 578290a6ce1SLorenzo Bianconi { 579290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 580290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 581290a6ce1SLorenzo Bianconi int i, len = 0; 582290a6ce1SLorenzo Bianconi 583290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 584290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", 585290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].odr_avl[i].hz); 586290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 587290a6ce1SLorenzo Bianconi 588290a6ce1SLorenzo Bianconi return len; 589290a6ce1SLorenzo Bianconi } 590290a6ce1SLorenzo Bianconi 591290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, 592290a6ce1SLorenzo Bianconi struct device_attribute *attr, 593290a6ce1SLorenzo Bianconi char *buf) 594290a6ce1SLorenzo Bianconi { 595290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 596290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 597290a6ce1SLorenzo Bianconi int i, len = 0; 598290a6ce1SLorenzo Bianconi 599290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 600290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", 601290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].fs_avl[i].gain); 602290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 603290a6ce1SLorenzo Bianconi 604290a6ce1SLorenzo Bianconi return len; 605290a6ce1SLorenzo Bianconi } 606290a6ce1SLorenzo Bianconi 607290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail); 608290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 609290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 610290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444, 611290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 612290a6ce1SLorenzo Bianconi 613290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = { 614290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 615290a6ce1SLorenzo Bianconi &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 616290a6ce1SLorenzo Bianconi NULL, 617290a6ce1SLorenzo Bianconi }; 618290a6ce1SLorenzo Bianconi 619290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = { 620290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_acc_attributes, 621290a6ce1SLorenzo Bianconi }; 622290a6ce1SLorenzo Bianconi 623290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = { 624290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_acc_attribute_group, 625290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 626290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 627290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 628290a6ce1SLorenzo Bianconi }; 629290a6ce1SLorenzo Bianconi 630290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = { 631290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 632290a6ce1SLorenzo Bianconi &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, 633290a6ce1SLorenzo Bianconi NULL, 634290a6ce1SLorenzo Bianconi }; 635290a6ce1SLorenzo Bianconi 636290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = { 637290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_gyro_attributes, 638290a6ce1SLorenzo Bianconi }; 639290a6ce1SLorenzo Bianconi 640290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = { 641290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_gyro_attribute_group, 642290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 643290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 644290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 645290a6ce1SLorenzo Bianconi }; 646290a6ce1SLorenzo Bianconi 647290a6ce1SLorenzo Bianconi static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; 648290a6ce1SLorenzo Bianconi 649dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) 650dba32904SLorenzo Bianconi { 651dba32904SLorenzo Bianconi struct device_node *np = hw->dev->of_node; 652dba32904SLorenzo Bianconi 653dba32904SLorenzo Bianconi if (!np) 654dba32904SLorenzo Bianconi return -EINVAL; 655dba32904SLorenzo Bianconi 656bf235277SLorenzo Bianconi return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); 657dba32904SLorenzo Bianconi } 658dba32904SLorenzo Bianconi 659dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) 660dba32904SLorenzo Bianconi { 661dba32904SLorenzo Bianconi int err = 0, drdy_pin; 662dba32904SLorenzo Bianconi 663dba32904SLorenzo Bianconi if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) { 664dba32904SLorenzo Bianconi struct st_sensors_platform_data *pdata; 665dba32904SLorenzo Bianconi struct device *dev = hw->dev; 666dba32904SLorenzo Bianconi 667dba32904SLorenzo Bianconi pdata = (struct st_sensors_platform_data *)dev->platform_data; 668dba32904SLorenzo Bianconi drdy_pin = pdata ? pdata->drdy_int_pin : 1; 669dba32904SLorenzo Bianconi } 670dba32904SLorenzo Bianconi 671dba32904SLorenzo Bianconi switch (drdy_pin) { 672dba32904SLorenzo Bianconi case 1: 673dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; 674dba32904SLorenzo Bianconi break; 675dba32904SLorenzo Bianconi case 2: 676dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; 677dba32904SLorenzo Bianconi break; 678dba32904SLorenzo Bianconi default: 679dba32904SLorenzo Bianconi dev_err(hw->dev, "unsupported data ready pin\n"); 680dba32904SLorenzo Bianconi err = -EINVAL; 681dba32904SLorenzo Bianconi break; 682dba32904SLorenzo Bianconi } 683dba32904SLorenzo Bianconi 684dba32904SLorenzo Bianconi return err; 685dba32904SLorenzo Bianconi } 686dba32904SLorenzo Bianconi 68721345107SLorenzo Bianconi static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) 68821345107SLorenzo Bianconi { 68921345107SLorenzo Bianconi const struct st_lsm6dsx_hw_ts_settings *ts_settings; 69021345107SLorenzo Bianconi int err, val; 69121345107SLorenzo Bianconi 69221345107SLorenzo Bianconi ts_settings = &hw->settings->ts_settings; 69321345107SLorenzo Bianconi /* enable hw timestamp generation if necessary */ 69421345107SLorenzo Bianconi if (ts_settings->timer_en.addr) { 69521345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->timer_en.mask); 69621345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 69721345107SLorenzo Bianconi ts_settings->timer_en.addr, 69821345107SLorenzo Bianconi ts_settings->timer_en.mask, val); 69921345107SLorenzo Bianconi if (err < 0) 70021345107SLorenzo Bianconi return err; 70121345107SLorenzo Bianconi } 70221345107SLorenzo Bianconi 70321345107SLorenzo Bianconi /* enable high resolution for hw ts timer if necessary */ 70421345107SLorenzo Bianconi if (ts_settings->hr_timer.addr) { 70521345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->hr_timer.mask); 70621345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 70721345107SLorenzo Bianconi ts_settings->hr_timer.addr, 70821345107SLorenzo Bianconi ts_settings->hr_timer.mask, val); 70921345107SLorenzo Bianconi if (err < 0) 71021345107SLorenzo Bianconi return err; 71121345107SLorenzo Bianconi } 71221345107SLorenzo Bianconi 71321345107SLorenzo Bianconi /* enable ts queueing in FIFO if necessary */ 71421345107SLorenzo Bianconi if (ts_settings->fifo_en.addr) { 71521345107SLorenzo Bianconi val = ST_LSM6DSX_SHIFT_VAL(1, ts_settings->fifo_en.mask); 71621345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, 71721345107SLorenzo Bianconi ts_settings->fifo_en.addr, 71821345107SLorenzo Bianconi ts_settings->fifo_en.mask, val); 71921345107SLorenzo Bianconi if (err < 0) 72021345107SLorenzo Bianconi return err; 72121345107SLorenzo Bianconi } 72221345107SLorenzo Bianconi return 0; 72321345107SLorenzo Bianconi } 72421345107SLorenzo Bianconi 725290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) 726290a6ce1SLorenzo Bianconi { 72751a8b707SLorenzo Bianconi u8 drdy_int_reg; 728290a6ce1SLorenzo Bianconi int err; 729290a6ce1SLorenzo Bianconi 73051a8b707SLorenzo Bianconi err = regmap_write(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, 73151a8b707SLorenzo Bianconi ST_LSM6DSX_REG_RESET_MASK); 732290a6ce1SLorenzo Bianconi if (err < 0) 733290a6ce1SLorenzo Bianconi return err; 734290a6ce1SLorenzo Bianconi 735290a6ce1SLorenzo Bianconi msleep(200); 736290a6ce1SLorenzo Bianconi 737290a6ce1SLorenzo Bianconi /* enable Block Data Update */ 73851a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR, 73951a8b707SLorenzo Bianconi ST_LSM6DSX_REG_BDU_MASK, 74051a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1)); 741290a6ce1SLorenzo Bianconi if (err < 0) 742290a6ce1SLorenzo Bianconi return err; 743290a6ce1SLorenzo Bianconi 744290a6ce1SLorenzo Bianconi /* enable FIFO watermak interrupt */ 745dba32904SLorenzo Bianconi err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); 746290a6ce1SLorenzo Bianconi if (err < 0) 747290a6ce1SLorenzo Bianconi return err; 748290a6ce1SLorenzo Bianconi 74921345107SLorenzo Bianconi err = regmap_update_bits(hw->regmap, drdy_int_reg, 75051a8b707SLorenzo Bianconi ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 75151a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 75251a8b707SLorenzo Bianconi 1)); 75321345107SLorenzo Bianconi if (err < 0) 75421345107SLorenzo Bianconi return err; 75521345107SLorenzo Bianconi 75621345107SLorenzo Bianconi return st_lsm6dsx_init_hw_timer(hw); 757290a6ce1SLorenzo Bianconi } 758290a6ce1SLorenzo Bianconi 759290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, 760510c0106SLorenzo Bianconi enum st_lsm6dsx_sensor_id id, 761510c0106SLorenzo Bianconi const char *name) 762290a6ce1SLorenzo Bianconi { 763290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 764290a6ce1SLorenzo Bianconi struct iio_dev *iio_dev; 765290a6ce1SLorenzo Bianconi 766290a6ce1SLorenzo Bianconi iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); 767290a6ce1SLorenzo Bianconi if (!iio_dev) 768290a6ce1SLorenzo Bianconi return NULL; 769290a6ce1SLorenzo Bianconi 770290a6ce1SLorenzo Bianconi iio_dev->modes = INDIO_DIRECT_MODE; 771290a6ce1SLorenzo Bianconi iio_dev->dev.parent = hw->dev; 772290a6ce1SLorenzo Bianconi iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; 773290a6ce1SLorenzo Bianconi 774290a6ce1SLorenzo Bianconi sensor = iio_priv(iio_dev); 775290a6ce1SLorenzo Bianconi sensor->id = id; 776290a6ce1SLorenzo Bianconi sensor->hw = hw; 777290a6ce1SLorenzo Bianconi sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; 778290a6ce1SLorenzo Bianconi sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; 779290a6ce1SLorenzo Bianconi sensor->watermark = 1; 780290a6ce1SLorenzo Bianconi 781290a6ce1SLorenzo Bianconi switch (id) { 782290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_ACC: 783290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_acc_channels; 784290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); 785290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_acc_info; 786290a6ce1SLorenzo Bianconi 787510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", 788510c0106SLorenzo Bianconi name); 789290a6ce1SLorenzo Bianconi break; 790290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_GYRO: 791290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_gyro_channels; 792290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); 793290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_gyro_info; 794290a6ce1SLorenzo Bianconi 795510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", 796510c0106SLorenzo Bianconi name); 797290a6ce1SLorenzo Bianconi break; 798290a6ce1SLorenzo Bianconi default: 799290a6ce1SLorenzo Bianconi return NULL; 800290a6ce1SLorenzo Bianconi } 801510c0106SLorenzo Bianconi iio_dev->name = sensor->name; 802290a6ce1SLorenzo Bianconi 803290a6ce1SLorenzo Bianconi return iio_dev; 804290a6ce1SLorenzo Bianconi } 805290a6ce1SLorenzo Bianconi 806510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, 80751a8b707SLorenzo Bianconi struct regmap *regmap) 808290a6ce1SLorenzo Bianconi { 809290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw; 810290a6ce1SLorenzo Bianconi int i, err; 811290a6ce1SLorenzo Bianconi 812290a6ce1SLorenzo Bianconi hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 813290a6ce1SLorenzo Bianconi if (!hw) 814290a6ce1SLorenzo Bianconi return -ENOMEM; 815290a6ce1SLorenzo Bianconi 816290a6ce1SLorenzo Bianconi dev_set_drvdata(dev, (void *)hw); 817290a6ce1SLorenzo Bianconi 818290a6ce1SLorenzo Bianconi mutex_init(&hw->fifo_lock); 819335eaedcSLorenzo Bianconi mutex_init(&hw->conf_lock); 820290a6ce1SLorenzo Bianconi 82191a6b841SLorenzo Bianconi hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL); 82291a6b841SLorenzo Bianconi if (!hw->buff) 82391a6b841SLorenzo Bianconi return -ENOMEM; 82491a6b841SLorenzo Bianconi 825290a6ce1SLorenzo Bianconi hw->dev = dev; 826290a6ce1SLorenzo Bianconi hw->irq = irq; 82751a8b707SLorenzo Bianconi hw->regmap = regmap; 828290a6ce1SLorenzo Bianconi 829290a6ce1SLorenzo Bianconi err = st_lsm6dsx_check_whoami(hw, hw_id); 830290a6ce1SLorenzo Bianconi if (err < 0) 831290a6ce1SLorenzo Bianconi return err; 832290a6ce1SLorenzo Bianconi 833290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 834510c0106SLorenzo Bianconi hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name); 835290a6ce1SLorenzo Bianconi if (!hw->iio_devs[i]) 836290a6ce1SLorenzo Bianconi return -ENOMEM; 837290a6ce1SLorenzo Bianconi } 838290a6ce1SLorenzo Bianconi 839290a6ce1SLorenzo Bianconi err = st_lsm6dsx_init_device(hw); 840290a6ce1SLorenzo Bianconi if (err < 0) 841290a6ce1SLorenzo Bianconi return err; 842290a6ce1SLorenzo Bianconi 843290a6ce1SLorenzo Bianconi if (hw->irq > 0) { 844290a6ce1SLorenzo Bianconi err = st_lsm6dsx_fifo_setup(hw); 845290a6ce1SLorenzo Bianconi if (err < 0) 846290a6ce1SLorenzo Bianconi return err; 847290a6ce1SLorenzo Bianconi } 848290a6ce1SLorenzo Bianconi 849290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 850290a6ce1SLorenzo Bianconi err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); 851290a6ce1SLorenzo Bianconi if (err) 852290a6ce1SLorenzo Bianconi return err; 853290a6ce1SLorenzo Bianconi } 854290a6ce1SLorenzo Bianconi 855290a6ce1SLorenzo Bianconi return 0; 856290a6ce1SLorenzo Bianconi } 857290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe); 858290a6ce1SLorenzo Bianconi 8593cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) 860d3f77058SLorenzo Bianconi { 861d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 862d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 86351a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 864d3f77058SLorenzo Bianconi int i, err = 0; 865d3f77058SLorenzo Bianconi 866d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 867d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 868d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 869d3f77058SLorenzo Bianconi continue; 870d3f77058SLorenzo Bianconi 87151a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 87251a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 87351a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 874d3f77058SLorenzo Bianconi if (err < 0) 875d3f77058SLorenzo Bianconi return err; 876d3f77058SLorenzo Bianconi } 877d3f77058SLorenzo Bianconi 878d3f77058SLorenzo Bianconi if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) 879d3f77058SLorenzo Bianconi err = st_lsm6dsx_flush_fifo(hw); 880d3f77058SLorenzo Bianconi 881d3f77058SLorenzo Bianconi return err; 882d3f77058SLorenzo Bianconi } 883d3f77058SLorenzo Bianconi 8843cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev) 885d3f77058SLorenzo Bianconi { 886d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 887d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 888d3f77058SLorenzo Bianconi int i, err = 0; 889d3f77058SLorenzo Bianconi 890d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 891d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 892d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 893d3f77058SLorenzo Bianconi continue; 894d3f77058SLorenzo Bianconi 895d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 896d3f77058SLorenzo Bianconi if (err < 0) 897d3f77058SLorenzo Bianconi return err; 898d3f77058SLorenzo Bianconi } 899d3f77058SLorenzo Bianconi 900d3f77058SLorenzo Bianconi if (hw->enable_mask) 901d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); 902d3f77058SLorenzo Bianconi 903d3f77058SLorenzo Bianconi return err; 904d3f77058SLorenzo Bianconi } 905d3f77058SLorenzo Bianconi 906d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = { 907d3f77058SLorenzo Bianconi SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume) 908d3f77058SLorenzo Bianconi }; 909d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops); 910d3f77058SLorenzo Bianconi 911290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); 912290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); 913290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); 914290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2"); 915