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> 39290a6ce1SLorenzo Bianconi 40dba32904SLorenzo Bianconi #include <linux/platform_data/st_sensors_pdata.h> 41dba32904SLorenzo Bianconi 42290a6ce1SLorenzo Bianconi #include "st_lsm6dsx.h" 43290a6ce1SLorenzo Bianconi 44290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_DEC_MASK GENMASK(2, 0) 45290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_DEC_MASK GENMASK(5, 3) 46290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT1_ADDR 0x0d 47dba32904SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ADDR 0x0e 48290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3) 49290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f 50290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_ADDR 0x12 51290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_RESET_MASK BIT(0) 52290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_ADDR 0x12 53290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_BDU_MASK BIT(6) 54290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13 55290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5) 56290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ROUNDING_ADDR 0x16 57290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ROUNDING_MASK BIT(2) 58290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_LIR_ADDR 0x58 59290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_LIR_MASK BIT(0) 60290a6ce1SLorenzo Bianconi 61290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_ADDR 0x10 62290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_ODR_MASK GENMASK(7, 4) 63290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_ADDR 0x10 64290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_FS_MASK GENMASK(3, 2) 65290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28 66290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a 67290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c 68290a6ce1SLorenzo Bianconi 69290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_ADDR 0x11 70290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_ODR_MASK GENMASK(7, 4) 71290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_ADDR 0x11 72290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_FS_MASK GENMASK(3, 2) 73290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22 74290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24 75290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26 76290a6ce1SLorenzo Bianconi 77290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61) 78290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122) 79290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244) 80290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488) 81290a6ce1SLorenzo Bianconi 82dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_245_GAIN IIO_DEGREE_TO_RAD(8750) 83dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(17500) 84dfebd8d8SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(35000) 85290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000) 86290a6ce1SLorenzo Bianconi 87290a6ce1SLorenzo Bianconi struct st_lsm6dsx_odr { 88290a6ce1SLorenzo Bianconi u16 hz; 89290a6ce1SLorenzo Bianconi u8 val; 90290a6ce1SLorenzo Bianconi }; 91290a6ce1SLorenzo Bianconi 92290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_ODR_LIST_SIZE 6 93290a6ce1SLorenzo Bianconi struct st_lsm6dsx_odr_table_entry { 94290a6ce1SLorenzo Bianconi struct st_lsm6dsx_reg reg; 95290a6ce1SLorenzo Bianconi struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE]; 96290a6ce1SLorenzo Bianconi }; 97290a6ce1SLorenzo Bianconi 98290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = { 99290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 100290a6ce1SLorenzo Bianconi .reg = { 101290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_ACC_ODR_ADDR, 102290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_ACC_ODR_MASK, 103290a6ce1SLorenzo Bianconi }, 104290a6ce1SLorenzo Bianconi .odr_avl[0] = { 13, 0x01 }, 105290a6ce1SLorenzo Bianconi .odr_avl[1] = { 26, 0x02 }, 106290a6ce1SLorenzo Bianconi .odr_avl[2] = { 52, 0x03 }, 107290a6ce1SLorenzo Bianconi .odr_avl[3] = { 104, 0x04 }, 108290a6ce1SLorenzo Bianconi .odr_avl[4] = { 208, 0x05 }, 109290a6ce1SLorenzo Bianconi .odr_avl[5] = { 416, 0x06 }, 110290a6ce1SLorenzo Bianconi }, 111290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 112290a6ce1SLorenzo Bianconi .reg = { 113290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR, 114290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_GYRO_ODR_MASK, 115290a6ce1SLorenzo Bianconi }, 116290a6ce1SLorenzo Bianconi .odr_avl[0] = { 13, 0x01 }, 117290a6ce1SLorenzo Bianconi .odr_avl[1] = { 26, 0x02 }, 118290a6ce1SLorenzo Bianconi .odr_avl[2] = { 52, 0x03 }, 119290a6ce1SLorenzo Bianconi .odr_avl[3] = { 104, 0x04 }, 120290a6ce1SLorenzo Bianconi .odr_avl[4] = { 208, 0x05 }, 121290a6ce1SLorenzo Bianconi .odr_avl[5] = { 416, 0x06 }, 122290a6ce1SLorenzo Bianconi } 123290a6ce1SLorenzo Bianconi }; 124290a6ce1SLorenzo Bianconi 125290a6ce1SLorenzo Bianconi struct st_lsm6dsx_fs { 126290a6ce1SLorenzo Bianconi u32 gain; 127290a6ce1SLorenzo Bianconi u8 val; 128290a6ce1SLorenzo Bianconi }; 129290a6ce1SLorenzo Bianconi 130290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_FS_LIST_SIZE 4 131290a6ce1SLorenzo Bianconi struct st_lsm6dsx_fs_table_entry { 132290a6ce1SLorenzo Bianconi struct st_lsm6dsx_reg reg; 133290a6ce1SLorenzo Bianconi struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE]; 134290a6ce1SLorenzo Bianconi }; 135290a6ce1SLorenzo Bianconi 136290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = { 137290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_ACC] = { 138290a6ce1SLorenzo Bianconi .reg = { 139290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_ACC_FS_ADDR, 140290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_ACC_FS_MASK, 141290a6ce1SLorenzo Bianconi }, 142290a6ce1SLorenzo Bianconi .fs_avl[0] = { ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 }, 143290a6ce1SLorenzo Bianconi .fs_avl[1] = { ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 }, 144290a6ce1SLorenzo Bianconi .fs_avl[2] = { ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 }, 145290a6ce1SLorenzo Bianconi .fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 }, 146290a6ce1SLorenzo Bianconi }, 147290a6ce1SLorenzo Bianconi [ST_LSM6DSX_ID_GYRO] = { 148290a6ce1SLorenzo Bianconi .reg = { 149290a6ce1SLorenzo Bianconi .addr = ST_LSM6DSX_REG_GYRO_FS_ADDR, 150290a6ce1SLorenzo Bianconi .mask = ST_LSM6DSX_REG_GYRO_FS_MASK, 151290a6ce1SLorenzo Bianconi }, 152290a6ce1SLorenzo Bianconi .fs_avl[0] = { ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 }, 153290a6ce1SLorenzo Bianconi .fs_avl[1] = { ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 }, 154290a6ce1SLorenzo Bianconi .fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 }, 155290a6ce1SLorenzo Bianconi .fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 }, 156290a6ce1SLorenzo Bianconi } 157290a6ce1SLorenzo Bianconi }; 158290a6ce1SLorenzo Bianconi 159290a6ce1SLorenzo Bianconi static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { 160290a6ce1SLorenzo Bianconi { 161d068e4a0SLorenzo Bianconi .wai = 0x69, 162d068e4a0SLorenzo Bianconi .max_fifo_size = 8192, 163d068e4a0SLorenzo Bianconi .id = { 164d068e4a0SLorenzo Bianconi [0] = ST_LSM6DS3_ID, 165d068e4a0SLorenzo Bianconi }, 166290a6ce1SLorenzo Bianconi }, 167290a6ce1SLorenzo Bianconi { 168df47710aSLorenzo Bianconi .wai = 0x69, 169df47710aSLorenzo Bianconi .max_fifo_size = 4096, 170df47710aSLorenzo Bianconi .id = { 171df47710aSLorenzo Bianconi [0] = ST_LSM6DS3H_ID, 172df47710aSLorenzo Bianconi }, 173df47710aSLorenzo Bianconi }, 174df47710aSLorenzo Bianconi { 175d068e4a0SLorenzo Bianconi .wai = 0x6a, 176d068e4a0SLorenzo Bianconi .max_fifo_size = 4096, 177d068e4a0SLorenzo Bianconi .id = { 1780b2a3e5fSLorenzo Bianconi [0] = ST_LSM6DSL_ID, 1790b2a3e5fSLorenzo Bianconi [1] = ST_LSM6DSM_ID, 180d068e4a0SLorenzo Bianconi }, 181290a6ce1SLorenzo Bianconi }, 182290a6ce1SLorenzo Bianconi }; 183290a6ce1SLorenzo Bianconi 184290a6ce1SLorenzo Bianconi #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \ 185290a6ce1SLorenzo Bianconi { \ 186290a6ce1SLorenzo Bianconi .type = chan_type, \ 187290a6ce1SLorenzo Bianconi .address = addr, \ 188290a6ce1SLorenzo Bianconi .modified = 1, \ 189290a6ce1SLorenzo Bianconi .channel2 = mod, \ 190290a6ce1SLorenzo Bianconi .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 191290a6ce1SLorenzo Bianconi BIT(IIO_CHAN_INFO_SCALE), \ 192290a6ce1SLorenzo Bianconi .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 193290a6ce1SLorenzo Bianconi .scan_index = scan_idx, \ 194290a6ce1SLorenzo Bianconi .scan_type = { \ 195290a6ce1SLorenzo Bianconi .sign = 's', \ 196290a6ce1SLorenzo Bianconi .realbits = 16, \ 197290a6ce1SLorenzo Bianconi .storagebits = 16, \ 198290a6ce1SLorenzo Bianconi .endianness = IIO_LE, \ 199290a6ce1SLorenzo Bianconi }, \ 200290a6ce1SLorenzo Bianconi } 201290a6ce1SLorenzo Bianconi 202290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { 203290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR, 204290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 205290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR, 206290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 207290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR, 208290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 209290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 210290a6ce1SLorenzo Bianconi }; 211290a6ce1SLorenzo Bianconi 212290a6ce1SLorenzo Bianconi static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = { 213290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR, 214290a6ce1SLorenzo Bianconi IIO_MOD_X, 0), 215290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR, 216290a6ce1SLorenzo Bianconi IIO_MOD_Y, 1), 217290a6ce1SLorenzo Bianconi ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR, 218290a6ce1SLorenzo Bianconi IIO_MOD_Z, 2), 219290a6ce1SLorenzo Bianconi IIO_CHAN_SOFT_TIMESTAMP(3), 220290a6ce1SLorenzo Bianconi }; 221290a6ce1SLorenzo Bianconi 222290a6ce1SLorenzo Bianconi int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask, 223290a6ce1SLorenzo Bianconi u8 val) 224290a6ce1SLorenzo Bianconi { 225290a6ce1SLorenzo Bianconi u8 data; 226290a6ce1SLorenzo Bianconi int err; 227290a6ce1SLorenzo Bianconi 228290a6ce1SLorenzo Bianconi mutex_lock(&hw->lock); 229290a6ce1SLorenzo Bianconi 230290a6ce1SLorenzo Bianconi err = hw->tf->read(hw->dev, addr, sizeof(data), &data); 231290a6ce1SLorenzo Bianconi if (err < 0) { 232290a6ce1SLorenzo Bianconi dev_err(hw->dev, "failed to read %02x register\n", addr); 233290a6ce1SLorenzo Bianconi goto out; 234290a6ce1SLorenzo Bianconi } 235290a6ce1SLorenzo Bianconi 236290a6ce1SLorenzo Bianconi data = (data & ~mask) | ((val << __ffs(mask)) & mask); 237290a6ce1SLorenzo Bianconi 238290a6ce1SLorenzo Bianconi err = hw->tf->write(hw->dev, addr, sizeof(data), &data); 239290a6ce1SLorenzo Bianconi if (err < 0) 240290a6ce1SLorenzo Bianconi dev_err(hw->dev, "failed to write %02x register\n", addr); 241290a6ce1SLorenzo Bianconi 242290a6ce1SLorenzo Bianconi out: 243290a6ce1SLorenzo Bianconi mutex_unlock(&hw->lock); 244290a6ce1SLorenzo Bianconi 245290a6ce1SLorenzo Bianconi return err; 246290a6ce1SLorenzo Bianconi } 247290a6ce1SLorenzo Bianconi 248290a6ce1SLorenzo Bianconi static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id) 249290a6ce1SLorenzo Bianconi { 250d068e4a0SLorenzo Bianconi int err, i, j; 251290a6ce1SLorenzo Bianconi u8 data; 252290a6ce1SLorenzo Bianconi 253290a6ce1SLorenzo Bianconi for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) { 254d068e4a0SLorenzo Bianconi for (j = 0; j < ST_LSM6DSX_MAX_ID; j++) { 255d068e4a0SLorenzo Bianconi if (id == st_lsm6dsx_sensor_settings[i].id[j]) 256d068e4a0SLorenzo Bianconi break; 257d068e4a0SLorenzo Bianconi } 258d068e4a0SLorenzo Bianconi if (j < ST_LSM6DSX_MAX_ID) 259290a6ce1SLorenzo Bianconi break; 260290a6ce1SLorenzo Bianconi } 261290a6ce1SLorenzo Bianconi 262290a6ce1SLorenzo Bianconi if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) { 263290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported hw id [%02x]\n", id); 264290a6ce1SLorenzo Bianconi return -ENODEV; 265290a6ce1SLorenzo Bianconi } 266290a6ce1SLorenzo Bianconi 267290a6ce1SLorenzo Bianconi err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_WHOAMI_ADDR, sizeof(data), 268290a6ce1SLorenzo Bianconi &data); 269290a6ce1SLorenzo Bianconi if (err < 0) { 270290a6ce1SLorenzo Bianconi dev_err(hw->dev, "failed to read whoami register\n"); 271290a6ce1SLorenzo Bianconi return err; 272290a6ce1SLorenzo Bianconi } 273290a6ce1SLorenzo Bianconi 274290a6ce1SLorenzo Bianconi if (data != st_lsm6dsx_sensor_settings[i].wai) { 275290a6ce1SLorenzo Bianconi dev_err(hw->dev, "unsupported whoami [%02x]\n", data); 276290a6ce1SLorenzo Bianconi return -ENODEV; 277290a6ce1SLorenzo Bianconi } 278290a6ce1SLorenzo Bianconi 279290a6ce1SLorenzo Bianconi hw->settings = &st_lsm6dsx_sensor_settings[i]; 280290a6ce1SLorenzo Bianconi 281290a6ce1SLorenzo Bianconi return 0; 282290a6ce1SLorenzo Bianconi } 283290a6ce1SLorenzo Bianconi 284290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor, 285290a6ce1SLorenzo Bianconi u32 gain) 286290a6ce1SLorenzo Bianconi { 287290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 288290a6ce1SLorenzo Bianconi int i, err; 289290a6ce1SLorenzo Bianconi u8 val; 290290a6ce1SLorenzo Bianconi 291290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 292290a6ce1SLorenzo Bianconi if (st_lsm6dsx_fs_table[id].fs_avl[i].gain == gain) 293290a6ce1SLorenzo Bianconi break; 294290a6ce1SLorenzo Bianconi 295290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_FS_LIST_SIZE) 296290a6ce1SLorenzo Bianconi return -EINVAL; 297290a6ce1SLorenzo Bianconi 298290a6ce1SLorenzo Bianconi val = st_lsm6dsx_fs_table[id].fs_avl[i].val; 299290a6ce1SLorenzo Bianconi err = st_lsm6dsx_write_with_mask(sensor->hw, 300290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].reg.addr, 301290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].reg.mask, 302290a6ce1SLorenzo Bianconi val); 303290a6ce1SLorenzo Bianconi if (err < 0) 304290a6ce1SLorenzo Bianconi return err; 305290a6ce1SLorenzo Bianconi 306290a6ce1SLorenzo Bianconi sensor->gain = gain; 307290a6ce1SLorenzo Bianconi 308290a6ce1SLorenzo Bianconi return 0; 309290a6ce1SLorenzo Bianconi } 310290a6ce1SLorenzo Bianconi 3112ccc1503SLorenzo Bianconi static int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, 3122ccc1503SLorenzo Bianconi u8 *val) 313290a6ce1SLorenzo Bianconi { 3142ccc1503SLorenzo Bianconi int i; 315290a6ce1SLorenzo Bianconi 316290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 3172ccc1503SLorenzo Bianconi if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz == odr) 318290a6ce1SLorenzo Bianconi break; 319290a6ce1SLorenzo Bianconi 320290a6ce1SLorenzo Bianconi if (i == ST_LSM6DSX_ODR_LIST_SIZE) 321290a6ce1SLorenzo Bianconi return -EINVAL; 322290a6ce1SLorenzo Bianconi 3232ccc1503SLorenzo Bianconi *val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val; 324290a6ce1SLorenzo Bianconi sensor->odr = odr; 325290a6ce1SLorenzo Bianconi 326290a6ce1SLorenzo Bianconi return 0; 327290a6ce1SLorenzo Bianconi } 328290a6ce1SLorenzo Bianconi 3292ccc1503SLorenzo Bianconi static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr) 3302ccc1503SLorenzo Bianconi { 3312ccc1503SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 3322ccc1503SLorenzo Bianconi int err; 3332ccc1503SLorenzo Bianconi u8 val; 3342ccc1503SLorenzo Bianconi 3352ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, odr, &val); 3362ccc1503SLorenzo Bianconi if (err < 0) 3372ccc1503SLorenzo Bianconi return err; 3382ccc1503SLorenzo Bianconi 3392ccc1503SLorenzo Bianconi return st_lsm6dsx_write_with_mask(sensor->hw, 3402ccc1503SLorenzo Bianconi st_lsm6dsx_odr_table[id].reg.addr, 3412ccc1503SLorenzo Bianconi st_lsm6dsx_odr_table[id].reg.mask, 3422ccc1503SLorenzo Bianconi val); 3432ccc1503SLorenzo Bianconi } 3442ccc1503SLorenzo Bianconi 345290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor) 346290a6ce1SLorenzo Bianconi { 347290a6ce1SLorenzo Bianconi int err; 348290a6ce1SLorenzo Bianconi 349290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_odr(sensor, sensor->odr); 350290a6ce1SLorenzo Bianconi if (err < 0) 351290a6ce1SLorenzo Bianconi return err; 352290a6ce1SLorenzo Bianconi 353290a6ce1SLorenzo Bianconi sensor->hw->enable_mask |= BIT(sensor->id); 354290a6ce1SLorenzo Bianconi 355290a6ce1SLorenzo Bianconi return 0; 356290a6ce1SLorenzo Bianconi } 357290a6ce1SLorenzo Bianconi 358290a6ce1SLorenzo Bianconi int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor) 359290a6ce1SLorenzo Bianconi { 360290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 361290a6ce1SLorenzo Bianconi int err; 362290a6ce1SLorenzo Bianconi 363290a6ce1SLorenzo Bianconi err = st_lsm6dsx_write_with_mask(sensor->hw, 364290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].reg.addr, 365290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].reg.mask, 0); 366290a6ce1SLorenzo Bianconi if (err < 0) 367290a6ce1SLorenzo Bianconi return err; 368290a6ce1SLorenzo Bianconi 369290a6ce1SLorenzo Bianconi sensor->hw->enable_mask &= ~BIT(id); 370290a6ce1SLorenzo Bianconi 371290a6ce1SLorenzo Bianconi return 0; 372290a6ce1SLorenzo Bianconi } 373290a6ce1SLorenzo Bianconi 374290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, 375290a6ce1SLorenzo Bianconi u8 addr, int *val) 376290a6ce1SLorenzo Bianconi { 377290a6ce1SLorenzo Bianconi int err, delay; 378290a6ce1SLorenzo Bianconi __le16 data; 379290a6ce1SLorenzo Bianconi 380290a6ce1SLorenzo Bianconi err = st_lsm6dsx_sensor_enable(sensor); 381290a6ce1SLorenzo Bianconi if (err < 0) 382290a6ce1SLorenzo Bianconi return err; 383290a6ce1SLorenzo Bianconi 384290a6ce1SLorenzo Bianconi delay = 1000000 / sensor->odr; 385290a6ce1SLorenzo Bianconi usleep_range(delay, 2 * delay); 386290a6ce1SLorenzo Bianconi 387290a6ce1SLorenzo Bianconi err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data), 388290a6ce1SLorenzo Bianconi (u8 *)&data); 389290a6ce1SLorenzo Bianconi if (err < 0) 390290a6ce1SLorenzo Bianconi return err; 391290a6ce1SLorenzo Bianconi 392290a6ce1SLorenzo Bianconi st_lsm6dsx_sensor_disable(sensor); 393290a6ce1SLorenzo Bianconi 394290a6ce1SLorenzo Bianconi *val = (s16)data; 395290a6ce1SLorenzo Bianconi 396290a6ce1SLorenzo Bianconi return IIO_VAL_INT; 397290a6ce1SLorenzo Bianconi } 398290a6ce1SLorenzo Bianconi 399290a6ce1SLorenzo Bianconi static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev, 400290a6ce1SLorenzo Bianconi struct iio_chan_spec const *ch, 401290a6ce1SLorenzo Bianconi int *val, int *val2, long mask) 402290a6ce1SLorenzo Bianconi { 403290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 404290a6ce1SLorenzo Bianconi int ret; 405290a6ce1SLorenzo Bianconi 406290a6ce1SLorenzo Bianconi switch (mask) { 407290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_RAW: 408290a6ce1SLorenzo Bianconi ret = iio_device_claim_direct_mode(iio_dev); 409290a6ce1SLorenzo Bianconi if (ret) 410290a6ce1SLorenzo Bianconi break; 411290a6ce1SLorenzo Bianconi 412290a6ce1SLorenzo Bianconi ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val); 413290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 414290a6ce1SLorenzo Bianconi break; 415290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: 416290a6ce1SLorenzo Bianconi *val = sensor->odr; 417290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT; 418290a6ce1SLorenzo Bianconi break; 419290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 420290a6ce1SLorenzo Bianconi *val = 0; 421290a6ce1SLorenzo Bianconi *val2 = sensor->gain; 422290a6ce1SLorenzo Bianconi ret = IIO_VAL_INT_PLUS_MICRO; 423290a6ce1SLorenzo Bianconi break; 424290a6ce1SLorenzo Bianconi default: 425290a6ce1SLorenzo Bianconi ret = -EINVAL; 426290a6ce1SLorenzo Bianconi break; 427290a6ce1SLorenzo Bianconi } 428290a6ce1SLorenzo Bianconi 429290a6ce1SLorenzo Bianconi return ret; 430290a6ce1SLorenzo Bianconi } 431290a6ce1SLorenzo Bianconi 432290a6ce1SLorenzo Bianconi static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, 433290a6ce1SLorenzo Bianconi struct iio_chan_spec const *chan, 434290a6ce1SLorenzo Bianconi int val, int val2, long mask) 435290a6ce1SLorenzo Bianconi { 436290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 437290a6ce1SLorenzo Bianconi int err; 438290a6ce1SLorenzo Bianconi 439290a6ce1SLorenzo Bianconi err = iio_device_claim_direct_mode(iio_dev); 440290a6ce1SLorenzo Bianconi if (err) 441290a6ce1SLorenzo Bianconi return err; 442290a6ce1SLorenzo Bianconi 443290a6ce1SLorenzo Bianconi switch (mask) { 444290a6ce1SLorenzo Bianconi case IIO_CHAN_INFO_SCALE: 445290a6ce1SLorenzo Bianconi err = st_lsm6dsx_set_full_scale(sensor, val2); 446290a6ce1SLorenzo Bianconi break; 4472ccc1503SLorenzo Bianconi case IIO_CHAN_INFO_SAMP_FREQ: { 4482ccc1503SLorenzo Bianconi u8 data; 4492ccc1503SLorenzo Bianconi 4502ccc1503SLorenzo Bianconi err = st_lsm6dsx_check_odr(sensor, val, &data); 451290a6ce1SLorenzo Bianconi break; 4522ccc1503SLorenzo Bianconi } 453290a6ce1SLorenzo Bianconi default: 454290a6ce1SLorenzo Bianconi err = -EINVAL; 455290a6ce1SLorenzo Bianconi break; 456290a6ce1SLorenzo Bianconi } 457290a6ce1SLorenzo Bianconi 458290a6ce1SLorenzo Bianconi iio_device_release_direct_mode(iio_dev); 459290a6ce1SLorenzo Bianconi 460290a6ce1SLorenzo Bianconi return err; 461290a6ce1SLorenzo Bianconi } 462290a6ce1SLorenzo Bianconi 463290a6ce1SLorenzo Bianconi static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val) 464290a6ce1SLorenzo Bianconi { 465290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); 466290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw = sensor->hw; 467290a6ce1SLorenzo Bianconi int err, max_fifo_len; 468290a6ce1SLorenzo Bianconi 469290a6ce1SLorenzo Bianconi max_fifo_len = hw->settings->max_fifo_size / ST_LSM6DSX_SAMPLE_SIZE; 470290a6ce1SLorenzo Bianconi if (val < 1 || val > max_fifo_len) 471290a6ce1SLorenzo Bianconi return -EINVAL; 472290a6ce1SLorenzo Bianconi 473290a6ce1SLorenzo Bianconi err = st_lsm6dsx_update_watermark(sensor, val); 474290a6ce1SLorenzo Bianconi if (err < 0) 475290a6ce1SLorenzo Bianconi return err; 476290a6ce1SLorenzo Bianconi 477290a6ce1SLorenzo Bianconi sensor->watermark = val; 478290a6ce1SLorenzo Bianconi 479290a6ce1SLorenzo Bianconi return 0; 480290a6ce1SLorenzo Bianconi } 481290a6ce1SLorenzo Bianconi 482290a6ce1SLorenzo Bianconi static ssize_t 483290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev, 484290a6ce1SLorenzo Bianconi struct device_attribute *attr, 485290a6ce1SLorenzo Bianconi char *buf) 486290a6ce1SLorenzo Bianconi { 487290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 488290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 489290a6ce1SLorenzo Bianconi int i, len = 0; 490290a6ce1SLorenzo Bianconi 491290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++) 492290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", 493290a6ce1SLorenzo Bianconi st_lsm6dsx_odr_table[id].odr_avl[i].hz); 494290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 495290a6ce1SLorenzo Bianconi 496290a6ce1SLorenzo Bianconi return len; 497290a6ce1SLorenzo Bianconi } 498290a6ce1SLorenzo Bianconi 499290a6ce1SLorenzo Bianconi static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev, 500290a6ce1SLorenzo Bianconi struct device_attribute *attr, 501290a6ce1SLorenzo Bianconi char *buf) 502290a6ce1SLorenzo Bianconi { 503290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev)); 504290a6ce1SLorenzo Bianconi enum st_lsm6dsx_sensor_id id = sensor->id; 505290a6ce1SLorenzo Bianconi int i, len = 0; 506290a6ce1SLorenzo Bianconi 507290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++) 508290a6ce1SLorenzo Bianconi len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", 509290a6ce1SLorenzo Bianconi st_lsm6dsx_fs_table[id].fs_avl[i].gain); 510290a6ce1SLorenzo Bianconi buf[len - 1] = '\n'; 511290a6ce1SLorenzo Bianconi 512290a6ce1SLorenzo Bianconi return len; 513290a6ce1SLorenzo Bianconi } 514290a6ce1SLorenzo Bianconi 515290a6ce1SLorenzo Bianconi static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail); 516290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_accel_scale_available, 0444, 517290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 518290a6ce1SLorenzo Bianconi static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444, 519290a6ce1SLorenzo Bianconi st_lsm6dsx_sysfs_scale_avail, NULL, 0); 520290a6ce1SLorenzo Bianconi 521290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_acc_attributes[] = { 522290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 523290a6ce1SLorenzo Bianconi &iio_dev_attr_in_accel_scale_available.dev_attr.attr, 524290a6ce1SLorenzo Bianconi NULL, 525290a6ce1SLorenzo Bianconi }; 526290a6ce1SLorenzo Bianconi 527290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_acc_attribute_group = { 528290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_acc_attributes, 529290a6ce1SLorenzo Bianconi }; 530290a6ce1SLorenzo Bianconi 531290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_acc_info = { 532290a6ce1SLorenzo Bianconi .driver_module = THIS_MODULE, 533290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_acc_attribute_group, 534290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 535290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 536290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 537290a6ce1SLorenzo Bianconi }; 538290a6ce1SLorenzo Bianconi 539290a6ce1SLorenzo Bianconi static struct attribute *st_lsm6dsx_gyro_attributes[] = { 540290a6ce1SLorenzo Bianconi &iio_dev_attr_sampling_frequency_available.dev_attr.attr, 541290a6ce1SLorenzo Bianconi &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr, 542290a6ce1SLorenzo Bianconi NULL, 543290a6ce1SLorenzo Bianconi }; 544290a6ce1SLorenzo Bianconi 545290a6ce1SLorenzo Bianconi static const struct attribute_group st_lsm6dsx_gyro_attribute_group = { 546290a6ce1SLorenzo Bianconi .attrs = st_lsm6dsx_gyro_attributes, 547290a6ce1SLorenzo Bianconi }; 548290a6ce1SLorenzo Bianconi 549290a6ce1SLorenzo Bianconi static const struct iio_info st_lsm6dsx_gyro_info = { 550290a6ce1SLorenzo Bianconi .driver_module = THIS_MODULE, 551290a6ce1SLorenzo Bianconi .attrs = &st_lsm6dsx_gyro_attribute_group, 552290a6ce1SLorenzo Bianconi .read_raw = st_lsm6dsx_read_raw, 553290a6ce1SLorenzo Bianconi .write_raw = st_lsm6dsx_write_raw, 554290a6ce1SLorenzo Bianconi .hwfifo_set_watermark = st_lsm6dsx_set_watermark, 555290a6ce1SLorenzo Bianconi }; 556290a6ce1SLorenzo Bianconi 557290a6ce1SLorenzo Bianconi static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; 558290a6ce1SLorenzo Bianconi 559dba32904SLorenzo Bianconi static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) 560dba32904SLorenzo Bianconi { 561dba32904SLorenzo Bianconi struct device_node *np = hw->dev->of_node; 562dba32904SLorenzo Bianconi int err; 563dba32904SLorenzo Bianconi 564dba32904SLorenzo Bianconi if (!np) 565dba32904SLorenzo Bianconi return -EINVAL; 566dba32904SLorenzo Bianconi 567dba32904SLorenzo Bianconi err = of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); 568dba32904SLorenzo Bianconi if (err == -ENODATA) { 569dba32904SLorenzo Bianconi /* if the property has not been specified use default value */ 570dba32904SLorenzo Bianconi *drdy_pin = 1; 571dba32904SLorenzo Bianconi err = 0; 572dba32904SLorenzo Bianconi } 573dba32904SLorenzo Bianconi 574dba32904SLorenzo Bianconi return err; 575dba32904SLorenzo Bianconi } 576dba32904SLorenzo Bianconi 577dba32904SLorenzo Bianconi static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) 578dba32904SLorenzo Bianconi { 579dba32904SLorenzo Bianconi int err = 0, drdy_pin; 580dba32904SLorenzo Bianconi 581dba32904SLorenzo Bianconi if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) { 582dba32904SLorenzo Bianconi struct st_sensors_platform_data *pdata; 583dba32904SLorenzo Bianconi struct device *dev = hw->dev; 584dba32904SLorenzo Bianconi 585dba32904SLorenzo Bianconi pdata = (struct st_sensors_platform_data *)dev->platform_data; 586dba32904SLorenzo Bianconi drdy_pin = pdata ? pdata->drdy_int_pin : 1; 587dba32904SLorenzo Bianconi } 588dba32904SLorenzo Bianconi 589dba32904SLorenzo Bianconi switch (drdy_pin) { 590dba32904SLorenzo Bianconi case 1: 591dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR; 592dba32904SLorenzo Bianconi break; 593dba32904SLorenzo Bianconi case 2: 594dba32904SLorenzo Bianconi *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR; 595dba32904SLorenzo Bianconi break; 596dba32904SLorenzo Bianconi default: 597dba32904SLorenzo Bianconi dev_err(hw->dev, "unsupported data ready pin\n"); 598dba32904SLorenzo Bianconi err = -EINVAL; 599dba32904SLorenzo Bianconi break; 600dba32904SLorenzo Bianconi } 601dba32904SLorenzo Bianconi 602dba32904SLorenzo Bianconi return err; 603dba32904SLorenzo Bianconi } 604dba32904SLorenzo Bianconi 605290a6ce1SLorenzo Bianconi static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) 606290a6ce1SLorenzo Bianconi { 607dba32904SLorenzo Bianconi u8 data, drdy_int_reg; 608290a6ce1SLorenzo Bianconi int err; 609290a6ce1SLorenzo Bianconi 610290a6ce1SLorenzo Bianconi data = ST_LSM6DSX_REG_RESET_MASK; 611290a6ce1SLorenzo Bianconi err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_RESET_ADDR, sizeof(data), 612290a6ce1SLorenzo Bianconi &data); 613290a6ce1SLorenzo Bianconi if (err < 0) 614290a6ce1SLorenzo Bianconi return err; 615290a6ce1SLorenzo Bianconi 616290a6ce1SLorenzo Bianconi msleep(200); 617290a6ce1SLorenzo Bianconi 618290a6ce1SLorenzo Bianconi /* latch interrupts */ 619290a6ce1SLorenzo Bianconi err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_LIR_ADDR, 620290a6ce1SLorenzo Bianconi ST_LSM6DSX_REG_LIR_MASK, 1); 621290a6ce1SLorenzo Bianconi if (err < 0) 622290a6ce1SLorenzo Bianconi return err; 623290a6ce1SLorenzo Bianconi 624290a6ce1SLorenzo Bianconi /* enable Block Data Update */ 625290a6ce1SLorenzo Bianconi err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_BDU_ADDR, 626290a6ce1SLorenzo Bianconi ST_LSM6DSX_REG_BDU_MASK, 1); 627290a6ce1SLorenzo Bianconi if (err < 0) 628290a6ce1SLorenzo Bianconi return err; 629290a6ce1SLorenzo Bianconi 630290a6ce1SLorenzo Bianconi err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_ROUNDING_ADDR, 631290a6ce1SLorenzo Bianconi ST_LSM6DSX_REG_ROUNDING_MASK, 1); 632290a6ce1SLorenzo Bianconi if (err < 0) 633290a6ce1SLorenzo Bianconi return err; 634290a6ce1SLorenzo Bianconi 635290a6ce1SLorenzo Bianconi /* enable FIFO watermak interrupt */ 636dba32904SLorenzo Bianconi err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); 637290a6ce1SLorenzo Bianconi if (err < 0) 638290a6ce1SLorenzo Bianconi return err; 639290a6ce1SLorenzo Bianconi 640dba32904SLorenzo Bianconi return st_lsm6dsx_write_with_mask(hw, drdy_int_reg, 641dba32904SLorenzo Bianconi ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 1); 642290a6ce1SLorenzo Bianconi } 643290a6ce1SLorenzo Bianconi 644290a6ce1SLorenzo Bianconi static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, 645510c0106SLorenzo Bianconi enum st_lsm6dsx_sensor_id id, 646510c0106SLorenzo Bianconi const char *name) 647290a6ce1SLorenzo Bianconi { 648290a6ce1SLorenzo Bianconi struct st_lsm6dsx_sensor *sensor; 649290a6ce1SLorenzo Bianconi struct iio_dev *iio_dev; 650290a6ce1SLorenzo Bianconi 651290a6ce1SLorenzo Bianconi iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor)); 652290a6ce1SLorenzo Bianconi if (!iio_dev) 653290a6ce1SLorenzo Bianconi return NULL; 654290a6ce1SLorenzo Bianconi 655290a6ce1SLorenzo Bianconi iio_dev->modes = INDIO_DIRECT_MODE; 656290a6ce1SLorenzo Bianconi iio_dev->dev.parent = hw->dev; 657290a6ce1SLorenzo Bianconi iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks; 658290a6ce1SLorenzo Bianconi 659290a6ce1SLorenzo Bianconi sensor = iio_priv(iio_dev); 660290a6ce1SLorenzo Bianconi sensor->id = id; 661290a6ce1SLorenzo Bianconi sensor->hw = hw; 662290a6ce1SLorenzo Bianconi sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz; 663290a6ce1SLorenzo Bianconi sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain; 664290a6ce1SLorenzo Bianconi sensor->watermark = 1; 665290a6ce1SLorenzo Bianconi 666290a6ce1SLorenzo Bianconi switch (id) { 667290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_ACC: 668290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_acc_channels; 669290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels); 670290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_acc_info; 671290a6ce1SLorenzo Bianconi 672290a6ce1SLorenzo Bianconi sensor->decimator_mask = ST_LSM6DSX_REG_ACC_DEC_MASK; 673510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_accel", 674510c0106SLorenzo Bianconi name); 675290a6ce1SLorenzo Bianconi break; 676290a6ce1SLorenzo Bianconi case ST_LSM6DSX_ID_GYRO: 677290a6ce1SLorenzo Bianconi iio_dev->channels = st_lsm6dsx_gyro_channels; 678290a6ce1SLorenzo Bianconi iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels); 679290a6ce1SLorenzo Bianconi iio_dev->info = &st_lsm6dsx_gyro_info; 680290a6ce1SLorenzo Bianconi 681290a6ce1SLorenzo Bianconi sensor->decimator_mask = ST_LSM6DSX_REG_GYRO_DEC_MASK; 682510c0106SLorenzo Bianconi scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro", 683510c0106SLorenzo Bianconi name); 684290a6ce1SLorenzo Bianconi break; 685290a6ce1SLorenzo Bianconi default: 686290a6ce1SLorenzo Bianconi return NULL; 687290a6ce1SLorenzo Bianconi } 688510c0106SLorenzo Bianconi iio_dev->name = sensor->name; 689290a6ce1SLorenzo Bianconi 690290a6ce1SLorenzo Bianconi return iio_dev; 691290a6ce1SLorenzo Bianconi } 692290a6ce1SLorenzo Bianconi 693510c0106SLorenzo Bianconi int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, const char *name, 694290a6ce1SLorenzo Bianconi const struct st_lsm6dsx_transfer_function *tf_ops) 695290a6ce1SLorenzo Bianconi { 696290a6ce1SLorenzo Bianconi struct st_lsm6dsx_hw *hw; 697290a6ce1SLorenzo Bianconi int i, err; 698290a6ce1SLorenzo Bianconi 699290a6ce1SLorenzo Bianconi hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 700290a6ce1SLorenzo Bianconi if (!hw) 701290a6ce1SLorenzo Bianconi return -ENOMEM; 702290a6ce1SLorenzo Bianconi 703290a6ce1SLorenzo Bianconi dev_set_drvdata(dev, (void *)hw); 704290a6ce1SLorenzo Bianconi 705290a6ce1SLorenzo Bianconi mutex_init(&hw->lock); 706290a6ce1SLorenzo Bianconi mutex_init(&hw->fifo_lock); 707290a6ce1SLorenzo Bianconi 708290a6ce1SLorenzo Bianconi hw->dev = dev; 709290a6ce1SLorenzo Bianconi hw->irq = irq; 710290a6ce1SLorenzo Bianconi hw->tf = tf_ops; 711290a6ce1SLorenzo Bianconi 712290a6ce1SLorenzo Bianconi err = st_lsm6dsx_check_whoami(hw, hw_id); 713290a6ce1SLorenzo Bianconi if (err < 0) 714290a6ce1SLorenzo Bianconi return err; 715290a6ce1SLorenzo Bianconi 716290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 717510c0106SLorenzo Bianconi hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name); 718290a6ce1SLorenzo Bianconi if (!hw->iio_devs[i]) 719290a6ce1SLorenzo Bianconi return -ENOMEM; 720290a6ce1SLorenzo Bianconi } 721290a6ce1SLorenzo Bianconi 722290a6ce1SLorenzo Bianconi err = st_lsm6dsx_init_device(hw); 723290a6ce1SLorenzo Bianconi if (err < 0) 724290a6ce1SLorenzo Bianconi return err; 725290a6ce1SLorenzo Bianconi 726290a6ce1SLorenzo Bianconi if (hw->irq > 0) { 727290a6ce1SLorenzo Bianconi err = st_lsm6dsx_fifo_setup(hw); 728290a6ce1SLorenzo Bianconi if (err < 0) 729290a6ce1SLorenzo Bianconi return err; 730290a6ce1SLorenzo Bianconi } 731290a6ce1SLorenzo Bianconi 732290a6ce1SLorenzo Bianconi for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { 733290a6ce1SLorenzo Bianconi err = devm_iio_device_register(hw->dev, hw->iio_devs[i]); 734290a6ce1SLorenzo Bianconi if (err) 735290a6ce1SLorenzo Bianconi return err; 736290a6ce1SLorenzo Bianconi } 737290a6ce1SLorenzo Bianconi 738290a6ce1SLorenzo Bianconi return 0; 739290a6ce1SLorenzo Bianconi } 740290a6ce1SLorenzo Bianconi EXPORT_SYMBOL(st_lsm6dsx_probe); 741290a6ce1SLorenzo Bianconi 742290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>"); 743290a6ce1SLorenzo Bianconi MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); 744290a6ce1SLorenzo Bianconi MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver"); 745290a6ce1SLorenzo Bianconi MODULE_LICENSE("GPL v2"); 746