553 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3 * STMicroelectronics st_lsm6dsx sensor driver4 *5 * Copyright 2016 STMicroelectronics Inc.6 *7 * Lorenzo Bianconi <lorenzo.bianconi@st.com>8 * Denis Ciocca <denis.ciocca@st.com>9 */10 11#ifndef ST_LSM6DSX_H12#define ST_LSM6DSX_H13 14#include <linux/device.h>15#include <linux/iio/iio.h>16#include <linux/regulator/consumer.h>17 18#define ST_LSM6DS3_DEV_NAME "lsm6ds3"19#define ST_LSM6DS3H_DEV_NAME "lsm6ds3h"20#define ST_LSM6DSL_DEV_NAME "lsm6dsl"21#define ST_LSM6DSM_DEV_NAME "lsm6dsm"22#define ST_ISM330DLC_DEV_NAME "ism330dlc"23#define ST_LSM6DSO_DEV_NAME "lsm6dso"24#define ST_ASM330LHH_DEV_NAME "asm330lhh"25#define ST_LSM6DSOX_DEV_NAME "lsm6dsox"26#define ST_LSM6DSR_DEV_NAME "lsm6dsr"27#define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c"28#define ST_ISM330DHCX_DEV_NAME "ism330dhcx"29#define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu"30#define ST_LSM6DS0_DEV_NAME "lsm6ds0"31#define ST_LSM6DSRX_DEV_NAME "lsm6dsrx"32#define ST_LSM6DST_DEV_NAME "lsm6dst"33#define ST_LSM6DSOP_DEV_NAME "lsm6dsop"34#define ST_ASM330LHHX_DEV_NAME "asm330lhhx"35#define ST_LSM6DSTX_DEV_NAME "lsm6dstx"36#define ST_LSM6DSV_DEV_NAME "lsm6dsv"37#define ST_LSM6DSV16X_DEV_NAME "lsm6dsv16x"38#define ST_LSM6DSO16IS_DEV_NAME "lsm6dso16is"39#define ST_ISM330IS_DEV_NAME "ism330is"40#define ST_ASM330LHB_DEV_NAME "asm330lhb"41#define ST_ASM330LHHXG1_DEV_NAME "asm330lhhxg1"42 43enum st_lsm6dsx_hw_id {44 ST_LSM6DS3_ID = 1,45 ST_LSM6DS3H_ID,46 ST_LSM6DSL_ID,47 ST_LSM6DSM_ID,48 ST_ISM330DLC_ID,49 ST_LSM6DSO_ID,50 ST_ASM330LHH_ID,51 ST_LSM6DSOX_ID,52 ST_LSM6DSR_ID,53 ST_LSM6DS3TRC_ID,54 ST_ISM330DHCX_ID,55 ST_LSM9DS1_ID,56 ST_LSM6DS0_ID,57 ST_LSM6DSRX_ID,58 ST_LSM6DST_ID,59 ST_LSM6DSOP_ID,60 ST_ASM330LHHX_ID,61 ST_LSM6DSTX_ID,62 ST_LSM6DSV_ID,63 ST_LSM6DSV16X_ID,64 ST_LSM6DSO16IS_ID,65 ST_ISM330IS_ID,66 ST_ASM330LHB_ID,67 ST_ASM330LHHXG1_ID,68 ST_LSM6DSX_MAX_ID,69};70 71#define ST_LSM6DSX_BUFF_SIZE 51272#define ST_LSM6DSX_CHAN_SIZE 273#define ST_LSM6DSX_SAMPLE_SIZE 674#define ST_LSM6DSX_TAG_SIZE 175#define ST_LSM6DSX_TAGGED_SAMPLE_SIZE (ST_LSM6DSX_SAMPLE_SIZE + \76 ST_LSM6DSX_TAG_SIZE)77#define ST_LSM6DSX_MAX_WORD_LEN ((32 / ST_LSM6DSX_SAMPLE_SIZE) * \78 ST_LSM6DSX_SAMPLE_SIZE)79#define ST_LSM6DSX_MAX_TAGGED_WORD_LEN ((32 / ST_LSM6DSX_TAGGED_SAMPLE_SIZE) \80 * ST_LSM6DSX_TAGGED_SAMPLE_SIZE)81#define ST_LSM6DSX_SHIFT_VAL(val, mask) (((val) << __ffs(mask)) & (mask))82 83#define ST_LSM6DSX_CHANNEL_ACC(chan_type, addr, mod, scan_idx) \84{ \85 .type = chan_type, \86 .address = addr, \87 .modified = 1, \88 .channel2 = mod, \89 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \90 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \91 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \92 .scan_index = scan_idx, \93 .scan_type = { \94 .sign = 's', \95 .realbits = 16, \96 .storagebits = 16, \97 .endianness = IIO_LE, \98 }, \99 .event_spec = &st_lsm6dsx_event, \100 .ext_info = st_lsm6dsx_ext_info, \101 .num_event_specs = 1, \102}103 104#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \105{ \106 .type = chan_type, \107 .address = addr, \108 .modified = 1, \109 .channel2 = mod, \110 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \111 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \112 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \113 .scan_index = scan_idx, \114 .scan_type = { \115 .sign = 's', \116 .realbits = 16, \117 .storagebits = 16, \118 .endianness = IIO_LE, \119 }, \120 .ext_info = st_lsm6dsx_ext_info, \121}122 123struct st_lsm6dsx_reg {124 u8 addr;125 u8 mask;126};127 128struct st_lsm6dsx_sensor;129struct st_lsm6dsx_hw;130 131struct st_lsm6dsx_odr {132 u32 milli_hz;133 u8 val;134};135 136#define ST_LSM6DSX_ODR_LIST_SIZE 8137struct st_lsm6dsx_odr_table_entry {138 struct st_lsm6dsx_reg reg;139 140 struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];141 int odr_len;142};143 144struct st_lsm6dsx_samples_to_discard {145 struct {146 u32 milli_hz;147 u16 samples;148 } val[ST_LSM6DSX_ODR_LIST_SIZE];149};150 151struct st_lsm6dsx_fs {152 u32 gain;153 u8 val;154};155 156#define ST_LSM6DSX_FS_LIST_SIZE 4157struct st_lsm6dsx_fs_table_entry {158 struct st_lsm6dsx_reg reg;159 160 struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE];161 int fs_len;162};163 164/**165 * struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings166 * @update_fifo: Update FIFO configuration callback.167 * @read_fifo: Read FIFO callback.168 * @fifo_th: FIFO threshold register info (addr + mask).169 * @fifo_diff: FIFO diff status register info (addr + mask).170 * @max_size: Sensor max fifo length in FIFO words.171 * @th_wl: FIFO threshold word length.172 */173struct st_lsm6dsx_fifo_ops {174 int (*update_fifo)(struct st_lsm6dsx_sensor *sensor, bool enable);175 int (*read_fifo)(struct st_lsm6dsx_hw *hw);176 struct {177 u8 addr;178 u16 mask;179 } fifo_th;180 struct {181 u8 addr;182 u16 mask;183 } fifo_diff;184 u16 max_size;185 u8 th_wl;186};187 188/**189 * struct st_lsm6dsx_hw_ts_settings - ST IMU hw timer settings190 * @timer_en: Hw timer enable register info (addr + mask).191 * @hr_timer: Hw timer resolution register info (addr + mask).192 * @fifo_en: Hw timer FIFO enable register info (addr + mask).193 * @decimator: Hw timer FIFO decimator register info (addr + mask).194 * @freq_fine: Difference in % of ODR with respect to the typical.195 */196struct st_lsm6dsx_hw_ts_settings {197 struct st_lsm6dsx_reg timer_en;198 struct st_lsm6dsx_reg hr_timer;199 struct st_lsm6dsx_reg fifo_en;200 struct st_lsm6dsx_reg decimator;201 u8 freq_fine;202};203 204/**205 * struct st_lsm6dsx_shub_settings - ST IMU hw i2c controller settings206 * @page_mux: register page mux info (addr + mask).207 * @master_en: master config register info (addr + mask).208 * @pullup_en: i2c controller pull-up register info (addr + mask).209 * @aux_sens: aux sensor register info (addr + mask).210 * @wr_once: write_once register info (addr + mask).211 * @emb_func: embedded function register info (addr + mask).212 * @num_ext_dev: max number of slave devices.213 * @shub_out: sensor hub first output register info.214 * @slv0_addr: slave0 address in secondary page.215 * @dw_slv0_addr: slave0 write register address in secondary page.216 * @batch_en: Enable/disable FIFO batching.217 * @pause: controller pause value.218 */219struct st_lsm6dsx_shub_settings {220 struct st_lsm6dsx_reg page_mux;221 struct {222 bool sec_page;223 u8 addr;224 u8 mask;225 } master_en;226 struct {227 bool sec_page;228 u8 addr;229 u8 mask;230 } pullup_en;231 struct st_lsm6dsx_reg aux_sens;232 struct st_lsm6dsx_reg wr_once;233 struct st_lsm6dsx_reg emb_func;234 u8 num_ext_dev;235 struct {236 bool sec_page;237 u8 addr;238 } shub_out;239 u8 slv0_addr;240 u8 dw_slv0_addr;241 u8 batch_en;242 u8 pause;243};244 245struct st_lsm6dsx_event_settings {246 struct st_lsm6dsx_reg enable_reg;247 struct st_lsm6dsx_reg wakeup_reg;248 u8 wakeup_src_reg;249 u8 wakeup_src_status_mask;250 u8 wakeup_src_z_mask;251 u8 wakeup_src_y_mask;252 u8 wakeup_src_x_mask;253};254 255enum st_lsm6dsx_ext_sensor_id {256 ST_LSM6DSX_ID_MAGN,257};258 259/**260 * struct st_lsm6dsx_ext_dev_settings - i2c controller slave settings261 * @i2c_addr: I2c slave address list.262 * @wai: Wai address info.263 * @id: external sensor id.264 * @odr_table: Output data rate of the sensor [Hz].265 * @fs_table: Configured sensor sensitivity table depending on full scale.266 * @temp_comp: Temperature compensation register info (addr + mask).267 * @pwr_table: Power on register info (addr + mask).268 * @off_canc: Offset cancellation register info (addr + mask).269 * @bdu: Block data update register info (addr + mask).270 * @out: Output register info.271 */272struct st_lsm6dsx_ext_dev_settings {273 u8 i2c_addr[2];274 struct {275 u8 addr;276 u8 val;277 } wai;278 enum st_lsm6dsx_ext_sensor_id id;279 struct st_lsm6dsx_odr_table_entry odr_table;280 struct st_lsm6dsx_fs_table_entry fs_table;281 struct st_lsm6dsx_reg temp_comp;282 struct {283 struct st_lsm6dsx_reg reg;284 u8 off_val;285 u8 on_val;286 } pwr_table;287 struct st_lsm6dsx_reg off_canc;288 struct st_lsm6dsx_reg bdu;289 struct {290 u8 addr;291 u8 len;292 } out;293};294 295/**296 * struct st_lsm6dsx_settings - ST IMU sensor settings297 * @reset: register address for reset.298 * @boot: register address for boot.299 * @bdu: register address for Block Data Update.300 * @id: List of hw id/device name supported by the driver configuration.301 * @channels: IIO channels supported by the device.302 * @irq_config: interrupts related registers.303 * @drdy_mask: register info for data-ready mask (addr + mask).304 * @odr_table: Hw sensors odr table (Hz + val).305 * @samples_to_discard: Number of samples to discard for filters settling time.306 * @fs_table: Hw sensors gain table (gain + val).307 * @decimator: List of decimator register info (addr + mask).308 * @batch: List of FIFO batching register info (addr + mask).309 * @fifo_ops: Sensor hw FIFO parameters.310 * @ts_settings: Hw timer related settings.311 * @shub_settings: i2c controller related settings.312 */313struct st_lsm6dsx_settings {314 struct st_lsm6dsx_reg reset;315 struct st_lsm6dsx_reg boot;316 struct st_lsm6dsx_reg bdu;317 struct {318 enum st_lsm6dsx_hw_id hw_id;319 const char *name;320 u8 wai;321 } id[ST_LSM6DSX_MAX_ID];322 struct {323 const struct iio_chan_spec *chan;324 int len;325 } channels[2];326 struct {327 struct st_lsm6dsx_reg irq1;328 struct st_lsm6dsx_reg irq2;329 struct st_lsm6dsx_reg irq1_func;330 struct st_lsm6dsx_reg irq2_func;331 struct st_lsm6dsx_reg lir;332 struct st_lsm6dsx_reg clear_on_read;333 struct st_lsm6dsx_reg hla;334 struct st_lsm6dsx_reg od;335 } irq_config;336 struct st_lsm6dsx_reg drdy_mask;337 struct st_lsm6dsx_odr_table_entry odr_table[2];338 struct st_lsm6dsx_samples_to_discard samples_to_discard[2];339 struct st_lsm6dsx_fs_table_entry fs_table[2];340 struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];341 struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];342 struct st_lsm6dsx_fifo_ops fifo_ops;343 struct st_lsm6dsx_hw_ts_settings ts_settings;344 struct st_lsm6dsx_shub_settings shub_settings;345 struct st_lsm6dsx_event_settings event_settings;346};347 348enum st_lsm6dsx_sensor_id {349 ST_LSM6DSX_ID_GYRO,350 ST_LSM6DSX_ID_ACC,351 ST_LSM6DSX_ID_EXT0,352 ST_LSM6DSX_ID_EXT1,353 ST_LSM6DSX_ID_EXT2,354 ST_LSM6DSX_ID_MAX,355};356 357enum st_lsm6dsx_fifo_mode {358 ST_LSM6DSX_FIFO_BYPASS = 0x0,359 ST_LSM6DSX_FIFO_CONT = 0x6,360};361 362/**363 * struct st_lsm6dsx_sensor - ST IMU sensor instance364 * @name: Sensor name.365 * @id: Sensor identifier.366 * @hw: Pointer to instance of struct st_lsm6dsx_hw.367 * @gain: Configured sensor sensitivity.368 * @odr: Output data rate of the sensor [Hz].369 * @samples_to_discard: Number of samples to discard for filters settling time.370 * @watermark: Sensor watermark level.371 * @decimator: Sensor decimation factor.372 * @sip: Number of samples in a given pattern.373 * @ts_ref: Sensor timestamp reference for hw one.374 * @ext_info: Sensor settings if it is connected to i2c controller375 */376struct st_lsm6dsx_sensor {377 char name[32];378 enum st_lsm6dsx_sensor_id id;379 struct st_lsm6dsx_hw *hw;380 381 u32 gain;382 u32 odr;383 384 u16 samples_to_discard;385 u16 watermark;386 u8 decimator;387 u8 sip;388 s64 ts_ref;389 390 struct {391 const struct st_lsm6dsx_ext_dev_settings *settings;392 u32 slv_odr;393 u8 addr;394 } ext_info;395};396 397/**398 * struct st_lsm6dsx_hw - ST IMU MEMS hw instance399 * @dev: Pointer to instance of struct device (I2C or SPI).400 * @regmap: Register map of the device.401 * @irq: Device interrupt line (I2C or SPI).402 * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.403 * @conf_lock: Mutex to prevent concurrent FIFO configuration update.404 * @page_lock: Mutex to prevent concurrent memory page configuration.405 * @suspend_mask: Suspended sensor bitmask.406 * @enable_mask: Enabled sensor bitmask.407 * @fifo_mask: Enabled hw FIFO bitmask.408 * @ts_gain: Hw timestamp rate after internal calibration.409 * @ts_sip: Total number of timestamp samples in a given pattern.410 * @sip: Total number of samples (acc/gyro/ts) in a given pattern.411 * @buff: Device read buffer.412 * @irq_routing: pointer to interrupt routing configuration.413 * @event_threshold: wakeup event threshold.414 * @enable_event: enabled event bitmask.415 * @iio_devs: Pointers to acc/gyro iio_dev instances.416 * @settings: Pointer to the specific sensor settings in use.417 * @orientation: sensor chip orientation relative to main hardware.418 * @scan: Temporary buffers used to align data before iio_push_to_buffers()419 */420struct st_lsm6dsx_hw {421 struct device *dev;422 struct regmap *regmap;423 int irq;424 425 struct mutex fifo_lock;426 struct mutex conf_lock;427 struct mutex page_lock;428 429 u8 suspend_mask;430 u8 enable_mask;431 u8 fifo_mask;432 s64 ts_gain;433 u8 ts_sip;434 u8 sip;435 436 const struct st_lsm6dsx_reg *irq_routing;437 u8 event_threshold;438 u8 enable_event;439 440 u8 *buff;441 442 struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];443 444 const struct st_lsm6dsx_settings *settings;445 446 struct iio_mount_matrix orientation;447 /* Ensure natural alignment of buffer elements */448 struct {449 __le16 channels[3];450 s64 ts __aligned(8);451 } scan[ST_LSM6DSX_ID_MAX];452};453 454static __maybe_unused const struct iio_event_spec st_lsm6dsx_event = {455 .type = IIO_EV_TYPE_THRESH,456 .dir = IIO_EV_DIR_EITHER,457 .mask_separate = BIT(IIO_EV_INFO_VALUE) |458 BIT(IIO_EV_INFO_ENABLE)459};460 461static __maybe_unused const unsigned long st_lsm6dsx_available_scan_masks[] = {462 0x7, 0x0,463};464 465extern const struct dev_pm_ops st_lsm6dsx_pm_ops;466 467int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,468 struct regmap *regmap);469int st_lsm6dsx_sensor_set_enable(struct st_lsm6dsx_sensor *sensor,470 bool enable);471int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);472int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val);473int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,474 u16 watermark);475int st_lsm6dsx_update_fifo(struct st_lsm6dsx_sensor *sensor, bool enable);476int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw);477int st_lsm6dsx_resume_fifo(struct st_lsm6dsx_hw *hw);478int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw);479int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw);480int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u32 odr, u8 *val);481int st_lsm6dsx_shub_probe(struct st_lsm6dsx_hw *hw, const char *name);482int st_lsm6dsx_shub_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable);483int st_lsm6dsx_shub_read_output(struct st_lsm6dsx_hw *hw, u8 *data, int len);484int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable);485 486static inline int487st_lsm6dsx_update_bits_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,488 unsigned int mask, unsigned int val)489{490 int err;491 492 mutex_lock(&hw->page_lock);493 err = regmap_update_bits(hw->regmap, addr, mask, val);494 mutex_unlock(&hw->page_lock);495 496 return err;497}498 499static inline int500st_lsm6dsx_read_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,501 void *val, unsigned int len)502{503 int err;504 505 mutex_lock(&hw->page_lock);506 err = regmap_bulk_read(hw->regmap, addr, val, len);507 mutex_unlock(&hw->page_lock);508 509 return err;510}511 512static inline int513st_lsm6dsx_write_locked(struct st_lsm6dsx_hw *hw, unsigned int addr,514 unsigned int val)515{516 int err;517 518 mutex_lock(&hw->page_lock);519 err = regmap_write(hw->regmap, addr, val);520 mutex_unlock(&hw->page_lock);521 522 return err;523}524 525static inline const struct iio_mount_matrix *526st_lsm6dsx_get_mount_matrix(const struct iio_dev *iio_dev,527 const struct iio_chan_spec *chan)528{529 struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);530 struct st_lsm6dsx_hw *hw = sensor->hw;531 532 return &hw->orientation;533}534 535static inline int536st_lsm6dsx_device_set_enable(struct st_lsm6dsx_sensor *sensor, bool enable)537{538 if (sensor->id == ST_LSM6DSX_ID_EXT0 ||539 sensor->id == ST_LSM6DSX_ID_EXT1 ||540 sensor->id == ST_LSM6DSX_ID_EXT2)541 return st_lsm6dsx_shub_set_enable(sensor, enable);542 543 return st_lsm6dsx_sensor_set_enable(sensor, enable);544}545 546static const547struct iio_chan_spec_ext_info __maybe_unused st_lsm6dsx_ext_info[] = {548 IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, st_lsm6dsx_get_mount_matrix),549 { }550};551 552#endif /* ST_LSM6DSX_H */553