android13/kernel-5.10/drivers/iio/imu/st_lsm6dsm/st_lsm6dsm.h

393 lines
12 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* STMicroelectronics lsm6dsm driver
*
* MEMS Software Solutions Team
*
* Copyright 2016 STMicroelectronics Inc.
*/
#ifndef ST_LSM6DSM_H
#define ST_LSM6DSM_H
#include <linux/types.h>
#include <linux/iio/trigger.h>
#include <linux/version.h>
#include "stm_iio_types.h"
#if KERNEL_VERSION(5, 19, 0) <= LINUX_VERSION_CODE
#include <linux/iio/iio-opaque.h>
#endif /* LINUX_VERSION_CODE */
#ifdef CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT
#include <linux/i2c.h>
#endif /* CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT */
#define LSM6DSM_DEV_NAME "lsm6dsm"
#define LSM6DSL_DEV_NAME "lsm6dsl"
#define LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c"
enum st_mask_id {
ST_MASK_ID_ACCEL = 0,
ST_MASK_ID_GYRO,
ST_MASK_ID_SIGN_MOTION,
ST_MASK_ID_STEP_COUNTER,
ST_MASK_ID_STEP_DETECTOR,
ST_MASK_ID_TILT,
ST_MASK_ID_WTILT,
ST_MASK_ID_TAP,
ST_MASK_ID_TAP_TAP,
ST_MASK_ID_EXT0,
ST_MASK_ID_HW_PEDOMETER,
ST_MASK_ID_SENSOR_HUB,
ST_MASK_ID_DIGITAL_FUNC,
ST_MASK_ID_SENSOR_HUB_ASYNC_OP,
};
#define ST_INDIO_DEV_NUM 9
#define ST_LSM6DSM_TX_MAX_LENGTH 12
#define ST_LSM6DSM_RX_MAX_LENGTH 4097
#define ST_LSM6DSM_BYTE_FOR_CHANNEL 2
#define ST_LSM6DSM_BYTE_FOR_WRIST_TILT 1
#define ST_LSM6DSM_FIFO_ELEMENT_LEN_BYTE 6
#define ST_LSM6DSM_MAX_FIFO_SIZE 4096
#define ST_LSM6DSM_MAX_FIFO_THRESHOLD 546
#define ST_LSM6DSM_MAX_FIFO_LENGHT (ST_LSM6DSM_MAX_FIFO_SIZE / \
ST_LSM6DSM_FIFO_ELEMENT_LEN_BYTE)
#define ST_LSM6DSM_SELFTEST_NA_MS "na"
#define ST_LSM6DSM_SELFTEST_FAIL_MS "fail"
#define ST_LSM6DSM_SELFTEST_PASS_MS "pass"
#define ST_LSM6DSM_WAKE_UP_SENSORS (BIT(ST_MASK_ID_SIGN_MOTION) | \
BIT(ST_MASK_ID_TILT) | BIT(ST_MASK_ID_WTILT))
#ifdef CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT
#define ST_LSM6DSM_NUM_CLIENTS 1
#else /* CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT */
#define ST_LSM6DSM_NUM_CLIENTS 0
#endif /* CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT */
#define ST_LSM6DSM_LSM_CHANNELS(device_type, modif, index, mod, \
endian, sbits, rbits, addr, s) \
{ \
.type = device_type, \
.modified = modif, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.scan_index = index, \
.channel2 = mod, \
.address = addr, \
.scan_type = { \
.sign = s, \
.realbits = rbits, \
.shift = sbits - rbits, \
.storagebits = sbits, \
.endianness = endian, \
}, \
}
extern const struct iio_event_spec lsm6dsm_fifo_flush_event;
#define ST_LSM6DSM_FLUSH_CHANNEL(device_type) \
{ \
.type = device_type, \
.modified = 0, \
.scan_index = -1, \
.indexed = -1, \
.event_spec = &lsm6dsm_fifo_flush_event,\
.num_event_specs = 1, \
}
#define ST_LSM6DSM_HWFIFO_ENABLED() \
IIO_DEVICE_ATTR(hwfifo_enabled, S_IWUSR | S_IRUGO, \
st_lsm6dsm_sysfs_get_hwfifo_enabled,\
st_lsm6dsm_sysfs_set_hwfifo_enabled, 0);
#define ST_LSM6DSM_HWFIFO_WATERMARK() \
IIO_DEVICE_ATTR(hwfifo_watermark, S_IWUSR | S_IRUGO, \
st_lsm6dsm_sysfs_get_hwfifo_watermark,\
st_lsm6dsm_sysfs_set_hwfifo_watermark, 0);
#define ST_LSM6DSM_HWFIFO_WATERMARK_MIN() \
IIO_DEVICE_ATTR(hwfifo_watermark_min, S_IRUGO, \
st_lsm6dsm_sysfs_get_hwfifo_watermark_min, NULL, 0);
#define ST_LSM6DSM_HWFIFO_WATERMARK_MAX() \
IIO_DEVICE_ATTR(hwfifo_watermark_max, S_IRUGO, \
st_lsm6dsm_sysfs_get_hwfifo_watermark_max, NULL, 0);
#define ST_LSM6DSM_HWFIFO_FLUSH() \
IIO_DEVICE_ATTR(hwfifo_flush, S_IWUSR, NULL, \
st_lsm6dsm_sysfs_flush_fifo, 0);
enum fifo_mode {
BYPASS = 0,
CONTINUOS,
};
struct st_lsm6dsm_transfer_buffer {
struct mutex buf_lock;
u8 rx_buf[ST_LSM6DSM_RX_MAX_LENGTH];
u8 tx_buf[ST_LSM6DSM_TX_MAX_LENGTH] ____cacheline_aligned;
};
struct lsm6dsm_out_decimation {
short decimator;
short num_samples;
};
struct lsm6dsm_fifo_output {
u8 sip;
int64_t deltatime;
int64_t deltatime_default;
int64_t timestamp;
int64_t timestamp_p;
short decimator;
short num_samples;
bool initialized;
};
/* struct lsm6dsm_data - common data for i2c or spi driver instance
* @name: pointer to the device name (i2c name or spi modalias).
* @enable_digfunc_mask: mask used to enable/disable hw digital functions.
* @enable_pedometer_mask: mask used to enable/disable hw pedometer function.
* @enable_sensorhub_mask: mask used to enable/disable sensor-hub feature.
* @irq_enable_fifo_mask: mask used to enable/disable fifo irq.
* @irq_enable_accel_ext_mask: mask used to enable/disable accel irq.
* @hw_odr: physical sensor odr expressed in Hz.
* @v_odr: requested sensor odr by userspace expressed in Hz.
* @hwfifo_enabled: is hwfifo enabled?
* @hwfifo_decimator: hwfifo decimator factor.
* @hwfifo_watermark: hwfifo watermark value.
* @samples_to_discard: samples to discard due to ODR switch.
* @nofifo_decimation: output status when fifo is disabled.
* @fifo_output: output status when fifo is enabled.
* @sensors_enabled: sensors enabled mask.
* @sensors_use_fifo: sensors use fifo mask.
* @accel_odr_dependency: odr dependency: accel, sensor-hub, dig-func.
* @accel_on: accel is going to be enabled during fifo odr switch?
* @magn_on: magn is going to be enabled during fifo odr switch?
* @odr_lock: mutex to avoid race condition during odr switch.
* @reset_steps: do I need to reset number of steps?
* @fifo_data: fifo data.
* @gyro_selftest_status: gyroscope selftest result.
* @accel_selftest_status: accelerometer selftest result.
* @irq: irq number.
* @timestamp: timestamp value from boot process.
* @module_id: identify iio devices of the same sensor module.
*/
struct lsm6dsm_data {
const char *name;
u16 enable_digfunc_mask;
u16 enable_pedometer_mask;
#ifdef CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT
u16 enable_sensorhub_mask;
#endif /* CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT */
u16 irq_enable_fifo_mask;
u16 irq_enable_accel_ext_mask;
unsigned int hw_odr[ST_INDIO_DEV_NUM + 1];
unsigned int v_odr[ST_INDIO_DEV_NUM + 1];
unsigned int trigger_odr;
bool hwfifo_enabled[ST_INDIO_DEV_NUM + 1];
u8 hwfifo_decimator[ST_INDIO_DEV_NUM + 1];
u16 hwfifo_watermark[ST_INDIO_DEV_NUM + 1];
u16 fifo_watermark;
u8 samples_to_discard[ST_INDIO_DEV_NUM + 1];
u8 samples_to_discard_2[ST_INDIO_DEV_NUM + 1];
struct lsm6dsm_out_decimation nofifo_decimation[ST_INDIO_DEV_NUM + 1];
struct lsm6dsm_fifo_output fifo_output[ST_INDIO_DEV_NUM + 1];
u16 sensors_enabled;
u16 sensors_use_fifo;
u64 num_steps;
int accel_odr_dependency[3];
bool accel_on;
bool magn_on;
enum fifo_mode fifo_status;
struct mutex odr_lock;
bool reset_steps;
u8 *fifo_data;
u8 accel_last_push[6];
u8 gyro_last_push[6];
u8 ext0_last_push[6];
int8_t gyro_selftest_status;
int8_t accel_selftest_status;
u8 drdy_reg;
int irq;
s64 timestamp;
int64_t fifo_enable_timestamp;
int64_t slower_counter;
uint8_t slower_id;
#ifdef CONFIG_ST_LSM6DSM_XL_DATA_INJECTION
bool injection_mode;
s64 last_injection_timestamp;
u8 injection_odr;
#endif /* CONFIG_ST_LSM6DSM_XL_DATA_INJECTION */
struct work_struct data_work;
struct device *dev;
struct iio_dev *indio_dev[ST_INDIO_DEV_NUM + 1];
struct iio_trigger *trig[ST_INDIO_DEV_NUM + 1];
struct mutex bank_registers_lock;
struct mutex fifo_lock;
u32 module_id;
#ifdef CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT
bool ext0_available;
int8_t ext0_selftest_status;
struct mutex i2c_transfer_lock;
#endif /* CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT */
const struct st_lsm6dsm_transfer_function *tf;
struct st_lsm6dsm_transfer_buffer tb;
};
struct st_lsm6dsm_transfer_function {
int (*write)(struct lsm6dsm_data *cdata,
u8 reg_addr, int len, u8 *data, bool b_lock);
int (*read)(struct lsm6dsm_data *cdata,
u8 reg_addr, int len, u8 *data, bool b_lock);
};
struct lsm6dsm_sensor_data {
struct lsm6dsm_data *cdata;
unsigned int c_gain[3];
u8 num_data_channels;
u8 sindex;
u8 data_out_reg;
};
int st_lsm6dsm_write_data_with_mask(struct lsm6dsm_data *cdata,
u8 reg_addr, u8 mask, u8 data, bool b_lock);
int st_lsm6dsm_push_data_with_timestamp(struct lsm6dsm_data *cdata,
u8 index, u8 *data, int64_t timestamp);
int st_lsm6dsm_common_probe(struct lsm6dsm_data *cdata, int irq);
void st_lsm6dsm_common_remove(struct lsm6dsm_data *cdata, int irq);
int st_lsm6dsm_set_enable(struct lsm6dsm_sensor_data *sdata, bool enable, bool buffer);
int st_lsm6dsm_set_fifo_mode(struct lsm6dsm_data *cdata, enum fifo_mode fm);
int st_lsm6dsm_enable_sensor_hub(struct lsm6dsm_data *cdata, bool enable,
enum st_mask_id id);
int lsm6dsm_read_output_data(struct lsm6dsm_data *cdata, int sindex, bool push);
int st_lsm6dsm_set_drdy_irq(struct lsm6dsm_sensor_data *sdata, bool state);
ssize_t st_lsm6dsm_sysfs_get_hwfifo_enabled(struct device *dev,
struct device_attribute *attr, char *buf);
ssize_t st_lsm6dsm_sysfs_set_hwfifo_enabled(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size);
ssize_t st_lsm6dsm_sysfs_get_hwfifo_watermark(struct device *dev,
struct device_attribute *attr, char *buf);
ssize_t st_lsm6dsm_sysfs_set_hwfifo_watermark(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size);
ssize_t st_lsm6dsm_sysfs_get_hwfifo_watermark_max(struct device *dev,
struct device_attribute *attr, char *buf);
ssize_t st_lsm6dsm_sysfs_get_hwfifo_watermark_min(struct device *dev,
struct device_attribute *attr, char *buf);
ssize_t st_lsm6dsm_sysfs_flush_fifo(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size);
ssize_t st_lsm6dsm_get_module_id(struct device *dev,
struct device_attribute *attr,
char *buf);
#ifdef CONFIG_IIO_BUFFER
int st_lsm6dsm_allocate_rings(struct lsm6dsm_data *cdata);
void st_lsm6dsm_deallocate_rings(struct lsm6dsm_data *cdata);
int st_lsm6dsm_trig_set_state(struct iio_trigger *trig, bool state);
int st_lsm6dsm_read_fifo(struct lsm6dsm_data *cdata, bool async);
#define ST_LSM6DSM_TRIGGER_SET_STATE (&st_lsm6dsm_trig_set_state)
#else /* CONFIG_IIO_BUFFER */
static inline int st_lsm6dsm_allocate_rings(struct lsm6dsm_data *cdata)
{
return 0;
}
static inline void st_lsm6dsm_deallocate_rings(struct lsm6dsm_data *cdata)
{
}
static inline int st_lsm6dsm_read_fifo(struct lsm6dsm_data *cdata, bool async)
{
return 0;
}
#define ST_LSM6DSM_TRIGGER_SET_STATE NULL
#endif /* CONFIG_IIO_BUFFER */
#ifdef CONFIG_IIO_TRIGGER
int st_lsm6dsm_allocate_triggers(struct lsm6dsm_data *cdata,
const struct iio_trigger_ops *trigger_ops);
void st_lsm6dsm_deallocate_triggers(struct lsm6dsm_data *cdata);
void st_lsm6dsm_flush_works(void);
#else /* CONFIG_IIO_TRIGGER */
static inline int st_lsm6dsm_allocate_triggers(struct lsm6dsm_data *cdata,
const struct iio_trigger_ops *trigger_ops, int irq)
{
return 0;
}
static inline void st_lsm6dsm_deallocate_triggers(struct lsm6dsm_data *cdata,
int irq)
{
return;
}
static inline void st_lsm6dsm_flush_works(void)
{
return;
}
#endif /* CONFIG_IIO_TRIGGER */
#ifdef CONFIG_PM
int st_lsm6dsm_common_suspend(struct lsm6dsm_data *cdata);
int st_lsm6dsm_common_resume(struct lsm6dsm_data *cdata);
#endif /* CONFIG_PM */
#ifdef CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT
int st_lsm6dsm_write_embedded_registers(struct lsm6dsm_data *cdata,
u8 reg_addr, u8 *data, int len);
int st_lsm6dsm_i2c_master_probe(struct lsm6dsm_data *cdata);
int st_lsm6dsm_i2c_master_exit(struct lsm6dsm_data *cdata);
#else /* CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT */
static inline int st_lsm6dsm_i2c_master_probe(struct lsm6dsm_data *cdata)
{
return 0;
}
static inline int st_lsm6dsm_i2c_master_exit(struct lsm6dsm_data *cdata)
{
return 0;
}
#endif /* CONFIG_ST_LSM6DSM_IIO_MASTER_SUPPORT */
static inline int st_lsm6dsm_iio_dev_currentmode(struct iio_dev *indio_dev)
{
#if KERNEL_VERSION(5, 19, 0) <= LINUX_VERSION_CODE
struct iio_dev_opaque *iio_opq = to_iio_dev_opaque(indio_dev);
return iio_opq->currentmode;
#else /* LINUX_VERSION_CODE */
return indio_dev->currentmode;
#endif /* LINUX_VERSION_CODE */
}
#endif /* ST_LSM6DSM_H */