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 }, 184290a6ce1SLorenzo Bianconi }, 185290a6ce1SLorenzo Bianconi { 186df47710aSLorenzo Bianconi .wai = 0x69, 1878f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 188df47710aSLorenzo Bianconi .id = { 189df47710aSLorenzo Bianconi [0] = ST_LSM6DS3H_ID, 190df47710aSLorenzo Bianconi }, 1917ca3ac9eSLorenzo Bianconi .decimator = { 1927ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 1937ca3ac9eSLorenzo Bianconi .addr = 0x08, 1947ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 1957ca3ac9eSLorenzo Bianconi }, 1967ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 1977ca3ac9eSLorenzo Bianconi .addr = 0x08, 1987ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 1997ca3ac9eSLorenzo Bianconi }, 2007ca3ac9eSLorenzo Bianconi }, 20192617c15SLorenzo Bianconi .fifo_ops = { 20292617c15SLorenzo Bianconi .fifo_th = { 20392617c15SLorenzo Bianconi .addr = 0x06, 20492617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 20592617c15SLorenzo Bianconi }, 20692617c15SLorenzo Bianconi .fifo_diff = { 20792617c15SLorenzo Bianconi .addr = 0x3a, 20892617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 20992617c15SLorenzo Bianconi }, 21092617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 21192617c15SLorenzo Bianconi }, 212df47710aSLorenzo Bianconi }, 213df47710aSLorenzo Bianconi { 214d068e4a0SLorenzo Bianconi .wai = 0x6a, 2158f2a88a2SLorenzo Bianconi .max_fifo_size = 682, 216d068e4a0SLorenzo Bianconi .id = { 2170b2a3e5fSLorenzo Bianconi [0] = ST_LSM6DSL_ID, 2180b2a3e5fSLorenzo Bianconi [1] = ST_LSM6DSM_ID, 219d068e4a0SLorenzo Bianconi }, 2207ca3ac9eSLorenzo Bianconi .decimator = { 2217ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 2227ca3ac9eSLorenzo Bianconi .addr = 0x08, 2237ca3ac9eSLorenzo Bianconi .mask = GENMASK(2, 0), 2247ca3ac9eSLorenzo Bianconi }, 2257ca3ac9eSLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 2267ca3ac9eSLorenzo Bianconi .addr = 0x08, 2277ca3ac9eSLorenzo Bianconi .mask = GENMASK(5, 3), 2287ca3ac9eSLorenzo Bianconi }, 2297ca3ac9eSLorenzo Bianconi }, 23092617c15SLorenzo Bianconi .fifo_ops = { 23192617c15SLorenzo Bianconi .fifo_th = { 23292617c15SLorenzo Bianconi .addr = 0x06, 23392617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 23492617c15SLorenzo Bianconi }, 23592617c15SLorenzo Bianconi .fifo_diff = { 23692617c15SLorenzo Bianconi .addr = 0x3a, 23792617c15SLorenzo Bianconi .mask = GENMASK(11, 0), 23892617c15SLorenzo Bianconi }, 23992617c15SLorenzo Bianconi .th_wl = 3, /* 1LSB = 2B */ 24092617c15SLorenzo Bianconi }, 241290a6ce1SLorenzo Bianconi }, 242290a6ce1SLorenzo Bianconi }; 243290a6ce1SLorenzo Bianconi 244290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \ 245290a6ce1SLorenzo Bianconi { \ 246290a6ce1SLorenzo Bianconi .type = chan_type, \ 247290a6ce1SLorenzo Bianconi .address = addr, \ 248290a6ce1SLorenzo Bianconi .modified = 1, \ 249290a6ce1SLorenzo Bianconi .channel2 = mod, \ 250290a6ce1SLorenzo Bianconi .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 251290a6ce1SLorenzo Bianconi BIT(IIO_CHAN_INFO_SCALE), \ 252290a6ce1SLorenzo Bianconi .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 253290a6ce1SLorenzo Bianconi .scan_index = scan_idx, \ 254290a6ce1SLorenzo Bianconi .scan_type = { \ 255290a6ce1SLorenzo Bianconi .sign = 's', \ 256290a6ce1SLorenzo Bianconi .realbits = 16, \ 257290a6ce1SLorenzo Bianconi .storagebits = 16, \ 258290a6ce1SLorenzo Bianconi .endianness = IIO_LE, \ 259290a6ce1SLorenzo Bianconi }, \ 260290a6ce1SLorenzo Bianconi } 261290a6ce1SLorenzo Bianconi 262290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { 263290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR, 264290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 265290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR, 266290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 267290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR, 268290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 269290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 270290a6ce1SLorenzo Bianconi }; 271290a6ce1SLorenzo Bianconi 272290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { 273290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR, 274290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 275290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR, 276290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 277290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR, 278290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 279290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 280290a6ce1SLorenzo Bianconi }; 281290a6ce1SLorenzo Bianconi 282290a6ce1SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id) 283290a6ce1SLorenzo Bianconi { 28451a8b707SLorenzo Bianconi int err, i, j, data; 285290a6ce1SLorenzo Bianconi 286290a6ce1SLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) { 287d068e4a0SLorenzo Bianconi for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) { 288d068e4a0SLorenzo Bianconi if (id == st_lsm6dsx_sensor_settings[i].id[j]) 289d068e4a0SLorenzo Bianconi break; 290d068e4a0SLorenzo Bianconi } 291d068e4a0SLorenzo Bianconi if (j < ST_LSM6DSX_MAX_ID) 292290a6ce1SLorenzo Bianconi break; 293290a6ce1SLorenzo Bianconi } 294290a6ce1SLorenzo Bianconi 295290a6ce1SLorenzo Bianconi if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) { 296290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported hw id [%02x]\n", id); 297290a6ce1SLorenzo Bianconi return -ENODEV; 298290a6ce1SLorenzo Bianconi } 299290a6ce1SLorenzo Bianconi 30051a8b707SLorenzo Bianconi err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data); 301290a6ce1SLorenzo Bianconi if (err < 0) { 302290a6ce1SLorenzo Bianconi dev_err(hw->dev, "failed to read whoami register\n"); 303290a6ce1SLorenzo Bianconi return err; 304290a6ce1SLorenzo Bianconi } 305290a6ce1SLorenzo Bianconi 306290a6ce1SLorenzo Bianconi if (data != st_lsm6dsx_sensor_settings[i].wai) { 307290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported whoami [%02x]\n", data); 308290a6ce1SLorenzo Bianconi return -ENODEV; 309290a6ce1SLorenzo Bianconi } 310290a6ce1SLorenzo Bianconi 311290a6ce1SLorenzo Bianconi hw->settings = &st_lsm6dsx_sensor_settings[i]; 312290a6ce1SLorenzo Bianconi 313290a6ce1SLorenzo Bianconi return 0; 314290a6ce1SLorenzo Bianconi } 315290a6ce1SLorenzo Bianconi 316290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, 317290a6ce1SLorenzo Bianconi u32 gain) 318290a6ce1SLorenzo Bianconi { 31951a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 32051a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 321290a6ce1SLorenzo Bianconi int i, err; 322290a6ce1SLorenzo Bianconi u8 val; 323290a6ce1SLorenzo Bianconi 324290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 32551a8b707SLorenzo Bianconi if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain) 326290a6ce1SLorenzo Bianconi break; 327290a6ce1SLorenzo Bianconi 328290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_FS_LIST_SIZE) 329290a6ce1SLorenzo Bianconi return -EINVAL; 330290a6ce1SLorenzo Bianconi 33151a8b707SLorenzo Bianconi val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val; 33251a8b707SLorenzo Bianconi reg = &st_lsm6dsx_fs_table[sensor->id].reg; 33351a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 33451a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(val, reg->mask)); 335290a6ce1SLorenzo Bianconi if (err < 0) 336290a6ce1SLorenzo Bianconi return err; 337290a6ce1SLorenzo Bianconi 338290a6ce1SLorenzo Bianconi sensor->gain = gain; 339290a6ce1SLorenzo Bianconi 340290a6ce1SLorenzo Bianconi return 0; 341290a6ce1SLorenzo Bianconi } 342290a6ce1SLorenzo Bianconi 3432ccc1503SLorenzo Bianconi static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, 3442ccc1503SLorenzo Bianconi u8 *val) 345290a6ce1SLorenzo Bianconi { 3462ccc1503SLorenzo Bianconi int i; 347290a6ce1SLorenzo Bianconi 348290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 3492ccc1503SLorenzo Bianconi if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr) 350290a6ce1SLorenzo Bianconi break; 351290a6ce1SLorenzo Bianconi 352290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_ODR_LIST_SIZE) 353290a6ce1SLorenzo Bianconi return -EINVAL; 354290a6ce1SLorenzo Bianconi 3552ccc1503SLorenzo Bianconi *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; 356290a6ce1SLorenzo Bianconi 357290a6ce1SLorenzo Bianconi return 0; 358290a6ce1SLorenzo Bianconi } 359290a6ce1SLorenzo Bianconi 3602ccc1503SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr) 3612ccc1503SLorenzo Bianconi { 36251a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 36351a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 3642ccc1503SLorenzo Bianconi int err; 3652ccc1503SLorenzo Bianconi u8 val; 3662ccc1503SLorenzo Bianconi 3672ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, odr, &val); 3682ccc1503SLorenzo Bianconi if (err < 0) 3692ccc1503SLorenzo Bianconi return err; 3702ccc1503SLorenzo Bianconi 37151a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 37251a8b707SLorenzo Bianconi return regmap_update_bits(hw->regmap, reg->addr, reg->mask, 37351a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(val, reg->mask)); 3742ccc1503SLorenzo Bianconi } 3752ccc1503SLorenzo Bianconi 376290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor) 377290a6ce1SLorenzo Bianconi { 378290a6ce1SLorenzo Bianconi int err; 379290a6ce1SLorenzo Bianconi 380290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 381290a6ce1SLorenzo Bianconi if (err < 0) 382290a6ce1SLorenzo Bianconi return err; 383290a6ce1SLorenzo Bianconi 384290a6ce1SLorenzo Bianconi sensor->hw->enable_mask |= BIT(sensor->id); 385290a6ce1SLorenzo Bianconi 386290a6ce1SLorenzo Bianconi return 0; 387290a6ce1SLorenzo Bianconi } 388290a6ce1SLorenzo Bianconi 389290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor) 390290a6ce1SLorenzo Bianconi { 39151a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 39251a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 393290a6ce1SLorenzo Bianconi int err; 394290a6ce1SLorenzo Bianconi 39551a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 39651a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 39751a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 398290a6ce1SLorenzo Bianconi if (err < 0) 399290a6ce1SLorenzo Bianconi return err; 400290a6ce1SLorenzo Bianconi 40151a8b707SLorenzo Bianconi sensor->hw->enable_mask &= ~BIT(sensor->id); 402290a6ce1SLorenzo Bianconi 403290a6ce1SLorenzo Bianconi return 0; 404290a6ce1SLorenzo Bianconi } 405290a6ce1SLorenzo Bianconi 406290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, 407290a6ce1SLorenzo Bianconi u8 addr, int *val) 408290a6ce1SLorenzo Bianconi { 40951a8b707SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 410290a6ce1SLorenzo Bianconi int err, delay; 411290a6ce1SLorenzo Bianconi __le16 data; 412290a6ce1SLorenzo Bianconi 413290a6ce1SLorenzo Bianconi err = st_lsm6dsx_sensor_enable(sensor); 414290a6ce1SLorenzo Bianconi if (err < 0) 415290a6ce1SLorenzo Bianconi return err; 416290a6ce1SLorenzo Bianconi 417290a6ce1SLorenzo Bianconi delay = 1000000 / sensor->odr; 418290a6ce1SLorenzo Bianconi usleep_range(delay, 2 * delay); 419290a6ce1SLorenzo Bianconi 42051a8b707SLorenzo Bianconi err = regmap_bulk_read(hw->regmap, addr, &data, sizeof(data)); 421290a6ce1SLorenzo Bianconi if (err < 0) 422290a6ce1SLorenzo Bianconi return err; 423290a6ce1SLorenzo Bianconi 424290a6ce1SLorenzo Bianconi st_lsm6dsx_sensor_disable(sensor); 425290a6ce1SLorenzo Bianconi 4267b9ebe42SLorenzo Bianconi *val = (s16)le16_to_cpu(data); 427290a6ce1SLorenzo Bianconi 428290a6ce1SLorenzo Bianconi return IIO_VAL_INT; 429290a6ce1SLorenzo Bianconi } 430290a6ce1SLorenzo Bianconi 431290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, 432290a6ce1SLorenzo Bianconi struct iio_chan_spec const *ch, 433290a6ce1SLorenzo Bianconi int *val, int *val2, long mask) 434290a6ce1SLorenzo Bianconi { 435290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 436290a6ce1SLorenzo Bianconi int ret; 437290a6ce1SLorenzo Bianconi 438290a6ce1SLorenzo Bianconi switch (mask) { 439290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_RAW: 440290a6ce1SLorenzo Bianconi ret = iio_device_claim_direct_mode(iio_dev); 441290a6ce1SLorenzo Bianconi if (ret) 442290a6ce1SLorenzo Bianconi break; 443290a6ce1SLorenzo Bianconi 444290a6ce1SLorenzo Bianconi ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val); 445290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 446290a6ce1SLorenzo Bianconi break; 447290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: 448290a6ce1SLorenzo Bianconi *val = sensor->odr; 449290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT; 450290a6ce1SLorenzo Bianconi break; 451290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 452290a6ce1SLorenzo Bianconi *val = 0; 453290a6ce1SLorenzo Bianconi *val2 = sensor->gain; 454290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT_PLUS_MICRO; 455290a6ce1SLorenzo Bianconi break; 456290a6ce1SLorenzo Bianconi default: 457290a6ce1SLorenzo Bianconi ret = -EINVAL; 458290a6ce1SLorenzo Bianconi break; 459290a6ce1SLorenzo Bianconi } 460290a6ce1SLorenzo Bianconi 461290a6ce1SLorenzo Bianconi return ret; 462290a6ce1SLorenzo Bianconi } 463290a6ce1SLorenzo Bianconi 464290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, 465290a6ce1SLorenzo Bianconi struct iio_chan_spec const *chan, 466290a6ce1SLorenzo Bianconi int val, int val2, long mask) 467290a6ce1SLorenzo Bianconi { 468290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 469290a6ce1SLorenzo Bianconi int err; 470290a6ce1SLorenzo Bianconi 471290a6ce1SLorenzo Bianconi err = iio_device_claim_direct_mode(iio_dev); 472290a6ce1SLorenzo Bianconi if (err) 473290a6ce1SLorenzo Bianconi return err; 474290a6ce1SLorenzo Bianconi 475290a6ce1SLorenzo Bianconi switch (mask) { 476290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 477290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_full_scale(sensor, val2); 478290a6ce1SLorenzo Bianconi break; 4792ccc1503SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: { 4802ccc1503SLorenzo Bianconi u8 data; 4812ccc1503SLorenzo Bianconi 4822ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, val, &data); 4835e3c3e33SLorenzo Bianconi if (!err) 4845e3c3e33SLorenzo Bianconi sensor->odr = val; 485290a6ce1SLorenzo Bianconi break; 4862ccc1503SLorenzo Bianconi } 487290a6ce1SLorenzo Bianconi default: 488290a6ce1SLorenzo Bianconi err = -EINVAL; 489290a6ce1SLorenzo Bianconi break; 490290a6ce1SLorenzo Bianconi } 491290a6ce1SLorenzo Bianconi 492290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 493290a6ce1SLorenzo Bianconi 494290a6ce1SLorenzo Bianconi return err; 495290a6ce1SLorenzo Bianconi } 496290a6ce1SLorenzo Bianconi 497290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val) 498290a6ce1SLorenzo Bianconi { 499290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 500290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 5018f2a88a2SLorenzo Bianconi int err; 502290a6ce1SLorenzo Bianconi 5038f2a88a2SLorenzo Bianconi if (val < 1 || val > hw->settings->max_fifo_size) 504290a6ce1SLorenzo Bianconi return -EINVAL; 505290a6ce1SLorenzo Bianconi 506335eaedcSLorenzo Bianconi mutex_lock(&hw->conf_lock); 507335eaedcSLorenzo Bianconi 508290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_watermark(sensor, val); 509335eaedcSLorenzo Bianconi 510335eaedcSLorenzo Bianconi mutex_unlock(&hw->conf_lock); 511335eaedcSLorenzo Bianconi 512290a6ce1SLorenzo Bianconi if (err < 0) 513290a6ce1SLorenzo Bianconi return err; 514290a6ce1SLorenzo Bianconi 515290a6ce1SLorenzo Bianconi sensor->watermark = val; 516290a6ce1SLorenzo Bianconi 517290a6ce1SLorenzo Bianconi return 0; 518290a6ce1SLorenzo Bianconi } 519290a6ce1SLorenzo Bianconi 520290a6ce1SLorenzo Bianconi static ssize_t 521290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, 522290a6ce1SLorenzo Bianconi struct device_attribute *attr, 523290a6ce1SLorenzo Bianconi char *buf) 524290a6ce1SLorenzo Bianconi { 525290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 526290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 527290a6ce1SLorenzo Bianconi int i, len = 0; 528290a6ce1SLorenzo Bianconi 529290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 530290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", 531290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].odr_avl[i].hz); 532290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 533290a6ce1SLorenzo Bianconi 534290a6ce1SLorenzo Bianconi return len; 535290a6ce1SLorenzo Bianconi } 536290a6ce1SLorenzo Bianconi 537290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, 538290a6ce1SLorenzo Bianconi struct device_attribute *attr, 539290a6ce1SLorenzo Bianconi char *buf) 540290a6ce1SLorenzo Bianconi { 541290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 542290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 543290a6ce1SLorenzo Bianconi int i, len = 0; 544290a6ce1SLorenzo Bianconi 545290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 546290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", 547290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].fs_avl[i].gain); 548290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 549290a6ce1SLorenzo Bianconi 550290a6ce1SLorenzo Bianconi return len; 551290a6ce1SLorenzo Bianconi } 552290a6ce1SLorenzo Bianconi 553290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail); 554290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 555290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 556290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444, 557290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 558290a6ce1SLorenzo Bianconi 559290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = { 560290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 561290a6ce1SLorenzo Bianconi &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 562290a6ce1SLorenzo Bianconi NULL, 563290a6ce1SLorenzo Bianconi }; 564290a6ce1SLorenzo Bianconi 565290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = { 566290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_acc_attributes, 567290a6ce1SLorenzo Bianconi }; 568290a6ce1SLorenzo Bianconi 569290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = { 570290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_acc_attribute_group, 571290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 572290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 573290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 574290a6ce1SLorenzo Bianconi }; 575290a6ce1SLorenzo Bianconi 576290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = { 577290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 578290a6ce1SLorenzo Bianconi &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, 579290a6ce1SLorenzo Bianconi NULL, 580290a6ce1SLorenzo Bianconi }; 581290a6ce1SLorenzo Bianconi 582290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = { 583290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_gyro_attributes, 584290a6ce1SLorenzo Bianconi }; 585290a6ce1SLorenzo Bianconi 586290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = { 587290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_gyro_attribute_group, 588290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 589290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 590290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 591290a6ce1SLorenzo Bianconi }; 592290a6ce1SLorenzo Bianconi 593290a6ce1SLorenzo Bianconi static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; 594290a6ce1SLorenzo Bianconi 595dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) 596dba32904SLorenzo Bianconi { 597dba32904SLorenzo Bianconi struct device_node *np = hw->dev->of_node; 598dba32904SLorenzo Bianconi 599dba32904SLorenzo Bianconi if (!np) 600dba32904SLorenzo Bianconi return -EINVAL; 601dba32904SLorenzo Bianconi 602bf235277SLorenzo Bianconi return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); 603dba32904SLorenzo Bianconi } 604dba32904SLorenzo Bianconi 605dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) 606dba32904SLorenzo Bianconi { 607dba32904SLorenzo Bianconi int err = 0, drdy_pin; 608dba32904SLorenzo Bianconi 609dba32904SLorenzo Bianconi if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) { 610dba32904SLorenzo Bianconi struct st_sensors_platform_data *pdata; 611dba32904SLorenzo Bianconi struct device *dev = hw->dev; 612dba32904SLorenzo Bianconi 613dba32904SLorenzo Bianconi pdata = (struct st_sensors_platform_data *)dev->platform_data; 614dba32904SLorenzo Bianconi drdy_pin = pdata ? pdata->drdy_int_pin : 1; 615dba32904SLorenzo Bianconi } 616dba32904SLorenzo Bianconi 617dba32904SLorenzo Bianconi switch (drdy_pin) { 618dba32904SLorenzo Bianconi case 1: 619dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; 620dba32904SLorenzo Bianconi break; 621dba32904SLorenzo Bianconi case 2: 622dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; 623dba32904SLorenzo Bianconi break; 624dba32904SLorenzo Bianconi default: 625dba32904SLorenzo Bianconi dev_err(hw->dev, "unsupported data ready pin\n"); 626dba32904SLorenzo Bianconi err = -EINVAL; 627dba32904SLorenzo Bianconi break; 628dba32904SLorenzo Bianconi } 629dba32904SLorenzo Bianconi 630dba32904SLorenzo Bianconi return err; 631dba32904SLorenzo Bianconi } 632dba32904SLorenzo Bianconi 633290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) 634290a6ce1SLorenzo Bianconi { 63551a8b707SLorenzo Bianconi u8 drdy_int_reg; 636290a6ce1SLorenzo Bianconi int err; 637290a6ce1SLorenzo Bianconi 63851a8b707SLorenzo Bianconi err = regmap_write(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR, 63951a8b707SLorenzo Bianconi ST_LSM6DSX_REG_RESET_MASK); 640290a6ce1SLorenzo Bianconi if (err < 0) 641290a6ce1SLorenzo Bianconi return err; 642290a6ce1SLorenzo Bianconi 643290a6ce1SLorenzo Bianconi msleep(200); 644290a6ce1SLorenzo Bianconi 645290a6ce1SLorenzo Bianconi /* enable Block Data Update */ 64651a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR, 64751a8b707SLorenzo Bianconi ST_LSM6DSX_REG_BDU_MASK, 64851a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1)); 649290a6ce1SLorenzo Bianconi if (err < 0) 650290a6ce1SLorenzo Bianconi return err; 651290a6ce1SLorenzo Bianconi 652290a6ce1SLorenzo Bianconi /* enable FIFO watermak interrupt */ 653dba32904SLorenzo Bianconi err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); 654290a6ce1SLorenzo Bianconi if (err < 0) 655290a6ce1SLorenzo Bianconi return err; 656290a6ce1SLorenzo Bianconi 65751a8b707SLorenzo Bianconi return regmap_update_bits(hw->regmap, drdy_int_reg, 65851a8b707SLorenzo Bianconi ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 65951a8b707SLorenzo Bianconi FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 66051a8b707SLorenzo Bianconi 1)); 661290a6ce1SLorenzo Bianconi } 662290a6ce1SLorenzo Bianconi 663290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, 664510c0106SLorenzo Bianconi enum st_lsm6dsx_sensor_id id, 665510c0106SLorenzo Bianconi const char *name) 666290a6ce1SLorenzo Bianconi { 667290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 668290a6ce1SLorenzo Bianconi struct iio_dev *iio_dev; 669290a6ce1SLorenzo Bianconi 670290a6ce1SLorenzo Bianconi iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); 671290a6ce1SLorenzo Bianconi if (!iio_dev) 672290a6ce1SLorenzo Bianconi return NULL; 673290a6ce1SLorenzo Bianconi 674290a6ce1SLorenzo Bianconi iio_dev->modes = INDIO_DIRECT_MODE; 675290a6ce1SLorenzo Bianconi iio_dev->dev.parent = hw->dev; 676290a6ce1SLorenzo Bianconi iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; 677290a6ce1SLorenzo Bianconi 678290a6ce1SLorenzo Bianconi sensor = iio_priv(iio_dev); 679290a6ce1SLorenzo Bianconi sensor->id = id; 680290a6ce1SLorenzo Bianconi sensor->hw = hw; 681290a6ce1SLorenzo Bianconi sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; 682290a6ce1SLorenzo Bianconi sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; 683290a6ce1SLorenzo Bianconi sensor->watermark = 1; 684290a6ce1SLorenzo Bianconi 685290a6ce1SLorenzo Bianconi switch (id) { 686290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_ACC: 687290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_acc_channels; 688290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); 689290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_acc_info; 690290a6ce1SLorenzo Bianconi 691510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", 692510c0106SLorenzo Bianconi name); 693290a6ce1SLorenzo Bianconi break; 694290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_GYRO: 695290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_gyro_channels; 696290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); 697290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_gyro_info; 698290a6ce1SLorenzo Bianconi 699510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", 700510c0106SLorenzo Bianconi name); 701290a6ce1SLorenzo Bianconi break; 702290a6ce1SLorenzo Bianconi default: 703290a6ce1SLorenzo Bianconi return NULL; 704290a6ce1SLorenzo Bianconi } 705510c0106SLorenzo Bianconi iio_dev->name = sensor->name; 706290a6ce1SLorenzo Bianconi 707290a6ce1SLorenzo Bianconi return iio_dev; 708290a6ce1SLorenzo Bianconi } 709290a6ce1SLorenzo Bianconi 710510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, 71151a8b707SLorenzo Bianconi struct regmap *regmap) 712290a6ce1SLorenzo Bianconi { 713290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw; 714290a6ce1SLorenzo Bianconi int i, err; 715290a6ce1SLorenzo Bianconi 716290a6ce1SLorenzo Bianconi hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 717290a6ce1SLorenzo Bianconi if (!hw) 718290a6ce1SLorenzo Bianconi return -ENOMEM; 719290a6ce1SLorenzo Bianconi 720290a6ce1SLorenzo Bianconi dev_set_drvdata(dev, (void *)hw); 721290a6ce1SLorenzo Bianconi 722290a6ce1SLorenzo Bianconi mutex_init(&hw->fifo_lock); 723335eaedcSLorenzo Bianconi mutex_init(&hw->conf_lock); 724290a6ce1SLorenzo Bianconi 72591a6b841SLorenzo Bianconi hw->buff = devm_kzalloc(dev, ST_LSM6DSX_BUFF_SIZE, GFP_KERNEL); 72691a6b841SLorenzo Bianconi if (!hw->buff) 72791a6b841SLorenzo Bianconi return -ENOMEM; 72891a6b841SLorenzo Bianconi 729290a6ce1SLorenzo Bianconi hw->dev = dev; 730290a6ce1SLorenzo Bianconi hw->irq = irq; 73151a8b707SLorenzo Bianconi hw->regmap = regmap; 732290a6ce1SLorenzo Bianconi 733290a6ce1SLorenzo Bianconi err = st_lsm6dsx_check_whoami(hw, hw_id); 734290a6ce1SLorenzo Bianconi if (err < 0) 735290a6ce1SLorenzo Bianconi return err; 736290a6ce1SLorenzo Bianconi 737290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 738510c0106SLorenzo Bianconi hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name); 739290a6ce1SLorenzo Bianconi if (!hw->iio_devs[i]) 740290a6ce1SLorenzo Bianconi return -ENOMEM; 741290a6ce1SLorenzo Bianconi } 742290a6ce1SLorenzo Bianconi 743290a6ce1SLorenzo Bianconi err = st_lsm6dsx_init_device(hw); 744290a6ce1SLorenzo Bianconi if (err < 0) 745290a6ce1SLorenzo Bianconi return err; 746290a6ce1SLorenzo Bianconi 747290a6ce1SLorenzo Bianconi if (hw->irq > 0) { 748290a6ce1SLorenzo Bianconi err = st_lsm6dsx_fifo_setup(hw); 749290a6ce1SLorenzo Bianconi if (err < 0) 750290a6ce1SLorenzo Bianconi return err; 751290a6ce1SLorenzo Bianconi } 752290a6ce1SLorenzo Bianconi 753290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 754290a6ce1SLorenzo Bianconi err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); 755290a6ce1SLorenzo Bianconi if (err) 756290a6ce1SLorenzo Bianconi return err; 757290a6ce1SLorenzo Bianconi } 758290a6ce1SLorenzo Bianconi 759290a6ce1SLorenzo Bianconi return 0; 760290a6ce1SLorenzo Bianconi } 761290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe); 762290a6ce1SLorenzo Bianconi 7633cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) 764d3f77058SLorenzo Bianconi { 765d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 766d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 76751a8b707SLorenzo Bianconi const struct st_lsm6dsx_reg *reg; 768d3f77058SLorenzo Bianconi int i, err = 0; 769d3f77058SLorenzo Bianconi 770d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 771d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 772d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 773d3f77058SLorenzo Bianconi continue; 774d3f77058SLorenzo Bianconi 77551a8b707SLorenzo Bianconi reg = &st_lsm6dsx_odr_table[sensor->id].reg; 77651a8b707SLorenzo Bianconi err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, 77751a8b707SLorenzo Bianconi ST_LSM6DSX_SHIFT_VAL(0, reg->mask)); 778d3f77058SLorenzo Bianconi if (err < 0) 779d3f77058SLorenzo Bianconi return err; 780d3f77058SLorenzo Bianconi } 781d3f77058SLorenzo Bianconi 782d3f77058SLorenzo Bianconi if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) 783d3f77058SLorenzo Bianconi err = st_lsm6dsx_flush_fifo(hw); 784d3f77058SLorenzo Bianconi 785d3f77058SLorenzo Bianconi return err; 786d3f77058SLorenzo Bianconi } 787d3f77058SLorenzo Bianconi 7883cec4850SLorenzo Bianconi static int __maybe_unused st_lsm6dsx_resume(struct device *dev) 789d3f77058SLorenzo Bianconi { 790d3f77058SLorenzo Bianconi struct st_lsm6dsx_hw *hw = dev_get_drvdata(dev); 791d3f77058SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 792d3f77058SLorenzo Bianconi int i, err = 0; 793d3f77058SLorenzo Bianconi 794d3f77058SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 795d3f77058SLorenzo Bianconi sensor = iio_priv(hw->iio_devs[i]); 796d3f77058SLorenzo Bianconi if (!(hw->enable_mask & BIT(sensor->id))) 797d3f77058SLorenzo Bianconi continue; 798d3f77058SLorenzo Bianconi 799d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 800d3f77058SLorenzo Bianconi if (err < 0) 801d3f77058SLorenzo Bianconi return err; 802d3f77058SLorenzo Bianconi } 803d3f77058SLorenzo Bianconi 804d3f77058SLorenzo Bianconi if (hw->enable_mask) 805d3f77058SLorenzo Bianconi err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT); 806d3f77058SLorenzo Bianconi 807d3f77058SLorenzo Bianconi return err; 808d3f77058SLorenzo Bianconi } 809d3f77058SLorenzo Bianconi 810d3f77058SLorenzo Bianconi const struct dev_pm_ops st_lsm6dsx_pm_ops = { 811d3f77058SLorenzo Bianconi SET_SYSTEM_SLEEP_PM_OPS(st_lsm6dsx_suspend, st_lsm6dsx_resume) 812d3f77058SLorenzo Bianconi }; 813d3f77058SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_pm_ops); 814d3f77058SLorenzo Bianconi 815290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); 816290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); 817290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); 818290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2"); 819