You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
465 lines
14 KiB
465 lines
14 KiB
/*
|
|
* STMicroelectronics st_asm330lhh sensor driver
|
|
*
|
|
* Copyright 2020 STMicroelectronics Inc.
|
|
*
|
|
* Lorenzo Bianconi <lorenzo.bianconi@st.com>
|
|
*
|
|
* Licensed under the GPL-2.
|
|
*/
|
|
|
|
#ifndef ST_ASM330LHH_H
|
|
#define ST_ASM330LHH_H
|
|
|
|
#include <linux/device.h>
|
|
#include <linux/iio/iio.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/input.h>
|
|
#include <linux/ktime.h>
|
|
#include <linux/slab.h>
|
|
|
|
#define ST_ASM330LHH_REVISION "2.0.1"
|
|
#define ST_ASM330LHH_PATCH "4"
|
|
|
|
#define ST_ASM330LHH_VERSION "v" \
|
|
ST_ASM330LHH_REVISION \
|
|
"-" \
|
|
ST_ASM330LHH_PATCH
|
|
|
|
#define ST_ASM330LHH_MAX_ODR 833
|
|
#define ST_ASM330LHH_ODR_LIST_SIZE 8
|
|
#define ST_ASM330LHH_ODR_EXPAND(odr, uodr) ((odr * 1000000) + uodr)
|
|
|
|
#define ST_ASM330LHH_DEV_NAME "asm330lhh"
|
|
|
|
#define ST_ASM330LHH_DEFAULT_XL_FS_INDEX 2
|
|
#define ST_ASM330LHH_DEFAULT_XL_ODR_INDEX 1
|
|
#define ST_ASM330LHH_DEFAULT_G_FS_INDEX 3
|
|
#define ST_ASM330LHH_DEFAULT_G_ODR_INDEX 1
|
|
#define ST_ASM330LHH_DEFAULT_T_FS_INDEX 0
|
|
#define ST_ASM330LHH_DEFAULT_T_ODR_INDEX 1
|
|
|
|
#define ST_ASM330LHH_REG_FIFO_CTRL1_ADDR 0x07
|
|
#define ST_ASM330LHH_REG_FIFO_CTRL2_ADDR 0x08
|
|
#define ST_ASM330LHH_REG_FIFO_WTM_MASK GENMASK(8, 0)
|
|
#define ST_ASM330LHH_REG_FIFO_WTM8_MASK BIT(0)
|
|
#define ST_ASM330LHH_REG_FIFO_STATUS_DIFF GENMASK(9, 0)
|
|
|
|
#define ST_ASM330LHH_REG_FIFO_CTRL3_ADDR 0x09
|
|
#define ST_ASM330LHH_REG_BDR_XL_MASK GENMASK(3, 0)
|
|
#define ST_ASM330LHH_REG_BDR_GY_MASK GENMASK(7, 4)
|
|
|
|
#define ST_ASM330LHH_REG_FIFO_CTRL4_ADDR 0x0a
|
|
#define ST_ASM330LHH_REG_FIFO_MODE_MASK GENMASK(2, 0)
|
|
#define ST_ASM330LHH_REG_DEC_TS_MASK GENMASK(7, 6)
|
|
#define ST_ASM330LHH_REG_ODR_T_BATCH_MASK GENMASK(5, 4)
|
|
|
|
#define ST_ASM330LHH_REG_INT1_CTRL_ADDR 0x0d
|
|
#define ST_ASM330LHH_REG_INT2_CTRL_ADDR 0x0e
|
|
#define ST_ASM330LHH_REG_INT_FIFO_TH_MASK BIT(3)
|
|
|
|
#define ST_ASM330LHH_REG_WHOAMI_ADDR 0x0f
|
|
#define ST_ASM330LHH_WHOAMI_VAL 0x6b
|
|
|
|
#define ST_ASM330LHH_CTRL1_XL_ADDR 0x10
|
|
#define ST_ASM330LHH_CTRL2_G_ADDR 0x11
|
|
|
|
#define ST_ASM330LHH_REG_CTRL3_C_ADDR 0x12
|
|
#define ST_ASM330LHH_REG_SW_RESET_MASK BIT(0)
|
|
#define ST_ASM330LHH_REG_PP_OD_MASK BIT(4)
|
|
#define ST_ASM330LHH_REG_H_LACTIVE_MASK BIT(5)
|
|
#define ST_ASM330LHH_REG_BDU_MASK BIT(6)
|
|
#define ST_ASM330LHH_REG_BOOT_MASK BIT(7)
|
|
|
|
#define ST_ASM330LHH_REG_CTRL4_C_ADDR 0x13
|
|
#define ST_ASM330LHH_REG_DRDY_MASK BIT(3)
|
|
|
|
#define ST_ASM330LHH_REG_CTRL5_C_ADDR 0x14
|
|
#define ST_ASM330LHH_REG_ROUNDING_MASK GENMASK(6, 5)
|
|
|
|
#define ST_ASM330LHH_REG_CTRL9_XL_ADDR 0x18
|
|
#define ST_ASM330LHH_REG_DEVICE_CONF_MASK BIT(1)
|
|
|
|
#define ST_ASM330LHH_REG_CTRL10_C_ADDR 0x19
|
|
#define ST_ASM330LHH_REG_TIMESTAMP_EN_MASK BIT(5)
|
|
|
|
#define ST_ASM330LHH_REG_STATUS_ADDR 0x1e
|
|
#define ST_ASM330LHH_REG_STATUS_TDA BIT(2)
|
|
|
|
#define ST_ASM330LHH_REG_OUT_TEMP_L_ADDR 0x20
|
|
|
|
#define ST_ASM330LHH_REG_OUTX_L_A_ADDR 0x28
|
|
#define ST_ASM330LHH_REG_OUTY_L_A_ADDR 0x2a
|
|
#define ST_ASM330LHH_REG_OUTZ_L_A_ADDR 0x2c
|
|
|
|
#define ST_ASM330LHH_REG_OUTX_L_G_ADDR 0x22
|
|
#define ST_ASM330LHH_REG_OUTY_L_G_ADDR 0x24
|
|
#define ST_ASM330LHH_REG_OUTZ_L_G_ADDR 0x26
|
|
|
|
#define ST_ASM330LHH_REG_TAP_CFG0_ADDR 0x56
|
|
#define ST_ASM330LHH_REG_LIR_MASK BIT(0)
|
|
|
|
#define ST_ASM330LHH_REG_THS_6D_ADDR 0x59
|
|
#define ST_ASM330LHH_SIXD_THS_MASK GENMASK(6, 5)
|
|
|
|
#define ST_ASM330LHH_REG_WAKE_UP_THS_ADDR 0x5b
|
|
#define ST_ASM330LHH_WAKE_UP_THS_MASK GENMASK(5, 0)
|
|
|
|
#define ST_ASM330LHH_REG_WAKE_UP_DUR_ADDR 0x5c
|
|
#define ST_ASM330LHH_WAKE_UP_DUR_MASK GENMASK(6, 5)
|
|
|
|
#define ST_ASM330LHH_REG_FREE_FALL_ADDR 0x5d
|
|
#define ST_ASM330LHH_FF_THS_MASK GENMASK(2, 0)
|
|
|
|
#define ST_ASM330LHH_INTERNAL_FREQ_FINE 0x63
|
|
|
|
/* Timestamp Tick 25us/LSB */
|
|
#define ST_ASM330LHH_TS_DELTA_NS 25000ULL
|
|
|
|
/* Define Custom events for FIFO flush */
|
|
#define CUSTOM_IIO_EV_DIR_FIFO_EMPTY (IIO_EV_DIR_NONE + 1)
|
|
#define CUSTOM_IIO_EV_DIR_FIFO_DATA (IIO_EV_DIR_NONE + 2)
|
|
#define CUSTOM_IIO_EV_TYPE_FIFO_FLUSH (IIO_EV_TYPE_CHANGE + 1)
|
|
|
|
/* Temperature in uC */
|
|
#define ST_ASM330LHH_TEMP_GAIN 256
|
|
#define ST_ASM330LHH_TEMP_FS_GAIN (1000000 / \
|
|
ST_ASM330LHH_TEMP_GAIN)
|
|
#define ST_ASM330LHH_TEMP_OFFSET 6400
|
|
|
|
/* FIFO simple size and depth */
|
|
#define ST_ASM330LHH_SAMPLE_SIZE 6
|
|
#define ST_ASM330LHH_TS_SAMPLE_SIZE 4
|
|
#define ST_ASM330LHH_TAG_SIZE 1
|
|
#define ST_ASM330LHH_FIFO_SAMPLE_SIZE (ST_ASM330LHH_SAMPLE_SIZE + \
|
|
ST_ASM330LHH_TAG_SIZE)
|
|
#define ST_ASM330LHH_MAX_FIFO_DEPTH 416
|
|
|
|
#define ST_ASM330LHH_DATA_CHANNEL(chan_type, addr, mod, ch2, scan_idx, \
|
|
rb, sb, sg) \
|
|
{ \
|
|
.type = chan_type, \
|
|
.address = addr, \
|
|
.modified = mod, \
|
|
.channel2 = ch2, \
|
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
|
BIT(IIO_CHAN_INFO_SCALE), \
|
|
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
|
.scan_index = scan_idx, \
|
|
.scan_type = { \
|
|
.sign = sg, \
|
|
.realbits = rb, \
|
|
.storagebits = sb, \
|
|
.endianness = IIO_LE, \
|
|
}, \
|
|
}
|
|
|
|
static const struct iio_event_spec st_asm330lhh_flush_event = {
|
|
.type = CUSTOM_IIO_EV_TYPE_FIFO_FLUSH,
|
|
.dir = IIO_EV_DIR_EITHER,
|
|
};
|
|
|
|
#define ST_ASM330LHH_EVENT_CHANNEL(ctype, etype) \
|
|
{ \
|
|
.type = ctype, \
|
|
.modified = 0, \
|
|
.scan_index = -1, \
|
|
.indexed = -1, \
|
|
.event_spec = &st_asm330lhh_flush_event, \
|
|
.num_event_specs = 1, \
|
|
}
|
|
|
|
#define ST_ASM330LHH_RX_MAX_LENGTH 64
|
|
#define ST_ASM330LHH_TX_MAX_LENGTH 16
|
|
|
|
#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING
|
|
#define ASM_MAXSAMPLE 4000
|
|
#define G_MAX 23920640
|
|
struct asm_sample {
|
|
int xyz[3];
|
|
unsigned int tsec;
|
|
unsigned long long tnsec;
|
|
};
|
|
#endif
|
|
|
|
struct st_asm330lhh_transfer_buffer {
|
|
u8 rx_buf[ST_ASM330LHH_RX_MAX_LENGTH];
|
|
u8 tx_buf[ST_ASM330LHH_TX_MAX_LENGTH] ____cacheline_aligned;
|
|
};
|
|
|
|
struct st_asm330lhh_transfer_function {
|
|
int (*read)(struct device *dev, u8 addr, int len, u8 *data);
|
|
int (*write)(struct device *dev, u8 addr, int len, const u8 *data);
|
|
};
|
|
|
|
/**
|
|
* struct st_asm330lhh_reg - Generic sensor register description (addr + mask)
|
|
* @addr: Address of register.
|
|
* @mask: Bitmask register for proper usage.
|
|
*/
|
|
struct st_asm330lhh_reg {
|
|
u8 addr;
|
|
u8 mask;
|
|
};
|
|
|
|
/**
|
|
* struct st_asm330lhh_odr - Single ODR entry
|
|
* @hz: Most significant part of the sensor ODR (Hz).
|
|
* @uhz: Less significant part of the sensor ODR (micro Hz).
|
|
* @val: ODR register value.
|
|
* @batch_val: Batching ODR register value.
|
|
*/
|
|
struct st_asm330lhh_odr {
|
|
u16 hz;
|
|
u32 uhz;
|
|
u8 val;
|
|
u8 batch_val;
|
|
};
|
|
|
|
/**
|
|
* struct st_asm330lhh_odr_table_entry - Sensor ODR table
|
|
* @size: Size of ODR table.
|
|
* @reg: ODR register.
|
|
* @batching_reg: ODR register for batching on fifo.
|
|
* @odr_avl: Array of supported ODR value.
|
|
*/
|
|
struct st_asm330lhh_odr_table_entry {
|
|
u8 size;
|
|
struct st_asm330lhh_reg reg;
|
|
struct st_asm330lhh_reg batching_reg;
|
|
struct st_asm330lhh_odr odr_avl[ST_ASM330LHH_ODR_LIST_SIZE];
|
|
};
|
|
|
|
/**
|
|
* struct st_asm330lhh_fs - Full Scale sensor table entry
|
|
* @reg: Register description for FS settings.
|
|
* @gain: Sensor sensitivity (mdps/LSB, mg/LSB and uC/LSB).
|
|
* @val: FS register value.
|
|
*/
|
|
struct st_asm330lhh_fs {
|
|
struct st_asm330lhh_reg reg;
|
|
u32 gain;
|
|
u8 val;
|
|
};
|
|
|
|
#define ST_ASM330LHH_FS_LIST_SIZE 6
|
|
#define ST_ASM330LHH_FS_ACC_LIST_SIZE 4
|
|
#define ST_ASM330LHH_FS_GYRO_LIST_SIZE 6
|
|
#define ST_ASM330LHH_FS_TEMP_LIST_SIZE 1
|
|
|
|
/**
|
|
* struct st_asm330lhh_fs_table_entry - Full Scale sensor table
|
|
* @size: Full Scale sensor table size.
|
|
* @fs_avl: Full Scale list entries.
|
|
*/
|
|
struct st_asm330lhh_fs_table_entry {
|
|
u8 size;
|
|
struct st_asm330lhh_fs fs_avl[ST_ASM330LHH_FS_LIST_SIZE];
|
|
};
|
|
|
|
#define ST_ASM330LHH_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61)
|
|
#define ST_ASM330LHH_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122)
|
|
#define ST_ASM330LHH_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244)
|
|
#define ST_ASM330LHH_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488)
|
|
|
|
#define ST_ASM330LHH_GYRO_FS_125_GAIN IIO_DEGREE_TO_RAD(4375)
|
|
#define ST_ASM330LHH_GYRO_FS_250_GAIN IIO_DEGREE_TO_RAD(8750)
|
|
#define ST_ASM330LHH_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(17500)
|
|
#define ST_ASM330LHH_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(35000)
|
|
#define ST_ASM330LHH_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000)
|
|
#define ST_ASM330LHH_GYRO_FS_4000_GAIN IIO_DEGREE_TO_RAD(140000)
|
|
|
|
enum st_asm330lhh_sensor_id {
|
|
ST_ASM330LHH_ID_GYRO = 0,
|
|
ST_ASM330LHH_ID_ACC,
|
|
ST_ASM330LHH_ID_TEMP,
|
|
ST_ASM330LHH_ID_MAX,
|
|
};
|
|
|
|
enum st_asm330lhh_fifo_mode {
|
|
ST_ASM330LHH_FIFO_BYPASS = 0x0,
|
|
ST_ASM330LHH_FIFO_CONT = 0x6,
|
|
};
|
|
|
|
enum {
|
|
ST_ASM330LHH_HW_FLUSH,
|
|
ST_ASM330LHH_HW_OPERATIONAL,
|
|
};
|
|
|
|
/**
|
|
* struct st_asm330lhh_sensor - ST IMU sensor instance
|
|
* @id: Sensor identifier.
|
|
* @hw: Pointer to instance of struct st_asm330lhh_hw.
|
|
* @gain: Configured sensor sensitivity.
|
|
* @odr: Output data rate of the sensor [Hz].
|
|
* @watermark: Sensor watermark level.
|
|
* @last_fifo_timestamp: Store last sample timestamp in FIFO, used by flush
|
|
*/
|
|
struct st_asm330lhh_sensor {
|
|
enum st_asm330lhh_sensor_id id;
|
|
struct st_asm330lhh_hw *hw;
|
|
struct iio_trigger *trig;
|
|
|
|
u32 gain;
|
|
u32 offset;
|
|
|
|
__le16 old_data;
|
|
|
|
int odr;
|
|
int uodr;
|
|
|
|
u16 max_watermark;
|
|
u16 watermark;
|
|
s64 last_fifo_timestamp;
|
|
#ifdef CONFIG_ENABLE_ASM_ACC_GYRO_BUFFERING
|
|
bool read_boot_sample;
|
|
int bufsample_cnt;
|
|
bool buffer_asm_samples;
|
|
struct kmem_cache *asm_cachepool;
|
|
struct asm_sample *asm_samplist[ASM_MAXSAMPLE];
|
|
ktime_t timestamp;
|
|
int max_buffer_time;
|
|
struct input_dev *buf_dev;
|
|
int report_evt_cnt;
|
|
struct mutex sensor_buff;
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* struct st_asm330lhh_hw - ST IMU MEMS hw instance
|
|
* @dev: Pointer to instance of struct device (I2C or SPI).
|
|
* @irq: Device interrupt line (I2C or SPI).
|
|
* @lock: Mutex to protect read and write operations.
|
|
* @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
|
|
* @page_lock: Mutex to prevent concurrent memory page configuration.
|
|
* @fifo_mode: FIFO operating mode supported by the device.
|
|
* @state: hw operational state.
|
|
* @enable_mask: Enabled sensor bitmask.
|
|
* @ts_offset: Hw timestamp offset.
|
|
* @hw_ts: Latest hw timestamp from the sensor.
|
|
* @ts: Latest timestamp from irq handler.
|
|
* @delta_ts: Delta time between two consecutive interrupts.
|
|
* @ts_delta_ns: Calibrate delta time tick.
|
|
* @hw_ts: Latest hw timestamp from the sensor.
|
|
* @val_ts_old: Hold hw timestamp for timer rollover.
|
|
* @hw_ts_high: Save MSB hw timestamp.
|
|
* @tsample: Timestamp for each sensor sample.
|
|
* @delta_ts: Delta time between two consecutive interrupts.
|
|
* @ts: Latest timestamp from irq handler.
|
|
* @odr_table_entry: Sensors ODR table.
|
|
* @iio_devs: Pointers to acc/gyro iio_dev instances.
|
|
* @tf: Transfer function structure used by I/O operations.
|
|
* @tb: Transfer buffers used by SPI I/O operations.
|
|
*/
|
|
struct st_asm330lhh_hw {
|
|
struct device *dev;
|
|
int irq;
|
|
int int_pin;
|
|
|
|
struct mutex lock;
|
|
struct mutex fifo_lock;
|
|
struct mutex page_lock;
|
|
|
|
enum st_asm330lhh_fifo_mode fifo_mode;
|
|
unsigned long state;
|
|
u32 enable_mask;
|
|
|
|
s64 ts_offset;
|
|
u64 ts_delta_ns;
|
|
s64 hw_ts;
|
|
u32 val_ts_old;
|
|
u32 hw_ts_high;
|
|
s64 tsample;
|
|
s64 delta_ts;
|
|
s64 ts;
|
|
const struct st_asm330lhh_odr_table_entry *odr_table_entry;
|
|
struct iio_dev *iio_devs[ST_ASM330LHH_ID_MAX];
|
|
|
|
const struct st_asm330lhh_transfer_function *tf;
|
|
struct st_asm330lhh_transfer_buffer tb;
|
|
struct regulator *vdd;
|
|
struct regulator *vio;
|
|
struct iio_mount_matrix orientation;
|
|
int enable_gpio;
|
|
bool asm330_hrtimer;
|
|
struct hrtimer st_asm330lhh_hrtimer;
|
|
};
|
|
|
|
extern const struct dev_pm_ops st_asm330lhh_pm_ops;
|
|
|
|
static inline int st_asm330lhh_read_atomic(struct st_asm330lhh_hw *hw, u8 addr,
|
|
int len, u8 *data)
|
|
{
|
|
int err;
|
|
|
|
mutex_lock(&hw->page_lock);
|
|
err = hw->tf->read(hw->dev, addr, len, data);
|
|
mutex_unlock(&hw->page_lock);
|
|
|
|
return err;
|
|
}
|
|
|
|
static inline int st_asm330lhh_write_atomic(struct st_asm330lhh_hw *hw, u8 addr,
|
|
int len, u8 *data)
|
|
{
|
|
int err;
|
|
|
|
mutex_lock(&hw->page_lock);
|
|
err = hw->tf->write(hw->dev, addr, len, data);
|
|
mutex_unlock(&hw->page_lock);
|
|
|
|
return err;
|
|
}
|
|
|
|
int __st_asm330lhh_write_with_mask(struct st_asm330lhh_hw *hw, u8 addr, u8 mask,
|
|
u8 val);
|
|
static inline int st_asm330lhh_write_with_mask(struct st_asm330lhh_hw *hw,
|
|
u8 addr, u8 mask, u8 val)
|
|
{
|
|
int err;
|
|
|
|
mutex_lock(&hw->page_lock);
|
|
err = __st_asm330lhh_write_with_mask(hw, addr, mask, val);
|
|
mutex_unlock(&hw->page_lock);
|
|
|
|
return err;
|
|
}
|
|
|
|
static inline bool st_asm330lhh_is_fifo_enabled(struct st_asm330lhh_hw *hw)
|
|
{
|
|
return hw->enable_mask & (BIT(ST_ASM330LHH_ID_GYRO) |
|
|
BIT(ST_ASM330LHH_ID_ACC));
|
|
}
|
|
|
|
int st_asm330lhh_probe(struct device *dev, int irq,
|
|
const struct st_asm330lhh_transfer_function *tf_ops);
|
|
int st_asm330lhh_sensor_set_enable(struct st_asm330lhh_sensor *sensor,
|
|
bool enable);
|
|
int st_asm330lhh_buffers_setup(struct st_asm330lhh_hw *hw);
|
|
int st_asm330lhh_get_batch_val(struct st_asm330lhh_sensor *sensor, int odr,
|
|
int uodr, u8 *val);
|
|
int st_asm330lhh_update_watermark(struct st_asm330lhh_sensor *sensor,
|
|
u16 watermark);
|
|
ssize_t st_asm330lhh_flush_fifo(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t size);
|
|
ssize_t st_asm330lhh_get_max_watermark(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
ssize_t st_asm330lhh_get_watermark(struct device *dev,
|
|
struct device_attribute *attr, char *buf);
|
|
ssize_t st_asm330lhh_set_watermark(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf, size_t size);
|
|
int st_asm330lhh_suspend_fifo(struct st_asm330lhh_hw *hw);
|
|
int st_asm330lhh_set_fifo_mode(struct st_asm330lhh_hw *hw,
|
|
enum st_asm330lhh_fifo_mode fifo_mode);
|
|
int __st_asm330lhh_set_sensor_batching_odr(struct st_asm330lhh_sensor *sensor,
|
|
bool enable);
|
|
int st_asm330lhh_update_batching(struct iio_dev *iio_dev, bool enable);
|
|
int st_asm330lhh_reset_hwts(struct st_asm330lhh_hw *hw);
|
|
int st_asm330lhh_update_fifo(struct iio_dev *iio_dev, bool enable);
|
|
int asm330_check_acc_gyro_early_buff_enable_flag(
|
|
struct st_asm330lhh_sensor *sensor);
|
|
void st_asm330lhh_set_cpu_idle_state(bool value);
|
|
void st_asm330lhh_hrtimer_reset(struct st_asm330lhh_hw *hw, s64 irq_delta_ts);
|
|
#endif /* ST_ASM330LHH_H */
|
|
|