drivers:iio:stm:accel: Add support to LIS2DU12 STMEMS accel
Added support to STMEMS acc LIS2DU12 sensor. The following features has been included: - Acc and Temp sensor in FIFO - Embedded features event detection supported: - Wake-up - Free fall - Tap - Double Tap - 6D / 4D - activity / inactivity - Embedded features parameters configuration - Self test procedure Signed-off-by: Mario Tesi <mario.tesi@st.com> Change-Id: I89df1f65ca14e01bc424b8e26de2c972cf71b999
This commit is contained in:
parent
b314796715
commit
115ea4079c
@ -0,0 +1,38 @@
|
||||
* lis2du12 driver for accel MEMS sensors
|
||||
|
||||
Required properties for all bus drivers:
|
||||
- compatible: must be one of:
|
||||
"st,lis2du12"
|
||||
|
||||
Required properties for the i2c/i3c bindings:
|
||||
- reg: i2c/i3c address of the sensor (for i3c is the static sddress)
|
||||
|
||||
Required properties for the spi bindings:
|
||||
- reg: the chipselect index
|
||||
- spi-max-frequency: maximal bus speed, should be set to 1000000 unless
|
||||
constrained by external circuitry
|
||||
|
||||
Optional properties for all bus drivers:
|
||||
- st,int-pin: the pin on the package that will be used to signal when
|
||||
sensor data are available (valid values: 1 or 2, default: 1).
|
||||
|
||||
- interrupts: interrupt mapping for IRQ. It should be configured with
|
||||
flags IRQ_TYPE_LEVEL_HIGH.
|
||||
|
||||
Refer to interrupt-controller/interrupts.txt for generic
|
||||
interrupt client node bindings.
|
||||
|
||||
- pd_dis_int1: disable pull down on int1 pin.
|
||||
|
||||
- pp_od_int: set int pin to open drain.
|
||||
|
||||
Example for an spi device node:
|
||||
|
||||
lis2du12-accel@0 {
|
||||
compatible = "st,lis2du12";
|
||||
reg = <0x0>;
|
||||
spi-max-frequency = <1000000>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
st,int-pin = <1>;
|
||||
};
|
@ -214,4 +214,39 @@ config IIO_ST_H3LIS331DL_SPI
|
||||
select REGMAP_SPI
|
||||
depends on IIO_ST_H3LIS331DL
|
||||
|
||||
config IIO_ST_LIS2DU12
|
||||
tristate "STMicroelectronics LIS2DU12 Accelerometer Driver"
|
||||
depends on (I2C || SPI || I3C)
|
||||
select IIO_BUFFER
|
||||
select IIO_KFIFO_BUF
|
||||
select IIO_ST_LIS2DU12_I2C if (I2C)
|
||||
select IIO_ST_LIS2DU12_SPI if (SPI)
|
||||
select IIO_ST_LIS2DU12_I3C if (I3C)
|
||||
help
|
||||
Say yes here to build support for the LIS2DU12 accelerometer.
|
||||
|
||||
This driver can also be built as a module. If so, will be created
|
||||
these modules:
|
||||
- st_lisdu12 (core functions for the driver [it is mandatory]);
|
||||
- st_lisdu12_i2c (necessary for the I2C devices [optional*]);
|
||||
- st_lisdu12_spi (necessary for the SPI devices [optional*]);
|
||||
- st_lisdu12_i3c (necessary for the I3C devices [optional*]);
|
||||
|
||||
(*) one of these is necessary to do something.
|
||||
|
||||
config IIO_ST_LIS2DU12_I2C
|
||||
tristate
|
||||
depends on IIO_ST_LIS2DU12
|
||||
depends on I2C
|
||||
|
||||
config IIO_ST_LIS2DU12_SPI
|
||||
tristate
|
||||
depends on IIO_ST_LIS2DU12
|
||||
depends on SPI
|
||||
|
||||
config IIO_ST_LIS2DU12_I3C
|
||||
tristate
|
||||
depends on IIO_ST_LIS2DU12
|
||||
depends on I3C
|
||||
|
||||
endmenu
|
||||
|
@ -48,3 +48,10 @@ st_h3lis331dl-y := st_h3lis331dl_core.o st_h3lis331dl_buffer.o
|
||||
obj-$(CONFIG_IIO_ST_H3LIS331DL) += st_h3lis331dl.o
|
||||
obj-$(CONFIG_IIO_ST_H3LIS331DL_I2C) += st_h3lis331dl_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_H3LIS331DL_SPI) += st_h3lis331dl_spi.o
|
||||
|
||||
st_lis2du12-y:= st_lis2du12_core.o st_lis2du12_buffer.o
|
||||
obj-$(CONFIG_IIO_ST_LIS2DU12) += st_lis2du12.o
|
||||
obj-$(CONFIG_IIO_ST_LIS2DU12_I2C) += st_lis2du12_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_LIS2DU12_SPI) += st_lis2du12_spi.o
|
||||
obj-$(CONFIG_IIO_ST_LIS2DU12_I3C) += st_lis2du12_i3c.o
|
||||
|
||||
|
364
drivers/iio/stm/accel/st_lis2du12.h
Normal file
364
drivers/iio/stm/accel/st_lis2du12.h
Normal file
@ -0,0 +1,364 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* STMicroelectronics lis2du12 driver
|
||||
*
|
||||
* MEMS Software Solutions Team
|
||||
*
|
||||
* Copyright 2022 STMicroelectronics Inc.
|
||||
*/
|
||||
|
||||
#ifndef ST_LIS2DU12_H
|
||||
#define ST_LIS2DU12_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
#include "../common/stm_iio_types.h"
|
||||
|
||||
#define ST_LIS2DU12_DEV_NAME "lis2du12"
|
||||
#define ST_LIS2DU12_MAX_WATERMARK 127
|
||||
#define ST_LIS2DU12_ACC_DATA_SIZE 6
|
||||
#define ST_LIS2DU12_TEMP_DATA_SIZE 2
|
||||
#define ST_LIS2DU12_DATA_SIZE (ST_LIS2DU12_ACC_DATA_SIZE + \
|
||||
ST_LIS2DU12_TEMP_DATA_SIZE)
|
||||
#define ST_LIS2DU12_ODR_EXPAND(odr, uodr) ((odr * 1000000) + uodr)
|
||||
|
||||
#define ST_LIS2DU12_IF_CTRL_ADDR 0x0e
|
||||
#define ST_LIS2DU12_PD_DIS_INT1_MASK BIT(2)
|
||||
|
||||
#define ST_LIS2DU12_CTRL1_ADDR 0x10
|
||||
#define ST_LIS2DU12_WU_EN_MASK GENMASK(2, 0)
|
||||
#define ST_LIS2DU12_IF_ADD_INC_MASK BIT(4)
|
||||
#define ST_LIS2DU12_SW_RESET_MASK BIT(5)
|
||||
#define ST_LIS2DU12_PP_OD_MASK BIT(7)
|
||||
|
||||
#define ST_LIS2DU12_CTRL2_ADDR 0x11
|
||||
#define ST_LIS2DU12_INT_F_FTH_MASK BIT(5)
|
||||
|
||||
#define ST_LIS2DU12_CTRL3_ADDR 0x12
|
||||
#define ST_LIS2DU12_ST_MASK GENMASK(1, 0)
|
||||
|
||||
#define ST_LIS2DU12_CTRL4_ADDR 0x13
|
||||
#define ST_LIS2DU12_BOOT_MASK BIT(0)
|
||||
#define ST_LIS2DU12_BDU_MASK BIT(5)
|
||||
|
||||
#define ST_LIS2DU12_CTRL5_ADDR 0x14
|
||||
#define ST_LIS2DU12_ODR_MASK GENMASK(7, 4)
|
||||
#define ST_LIS2DU12_FS_MASK GENMASK(1, 0)
|
||||
|
||||
#define ST_LIS2DU12_FIFO_CTRL_ADDR 0x15
|
||||
#define ST_LIS2DU12_FIFOMODE_MASK GENMASK(3, 0)
|
||||
#define ST_LIS2DU12_ROUNDING_XYZ_MASK BIT(7)
|
||||
|
||||
#define ST_LIS2DU12_FIFO_WTM_ADDR 0x16
|
||||
#define ST_LIS2DU12_FTH_MASK GENMASK(6, 0)
|
||||
|
||||
#define ST_LIS2DU12_INTERRUPT_CFG_ADDR 0x17
|
||||
#define ST_LIS2DU12_INTERRUPTS_ENABLE_MASK BIT(0)
|
||||
#define ST_LIS2DU12_LIR_MASK BIT(1)
|
||||
#define ST_LIS2DU12_H_LACTIVE_MASK BIT(2)
|
||||
#define ST_LIS2DU12_SLEEP_STATUS_ON_INT_MASK BIT(3)
|
||||
#define ST_LIS2DU12_INT_SHORT_EN_MASK BIT(6)
|
||||
|
||||
#define ST_LIS2DU12_TAP_THS_X_ADDR 0x18
|
||||
#define ST_LIS2DU12_D4D_EN_MASK BIT(7)
|
||||
#define ST_LIS2DU12_D6D_THS_MASK GENMASK(6, 5)
|
||||
#define ST_LIS2DU12_TAP_THS_X_MASK GENMASK(4, 0)
|
||||
|
||||
#define ST_LIS2DU12_TAP_THS_Y_ADDR 0x19
|
||||
#define ST_LIS2DU12_TAP_PRIORITY_MASK GENMASK(7, 5)
|
||||
#define ST_LIS2DU12_TAP_THS_Y_MASK GENMASK(4, 0)
|
||||
|
||||
#define ST_LIS2DU12_TAP_THS_Z_ADDR 0x1a
|
||||
#define ST_LIS2DU12_TAP_EN_MASK GENMASK(7, 5)
|
||||
#define ST_LIS2DU12_TAP_THS_Z_MASK GENMASK(4, 0)
|
||||
|
||||
#define ST_LIS2DU12_INT_DUR_ADDR 0x1b
|
||||
#define ST_LIS2DU12_SHOCK_MASK GENMASK(1, 0)
|
||||
#define ST_LIS2DU12_QUIET_MASK GENMASK(3, 2)
|
||||
#define ST_LIS2DU12_LATENCY_MASK GENMASK(7, 4)
|
||||
|
||||
#define ST_LIS2DU12_WAKE_UP_THS_ADDR 0x1c
|
||||
#define ST_LIS2DU12_WK_THS_MASK GENMASK(5, 0)
|
||||
#define ST_LIS2DU12_SLEEP_ON_MASK BIT(6)
|
||||
#define ST_LIS2DU12_SINGLE_DOUBLE_TAP_MASK BIT(7)
|
||||
|
||||
#define ST_LIS2DU12_WAKE_UP_DUR_ADDR 0x1d
|
||||
#define ST_LIS2DU12_SLEEP_DUR_MASK GENMASK(3, 0)
|
||||
#define ST_LIS2DU12_WAKE_DUR_MASK GENMASK(6, 5)
|
||||
#define ST_LIS2DU12_FF_DUR5_MASK BIT(7)
|
||||
|
||||
#define ST_LIS2DU12_FREE_FALL_ADDR 0x1e
|
||||
#define ST_LIS2DU12_FF_THS_MASK GENMASK(2, 0)
|
||||
#define ST_LIS2DU12_FF_DUR_MASK GENMASK(7, 3)
|
||||
|
||||
#define ST_LIS2DU12_MD1_CFG_ADDR 0x1f
|
||||
#define ST_LIS2DU12_MD2_CFG_ADDR 0x20
|
||||
#define ST_LIS2DU12_MD_INT_MASK GENMASK(7, 2)
|
||||
#define ST_LIS2DU12_INT_6D_MASK BIT(2)
|
||||
#define ST_LIS2DU12_INT_DOUBLE_TAP_MASK BIT(3)
|
||||
#define ST_LIS2DU12_INT_FF_MASK BIT(4)
|
||||
#define ST_LIS2DU12_INT_WU_MASK BIT(5)
|
||||
#define ST_LIS2DU12_INT_SINGLE_TAP_MASK BIT(6)
|
||||
#define ST_LIS2DU12_INT_SLEEP_CHANGE_MASK BIT(7)
|
||||
|
||||
#define ST_LIS2DU12_WAKE_UP_SRC_ADDR 0x21
|
||||
#define ST_LIS2DU12_WU_MASK GENMASK(3, 0)
|
||||
#define ST_LIS2DU12_WU_IA_MASK BIT(3)
|
||||
#define ST_LIS2DU12_SLEEP_STATE_MASK BIT(4)
|
||||
#define ST_LIS2DU12_FF_IA_MASK BIT(5)
|
||||
#define ST_LIS2DU12_SLEEP_CHANGE_IA_MASK BIT(6)
|
||||
|
||||
#define ST_LIS2DU12_TAP_SRC_ADDR 0x22
|
||||
#define ST_LIS2DU12_DOUBLE_TAP_IA_MASK BIT(4)
|
||||
#define ST_LIS2DU12_SINGLE_TAP_IA_MASK BIT(5)
|
||||
|
||||
#define ST_LIS2DU12_SIXD_SRC_ADDR 0x23
|
||||
#define ST_LIS2DU12_OVERTHRESHOLD_MASK GENMASK(5, 0)
|
||||
#define ST_LIS2DU12_D6D_IA_MASK BIT(6)
|
||||
|
||||
#define ST_LIS2DU12_ALL_INT_SRC_ADDR 0x24
|
||||
#define ST_LIS2DU12_FF_IA_ALL_MASK BIT(0)
|
||||
#define ST_LIS2DU12_WU_IA_ALL_MASK BIT(1)
|
||||
#define ST_LIS2DU12_SINGLE_TAP_ALL_MASK BIT(2)
|
||||
#define ST_LIS2DU12_DOUBLE_TAP_ALL_MASK BIT(3)
|
||||
#define ST_LIS2DU12_D6D_IA_ALL_MASK BIT(4)
|
||||
#define ST_LIS2DU12_SLEEP_CHANGE_IA_ALL_MASK BIT(5)
|
||||
#define ST_LIS2DU12_INT_GLOBAL_MASK BIT(6)
|
||||
|
||||
#define ST_LIS2DU12_STATUS_ADDR 0x25
|
||||
#define ST_LIS2DU12_DRDY_MASK BIT(0)
|
||||
|
||||
#define ST_LIS2DU12_FIFO_STATUS1_ADDR 0x26
|
||||
#define ST_LIS2DU12_FTH_WTM_MASK BIT(7)
|
||||
|
||||
#define ST_LIS2DU12_FIFO_STATUS2_ADDR 0x27
|
||||
#define ST_LIS2DU12_FSS_MASK GENMASK(7, 0)
|
||||
|
||||
#define ST_LIS2DU12_OUT_X_L_ADDR 0x28
|
||||
#define ST_LIS2DU12_OUT_Y_L_ADDR 0x2a
|
||||
#define ST_LIS2DU12_OUT_Z_L_ADDR 0x2c
|
||||
|
||||
#define ST_LIS2DU12_TEMP_L_ADDR 0x30
|
||||
|
||||
#define ST_LIS2DU12_WHOAMI_ADDR 0x43
|
||||
#define ST_LIS2DU12_WHOAMI_VAL 0x45
|
||||
|
||||
#define ST_LIS2DU12_ST_SIGN_ADDR 0x58
|
||||
#define ST_LIS2DU12_STSIGN_MASK GENMASK(7, 5)
|
||||
|
||||
#define ST_LIS2DU12_SHIFT_VAL(val, mask) (((val) << __ffs(mask)) & (mask))
|
||||
|
||||
#define ST_LIS2DU12_ACC_CHAN(addr, ch2, idx) \
|
||||
{ \
|
||||
.type = IIO_ACCEL, \
|
||||
.address = addr, \
|
||||
.modified = 1, \
|
||||
.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 = idx, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define ST_LIS2DU12_TEMP_CHAN(addr, ch2) \
|
||||
{ \
|
||||
.type = IIO_TEMP, \
|
||||
.address = addr, \
|
||||
.modified = 1, \
|
||||
.channel2 = ch2, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
.scan_index = 0, \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 12, \
|
||||
.storagebits = 16, \
|
||||
.shift = 4, \
|
||||
.endianness = IIO_LE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
#define ST_LIS2DU12_EVENT_CHANNEL(chan_type, evt_spec) \
|
||||
{ \
|
||||
.type = chan_type, \
|
||||
.modified = 0, \
|
||||
.scan_index = -1, \
|
||||
.indexed = -1, \
|
||||
.event_spec = evt_spec, \
|
||||
.num_event_specs = 1, \
|
||||
}
|
||||
|
||||
enum st_lis2du12_fifo_mode {
|
||||
ST_LIS2DU12_FIFO_BYPASS = 0x0,
|
||||
ST_LIS2DU12_FIFO_CONTINUOUS = 0x6,
|
||||
};
|
||||
|
||||
enum st_lis2du12_selftest_status {
|
||||
ST_LIS2DU12_ST_RESET,
|
||||
ST_LIS2DU12_ST_PASS,
|
||||
ST_LIS2DU12_ST_FAIL,
|
||||
};
|
||||
|
||||
enum st_lis2du12_sensor_id {
|
||||
ST_LIS2DU12_ID_ACC,
|
||||
ST_LIS2DU12_ID_TEMP,
|
||||
ST_LIS2DU12_ID_TAP_TAP,
|
||||
ST_LIS2DU12_ID_TAP,
|
||||
ST_LIS2DU12_ID_WU,
|
||||
ST_LIS2DU12_ID_FF,
|
||||
ST_LIS2DU12_ID_6D,
|
||||
ST_LIS2DU12_ID_ACT,
|
||||
ST_LIS2DU12_ID_MAX,
|
||||
};
|
||||
|
||||
enum st_lis2du12_attr_id {
|
||||
ST_LIS2DU12_WK_THS_ATTR_ID = 0x0,
|
||||
ST_LIS2DU12_WK_DUR_ATTR_ID,
|
||||
ST_LIS2DU12_FF_THS_ATTR_ID,
|
||||
ST_LIS2DU12_FF_DUR_ATTR_ID,
|
||||
ST_LIS2DU12_6D_THS_ATTR_ID,
|
||||
ST_LIS2DU12_LATENCY_ATTR_ID,
|
||||
ST_LIS2DU12_QUIET_ATTR_ID,
|
||||
ST_LIS2DU12_SHOCK_ATTR_ID,
|
||||
ST_LIS2DU12_TAP_PRIORITY_ATTR_ID,
|
||||
ST_LIS2DU12_TAP_THRESHOLD_X_ATTR_ID,
|
||||
ST_LIS2DU12_TAP_THRESHOLD_Y_ATTR_ID,
|
||||
ST_LIS2DU12_TAP_THRESHOLD_Z_ATTR_ID,
|
||||
ST_LIS2DU12_TAP_ENABLE_ATTR_ID,
|
||||
ST_LIS2DU12_SLEEP_DUR_ATTR_ID,
|
||||
};
|
||||
|
||||
#define ST_LIS2DU12_MAX_BUFFER ST_LIS2DU12_ID_TEMP
|
||||
|
||||
struct st_lis2du12_sensor {
|
||||
enum st_lis2du12_sensor_id id;
|
||||
struct st_lis2du12_hw *hw;
|
||||
|
||||
u16 odr;
|
||||
u32 uodr;
|
||||
|
||||
union {
|
||||
struct {
|
||||
u16 gain;
|
||||
u32 offset;
|
||||
u8 watermark;
|
||||
};
|
||||
|
||||
struct {
|
||||
u8 wk_en;
|
||||
u8 d6d_ths;
|
||||
u8 tap_ths_x;
|
||||
u8 tap_ths_y;
|
||||
u8 tap_ths_z;
|
||||
u8 tap_priority;
|
||||
u8 tap_en;
|
||||
u8 latency;
|
||||
u8 quiet;
|
||||
u8 shock;
|
||||
u8 wh_ths;
|
||||
u8 wh_dur;
|
||||
u8 sleep_dur;
|
||||
u8 ff_dur;
|
||||
u8 ff_ths;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
struct st_lis2du12_hw {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
|
||||
struct regmap *regmap;
|
||||
struct mutex fifo_lock;
|
||||
struct mutex lock;
|
||||
|
||||
struct iio_dev *iio_devs[ST_LIS2DU12_ID_MAX];
|
||||
|
||||
enum st_lis2du12_selftest_status st_status;
|
||||
enum st_lis2du12_fifo_mode fifo_mode;
|
||||
u16 enable_mask;
|
||||
|
||||
u8 fifo_watermark;
|
||||
bool round_xl_xyz;
|
||||
u8 std_level;
|
||||
u64 samples;
|
||||
|
||||
s64 delta_ts;
|
||||
s64 ts_irq;
|
||||
s64 ts;
|
||||
|
||||
u8 drdy_reg;
|
||||
u8 md_reg;
|
||||
bool fourd_enabled;
|
||||
};
|
||||
|
||||
extern const struct dev_pm_ops st_lis2du12_pm_ops;
|
||||
|
||||
static inline s64 st_lis2du12_get_timestamp(struct st_lis2du12_hw *hw)
|
||||
{
|
||||
return iio_get_time_ns(hw->iio_devs[ST_LIS2DU12_ID_ACC]);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
st_lis2du12_interrupts_enabled(struct st_lis2du12_hw *hw)
|
||||
{
|
||||
return hw->enable_mask & (BIT(ST_LIS2DU12_ID_FF) |
|
||||
BIT(ST_LIS2DU12_ID_TAP_TAP) |
|
||||
BIT(ST_LIS2DU12_ID_TAP) |
|
||||
BIT(ST_LIS2DU12_ID_WU) |
|
||||
BIT(ST_LIS2DU12_ID_6D) |
|
||||
BIT(ST_LIS2DU12_ID_ACT));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
st_lis2du12_fifo_enabled(struct st_lis2du12_hw *hw)
|
||||
{
|
||||
return hw->enable_mask & (BIT(ST_LIS2DU12_ID_ACC) |
|
||||
BIT(ST_LIS2DU12_ID_TEMP));
|
||||
}
|
||||
|
||||
static inline int
|
||||
st_lis2du12_read_locked(struct st_lis2du12_hw *hw, unsigned int addr,
|
||||
void *val, unsigned int len)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&hw->lock);
|
||||
err = regmap_bulk_read(hw->regmap, addr, val, len);
|
||||
mutex_unlock(&hw->lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline struct st_lis2du12_sensor *
|
||||
st_lis2du12_get_sensor_from_id(struct st_lis2du12_hw *hw,
|
||||
enum st_lis2du12_sensor_id id)
|
||||
{
|
||||
return iio_priv(hw->iio_devs[id]);
|
||||
}
|
||||
|
||||
int st_lis2du12_probe(struct device *dev, int irq,
|
||||
struct regmap *regmap);
|
||||
int st_lis2du12_buffer_setup(struct st_lis2du12_hw *hw);
|
||||
ssize_t st_lis2du12_flush_fifo(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size);
|
||||
ssize_t st_lis2du12_set_hwfifo_watermark(struct device *device,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size);
|
||||
int st_lis2du12_sensor_set_enable(struct st_lis2du12_sensor *sensor,
|
||||
bool enable);
|
||||
#endif /* ST_LIS2DU12_H */
|
555
drivers/iio/stm/accel/st_lis2du12_buffer.c
Normal file
555
drivers/iio/stm/accel/st_lis2du12_buffer.c
Normal file
@ -0,0 +1,555 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics lis2du12 fifo driver
|
||||
*
|
||||
* MEMS Software Solutions Team
|
||||
*
|
||||
* Copyright 2022 STMicroelectronics Inc.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "st_lis2du12.h"
|
||||
|
||||
#define ST_LIS2DU12_EWMA_LEVEL 120
|
||||
#define ST_LIS2DU12_EWMA_DIV 128
|
||||
static inline s64 st_lis2du12_ewma(s64 old, s64 new, int weight)
|
||||
{
|
||||
s64 diff, incr;
|
||||
|
||||
diff = new - old;
|
||||
incr = div_s64((ST_LIS2DU12_EWMA_DIV - weight) * diff,
|
||||
ST_LIS2DU12_EWMA_DIV);
|
||||
|
||||
return old + incr;
|
||||
}
|
||||
|
||||
static int st_lis2du12_set_fifo_mode(struct st_lis2du12_hw *hw,
|
||||
enum st_lis2du12_fifo_mode mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = regmap_update_bits(hw->regmap,
|
||||
ST_LIS2DU12_FIFO_CTRL_ADDR,
|
||||
ST_LIS2DU12_FIFOMODE_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_FIFOMODE_MASK, mode));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hw->fifo_mode = mode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_lis2du12_update_fifo_watermark(struct st_lis2du12_sensor *sensor,
|
||||
u8 watermark)
|
||||
{
|
||||
u16 fifo_watermark = ST_LIS2DU12_MAX_WATERMARK;
|
||||
struct st_lis2du12_hw *hw = sensor->hw;
|
||||
struct st_lis2du12_sensor *cur_sensor;
|
||||
u16 cur_watermark = 0;
|
||||
int i, err;
|
||||
|
||||
for (i = ST_LIS2DU12_ID_ACC; i <= ST_LIS2DU12_MAX_BUFFER; i++) {
|
||||
if (!hw->iio_devs[i])
|
||||
continue;
|
||||
|
||||
cur_sensor = iio_priv(hw->iio_devs[i]);
|
||||
|
||||
if (!(hw->enable_mask & BIT(cur_sensor->id)))
|
||||
continue;
|
||||
|
||||
cur_watermark = (cur_sensor == sensor) ? watermark :
|
||||
cur_sensor->watermark;
|
||||
|
||||
fifo_watermark = min_t(u8, fifo_watermark,
|
||||
cur_watermark);
|
||||
}
|
||||
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
err = regmap_update_bits(hw->regmap,
|
||||
ST_LIS2DU12_FIFO_WTM_ADDR,
|
||||
ST_LIS2DU12_FTH_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_FTH_MASK, fifo_watermark));
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
hw->fifo_watermark = fifo_watermark;
|
||||
|
||||
out:
|
||||
mutex_unlock(&hw->fifo_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int st_lis2du12_update_fifo(struct iio_dev *iio_dev, bool enable)
|
||||
{
|
||||
struct st_lis2du12_sensor *sensor = iio_priv(iio_dev);
|
||||
struct st_lis2du12_hw *hw = sensor->hw;
|
||||
int err;
|
||||
|
||||
if (enable) {
|
||||
hw->ts_irq = hw->ts = st_lis2du12_get_timestamp(hw);
|
||||
hw->delta_ts = div_s64(1000000000LL, sensor->odr) *
|
||||
hw->fifo_watermark;
|
||||
hw->samples = 0;
|
||||
}
|
||||
|
||||
disable_irq(hw->irq);
|
||||
|
||||
err = st_lis2du12_sensor_set_enable(sensor, enable);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
if (sensor->id == ST_LIS2DU12_ID_TEMP) {
|
||||
u8 round = enable ? false : true;
|
||||
|
||||
/* configure rounding accordingly */
|
||||
err = regmap_update_bits(hw->regmap,
|
||||
ST_LIS2DU12_FIFO_CTRL_ADDR,
|
||||
ST_LIS2DU12_ROUNDING_XYZ_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_ROUNDING_XYZ_MASK, round));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hw->round_xl_xyz = round;
|
||||
}
|
||||
|
||||
st_lis2du12_update_fifo_watermark(sensor, sensor->watermark);
|
||||
|
||||
if (enable && (hw->fifo_mode == ST_LIS2DU12_FIFO_BYPASS))
|
||||
err = st_lis2du12_set_fifo_mode(hw, ST_LIS2DU12_FIFO_CONTINUOUS);
|
||||
else if (!st_lis2du12_fifo_enabled(hw))
|
||||
err = st_lis2du12_set_fifo_mode(hw, ST_LIS2DU12_FIFO_BYPASS);
|
||||
|
||||
out:
|
||||
enable_irq(hw->irq);
|
||||
|
||||
return err < 0 ? err : 0;
|
||||
}
|
||||
|
||||
ssize_t st_lis2du12_set_hwfifo_watermark(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct iio_dev *iio_dev = dev_to_iio_dev(dev);
|
||||
struct st_lis2du12_sensor *sensor = iio_priv(iio_dev);
|
||||
int err, val;
|
||||
|
||||
mutex_lock(&iio_dev->mlock);
|
||||
if (iio_buffer_enabled(iio_dev)) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
err = kstrtoint(buf, 10, &val);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
if (val < 1 || val > ST_LIS2DU12_MAX_WATERMARK) {
|
||||
err = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
err = st_lis2du12_update_fifo_watermark(sensor, val);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
sensor->watermark = val;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&iio_dev->mlock);
|
||||
|
||||
return err < 0 ? err : size;
|
||||
}
|
||||
|
||||
static int st_lis2du12_buffer_preenable(struct iio_dev *iio_dev)
|
||||
{
|
||||
return st_lis2du12_update_fifo(iio_dev, true);
|
||||
}
|
||||
|
||||
static int st_lis2du12_buffer_postdisable(struct iio_dev *iio_dev)
|
||||
{
|
||||
return st_lis2du12_update_fifo(iio_dev, false);
|
||||
}
|
||||
|
||||
static const struct
|
||||
iio_buffer_setup_ops st_lis2du12_buffer_setup_ops = {
|
||||
.preenable = st_lis2du12_buffer_preenable,
|
||||
.postdisable = st_lis2du12_buffer_postdisable,
|
||||
};
|
||||
|
||||
static int st_lis2du12_read_fifo(struct st_lis2du12_hw *hw)
|
||||
{
|
||||
u8 iio_buff[ALIGN(ST_LIS2DU12_ACC_DATA_SIZE, sizeof(s64)) + sizeof(s64)];
|
||||
u8 buff[16 * ST_LIS2DU12_ACC_DATA_SIZE], samples, data_size;
|
||||
struct iio_dev *iio_acc_dev = hw->iio_devs[ST_LIS2DU12_ID_ACC];
|
||||
struct iio_dev *iio_temp_dev = hw->iio_devs[ST_LIS2DU12_ID_TEMP];
|
||||
struct iio_chan_spec const *ch = iio_acc_dev->channels;
|
||||
int i, err, word_len, fifo_len, read_len = 0;
|
||||
s64 delta_ts;
|
||||
int status;
|
||||
|
||||
err = regmap_read(hw->regmap, ST_LIS2DU12_FIFO_STATUS2_ADDR, &status);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
samples = status & ST_LIS2DU12_FSS_MASK;
|
||||
delta_ts = div_s64(hw->delta_ts, hw->fifo_watermark);
|
||||
|
||||
if (hw->round_xl_xyz)
|
||||
data_size = ST_LIS2DU12_ACC_DATA_SIZE;
|
||||
else
|
||||
data_size = ST_LIS2DU12_DATA_SIZE;
|
||||
|
||||
fifo_len = samples * data_size;
|
||||
|
||||
while (read_len < fifo_len) {
|
||||
word_len = min_t(int, fifo_len - read_len,
|
||||
sizeof(buff));
|
||||
err = st_lis2du12_read_locked(hw, ch[0].address,
|
||||
buff, word_len);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < word_len; i += data_size) {
|
||||
if (unlikely(++hw->samples < hw->std_level)) {
|
||||
hw->ts += delta_ts;
|
||||
continue;
|
||||
}
|
||||
|
||||
hw->ts = min_t(s64,
|
||||
st_lis2du12_get_timestamp(hw),
|
||||
hw->ts);
|
||||
|
||||
if (hw->enable_mask & BIT(ST_LIS2DU12_ID_ACC)) {
|
||||
memcpy(iio_buff, &buff[i],
|
||||
ST_LIS2DU12_ACC_DATA_SIZE);
|
||||
iio_push_to_buffers_with_timestamp(iio_acc_dev,
|
||||
iio_buff,
|
||||
hw->ts);
|
||||
}
|
||||
|
||||
if (!hw->round_xl_xyz &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DU12_ID_TEMP))) {
|
||||
memcpy(iio_buff,
|
||||
&buff[i + ST_LIS2DU12_ACC_DATA_SIZE],
|
||||
ST_LIS2DU12_TEMP_DATA_SIZE);
|
||||
iio_push_to_buffers_with_timestamp(iio_temp_dev,
|
||||
iio_buff,
|
||||
hw->ts);
|
||||
}
|
||||
|
||||
hw->ts += delta_ts;
|
||||
}
|
||||
|
||||
read_len += word_len;
|
||||
}
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
ssize_t st_lis2du12_flush_fifo(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct iio_dev *iio_dev = dev_to_iio_dev(dev);
|
||||
struct st_lis2du12_sensor *sensor = iio_priv(iio_dev);
|
||||
struct st_lis2du12_hw *hw = sensor->hw;
|
||||
s64 code;
|
||||
int err;
|
||||
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
|
||||
err = st_lis2du12_read_fifo(hw);
|
||||
hw->ts_irq = st_lis2du12_get_timestamp(hw);
|
||||
|
||||
mutex_unlock(&hw->fifo_lock);
|
||||
|
||||
code = IIO_UNMOD_EVENT_CODE(IIO_ACCEL, -1,
|
||||
STM_IIO_EV_TYPE_FIFO_FLUSH,
|
||||
IIO_EV_DIR_EITHER);
|
||||
iio_push_event(iio_dev, code, hw->ts_irq);
|
||||
|
||||
return err < 0 ? err : size;
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t st_lis2du12_handler_irq(int irq, void *private)
|
||||
{
|
||||
struct st_lis2du12_hw *hw = private;
|
||||
s64 ts;
|
||||
|
||||
ts = st_lis2du12_get_timestamp(hw);
|
||||
hw->delta_ts = st_lis2du12_ewma(hw->delta_ts, ts - hw->ts_irq,
|
||||
ST_LIS2DU12_EWMA_LEVEL);
|
||||
hw->ts_irq = ts;
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t st_lis2du12_handler_thread(int irq, void *private)
|
||||
{
|
||||
int status, all_int_source, wk_source, sixd_source;
|
||||
struct st_lis2du12_hw *hw = private;
|
||||
s64 code;
|
||||
int err;
|
||||
|
||||
err = regmap_read(hw->regmap, ST_LIS2DU12_FIFO_STATUS1_ADDR,
|
||||
&status);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (status & ST_LIS2DU12_FTH_WTM_MASK) {
|
||||
mutex_lock(&hw->fifo_lock);
|
||||
st_lis2du12_read_fifo(hw);
|
||||
mutex_unlock(&hw->fifo_lock);
|
||||
}
|
||||
|
||||
err = regmap_read(hw->regmap, ST_LIS2DU12_ALL_INT_SRC_ADDR,
|
||||
&all_int_source);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (((all_int_source & ST_LIS2DU12_SINGLE_TAP_ALL_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DU12_ID_TAP))) ||
|
||||
((all_int_source & ST_LIS2DU12_DOUBLE_TAP_ALL_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DU12_ID_TAP_TAP)))) {
|
||||
struct iio_dev *iio_dev;
|
||||
enum iio_chan_type type;
|
||||
int source;
|
||||
|
||||
err = regmap_read(hw->regmap, ST_LIS2DU12_TAP_SRC_ADDR,
|
||||
&source);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
if (source & ST_LIS2DU12_DOUBLE_TAP_IA_MASK) {
|
||||
iio_dev = hw->iio_devs[ST_LIS2DU12_ID_TAP_TAP];
|
||||
type = STM_IIO_TAP_TAP;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2du12_get_timestamp(hw));
|
||||
}
|
||||
|
||||
if (source & ST_LIS2DU12_SINGLE_TAP_IA_MASK) {
|
||||
iio_dev = hw->iio_devs[ST_LIS2DU12_ID_TAP];
|
||||
type = STM_IIO_TAP;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, -1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2du12_get_timestamp(hw));
|
||||
}
|
||||
}
|
||||
|
||||
if ((all_int_source & ST_LIS2DU12_WU_IA_ALL_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DU12_ID_WU))) {
|
||||
struct iio_dev *iio_dev;
|
||||
enum iio_chan_type type;
|
||||
u8 wu_src;
|
||||
|
||||
err = regmap_read(hw->regmap, ST_LIS2DU12_WAKE_UP_SRC_ADDR,
|
||||
&wk_source);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
wu_src = wk_source & ST_LIS2DU12_WU_MASK;
|
||||
iio_dev = hw->iio_devs[ST_LIS2DU12_ID_WU];
|
||||
/* use STM_IIO_GESTURE event type for custom events */
|
||||
type = STM_IIO_GESTURE;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, wu_src,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2du12_get_timestamp(hw));
|
||||
}
|
||||
|
||||
if ((all_int_source & ST_LIS2DU12_FF_IA_ALL_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DU12_ID_FF))) {
|
||||
struct iio_dev *iio_dev;
|
||||
enum iio_chan_type type;
|
||||
|
||||
iio_dev = hw->iio_devs[ST_LIS2DU12_ID_FF];
|
||||
/* use STM_IIO_GESTURE event type for custom events */
|
||||
type = STM_IIO_GESTURE;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, 1,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2du12_get_timestamp(hw));
|
||||
}
|
||||
|
||||
if ((all_int_source & ST_LIS2DU12_D6D_IA_ALL_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DU12_ID_6D))) {
|
||||
struct iio_dev *iio_dev;
|
||||
enum iio_chan_type type;
|
||||
u8 sixd_src;
|
||||
|
||||
err = regmap_read(hw->regmap, ST_LIS2DU12_SIXD_SRC_ADDR,
|
||||
&sixd_source);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
sixd_src = sixd_source & ST_LIS2DU12_OVERTHRESHOLD_MASK;
|
||||
iio_dev = hw->iio_devs[ST_LIS2DU12_ID_6D];
|
||||
/* use IIO_GESTURE event type for custom events */
|
||||
type = STM_IIO_GESTURE;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, sixd_src,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2du12_get_timestamp(hw));
|
||||
}
|
||||
|
||||
if ((all_int_source & ST_LIS2DU12_SLEEP_CHANGE_IA_ALL_MASK) &&
|
||||
(hw->enable_mask & BIT(ST_LIS2DU12_ID_ACT))) {
|
||||
struct iio_dev *iio_dev;
|
||||
enum iio_chan_type type;
|
||||
u8 sleep_state;
|
||||
|
||||
err = regmap_read(hw->regmap, ST_LIS2DU12_WAKE_UP_SRC_ADDR,
|
||||
&wk_source);
|
||||
if (err < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
sleep_state = wk_source & ST_LIS2DU12_SLEEP_STATE_MASK;
|
||||
iio_dev = hw->iio_devs[ST_LIS2DU12_ID_ACT];
|
||||
/* use IIO_GESTURE event type for custom events */
|
||||
type = STM_IIO_GESTURE;
|
||||
code = IIO_UNMOD_EVENT_CODE(type, sleep_state,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_RISING);
|
||||
iio_push_event(iio_dev, code,
|
||||
st_lis2du12_get_timestamp(hw));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int st_lis2du12_buffer_setup(struct st_lis2du12_hw *hw)
|
||||
{
|
||||
struct device_node *np = hw->dev->of_node;
|
||||
|
||||
#if KERNEL_VERSION(5, 13, 0) > LINUX_VERSION_CODE
|
||||
struct iio_buffer *buffer;
|
||||
#endif /* LINUX_VERSION_CODE */
|
||||
|
||||
unsigned long irq_type;
|
||||
u8 irq_active_low, i;
|
||||
int ret;
|
||||
|
||||
irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
|
||||
if (irq_type == IRQF_TRIGGER_NONE)
|
||||
irq_type = IRQF_TRIGGER_HIGH;
|
||||
|
||||
switch (irq_type) {
|
||||
case IRQF_TRIGGER_HIGH:
|
||||
case IRQF_TRIGGER_RISING:
|
||||
irq_active_low = 0;
|
||||
break;
|
||||
case IRQF_TRIGGER_LOW:
|
||||
case IRQF_TRIGGER_FALLING:
|
||||
irq_active_low = 1;
|
||||
break;
|
||||
default:
|
||||
dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (irq_active_low) {
|
||||
/* configure interrupts to low level */
|
||||
ret = regmap_update_bits(hw->regmap,
|
||||
ST_LIS2DU12_INTERRUPT_CFG_ADDR,
|
||||
ST_LIS2DU12_H_LACTIVE_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_H_LACTIVE_MASK, 1));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check pull down disable on int1 pin property */
|
||||
if (np && of_property_read_bool(np, "pd_dis_int1")) {
|
||||
ret = regmap_update_bits(hw->regmap,
|
||||
ST_LIS2DU12_IF_CTRL_ADDR,
|
||||
ST_LIS2DU12_PD_DIS_INT1_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_PD_DIS_INT1_MASK, 1));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* check push pull / open drain int pin property */
|
||||
if (np && of_property_read_bool(np, "pp_od_int")) {
|
||||
ret = regmap_update_bits(hw->regmap,
|
||||
ST_LIS2DU12_CTRL1_ADDR,
|
||||
ST_LIS2DU12_PP_OD_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_PP_OD_MASK, 1));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(hw->dev, hw->irq,
|
||||
st_lis2du12_handler_irq,
|
||||
st_lis2du12_handler_thread,
|
||||
irq_type | IRQF_ONESHOT,
|
||||
"st_lis2du12", hw);
|
||||
if (ret) {
|
||||
dev_err(hw->dev, "failed to request trigger irq %d\n",
|
||||
hw->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* configure rounding to read only acc data from FIFO */
|
||||
ret = regmap_update_bits(hw->regmap,
|
||||
ST_LIS2DU12_FIFO_CTRL_ADDR,
|
||||
ST_LIS2DU12_ROUNDING_XYZ_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_ROUNDING_XYZ_MASK, 1));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hw->round_xl_xyz = true;
|
||||
|
||||
for (i = ST_LIS2DU12_ID_ACC; i <= ST_LIS2DU12_MAX_BUFFER; i++) {
|
||||
if (!hw->iio_devs[i])
|
||||
continue;
|
||||
|
||||
#if KERNEL_VERSION(5, 19, 0) <= LINUX_VERSION_CODE
|
||||
ret = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i],
|
||||
&st_lis2du12_buffer_setup_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
#elif KERNEL_VERSION(5, 13, 0) <= LINUX_VERSION_CODE
|
||||
ret = devm_iio_kfifo_buffer_setup(hw->dev, hw->iio_devs[i],
|
||||
INDIO_BUFFER_SOFTWARE,
|
||||
&st_lis2du12_buffer_setup_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
#else /* LINUX_VERSION_CODE */
|
||||
buffer = devm_iio_kfifo_allocate(hw->dev);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
iio_device_attach_buffer(hw->iio_devs[i], buffer);
|
||||
hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
|
||||
hw->iio_devs[i]->setup_ops = &st_lis2du12_buffer_setup_ops;
|
||||
#endif /* LINUX_VERSION_CODE */
|
||||
}
|
||||
|
||||
ret = st_lis2du12_set_fifo_mode(hw, ST_LIS2DU12_FIFO_BYPASS);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(hw->regmap,
|
||||
hw->drdy_reg,
|
||||
ST_LIS2DU12_INT_F_FTH_MASK,
|
||||
FIELD_PREP(ST_LIS2DU12_INT_F_FTH_MASK, 1));
|
||||
}
|
1555
drivers/iio/stm/accel/st_lis2du12_core.c
Normal file
1555
drivers/iio/stm/accel/st_lis2du12_core.c
Normal file
File diff suppressed because it is too large
Load Diff
67
drivers/iio/stm/accel/st_lis2du12_i2c.c
Normal file
67
drivers/iio/stm/accel/st_lis2du12_i2c.c
Normal file
@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics st_lis2du12 i2c driver
|
||||
*
|
||||
* MEMS Software Solutions Team
|
||||
*
|
||||
* Copyright 2022 STMicroelectronics Inc.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "st_lis2du12.h"
|
||||
|
||||
static const struct regmap_config st_lis2du12_i2c_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int st_lis2du12_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client,
|
||||
&st_lis2du12_i2c_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to register i2c regmap %d\n",
|
||||
(int)PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return st_lis2du12_probe(&client->dev, client->irq, regmap);
|
||||
}
|
||||
|
||||
static const struct of_device_id st_lis2du12_i2c_of_match[] = {
|
||||
{
|
||||
.compatible = "st," ST_LIS2DU12_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lis2du12_i2c_of_match);
|
||||
|
||||
static const struct i2c_device_id st_lis2du12_i2c_id_table[] = {
|
||||
{ ST_LIS2DU12_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st_lis2du12_i2c_id_table);
|
||||
|
||||
static struct i2c_driver st_lis2du12_driver = {
|
||||
.driver = {
|
||||
.name = "st_" ST_LIS2DU12_DEV_NAME "_i2c",
|
||||
.pm = &st_lis2du12_pm_ops,
|
||||
.of_match_table = of_match_ptr(st_lis2du12_i2c_of_match),
|
||||
},
|
||||
.probe = st_lis2du12_i2c_probe,
|
||||
.id_table = st_lis2du12_i2c_id_table,
|
||||
};
|
||||
module_i2c_driver(st_lis2du12_driver);
|
||||
|
||||
MODULE_AUTHOR("MEMS Software Solutions Team");
|
||||
MODULE_DESCRIPTION("STMicroelectronics st_lis2du12 i2c driver");
|
||||
MODULE_LICENSE("GPL v2");
|
58
drivers/iio/stm/accel/st_lis2du12_i3c.c
Normal file
58
drivers/iio/stm/accel/st_lis2du12_i3c.c
Normal file
@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics st_lis2du12 i3c driver
|
||||
*
|
||||
* MEMS Software Solutions Team
|
||||
*
|
||||
* Copyright 2022 STMicroelectronics Inc.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i3c/device.h>
|
||||
#include <linux/i3c/master.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "st_lis2du12.h"
|
||||
|
||||
static const struct i3c_device_id st_lis2du12_i3c_ids[] = {
|
||||
I3C_DEVICE(0x0104, ST_LIS2DU12_WHOAMI_VAL, NULL),
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i3c, st_lis2du12_i3c_ids);
|
||||
|
||||
static int st_lis2du12_i3c_probe(struct i3c_device *i3cdev)
|
||||
{
|
||||
struct regmap_config st_lis2du12_i3c_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_i3c(i3cdev, &st_lis2du12_i3c_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&i3cdev->dev,
|
||||
"Failed to register i3c regmap %d\n",
|
||||
(int)PTR_ERR(regmap));
|
||||
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return st_lis2du12_probe(&i3cdev->dev, 0, regmap);
|
||||
}
|
||||
|
||||
static struct i3c_driver st_lis2du12_driver = {
|
||||
.driver = {
|
||||
.name = "st_" ST_LIS2DU12_DEV_NAME "_i3c",
|
||||
.pm = &st_lis2du12_pm_ops,
|
||||
},
|
||||
.probe = st_lis2du12_i3c_probe,
|
||||
.id_table = st_lis2du12_i3c_ids,
|
||||
};
|
||||
module_i3c_driver(st_lis2du12_driver);
|
||||
|
||||
MODULE_AUTHOR("MEMS Software Solutions Team");
|
||||
MODULE_DESCRIPTION("STMicroelectronics st_lis2du12 i3c driver");
|
||||
MODULE_LICENSE("GPL v2");
|
64
drivers/iio/stm/accel/st_lis2du12_spi.c
Normal file
64
drivers/iio/stm/accel/st_lis2du12_spi.c
Normal file
@ -0,0 +1,64 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics lis2du12 spi driver
|
||||
*
|
||||
* MEMS Software Solutions Team
|
||||
*
|
||||
* Copyright 2022 STMicroelectronics Inc.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "st_lis2du12.h"
|
||||
|
||||
static const struct regmap_config st_lis2du12_spi_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int st_lis2du12_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
|
||||
regmap = devm_regmap_init_spi(spi,
|
||||
&st_lis2du12_spi_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
|
||||
(int)PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
return st_lis2du12_probe(&spi->dev, spi->irq, regmap);
|
||||
}
|
||||
|
||||
static const struct of_device_id st_lis2du12_spi_of_match[] = {
|
||||
{
|
||||
.compatible = "st," ST_LIS2DU12_DEV_NAME,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, st_lis2du12_spi_of_match);
|
||||
|
||||
static const struct spi_device_id st_lis2du12_spi_id_table[] = {
|
||||
{ ST_LIS2DU12_DEV_NAME },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, st_lis2du12_spi_id_table);
|
||||
|
||||
static struct spi_driver st_lis2du12_driver = {
|
||||
.driver = {
|
||||
.name = "st_" ST_LIS2DU12_DEV_NAME "_spi",
|
||||
.pm = &st_lis2du12_pm_ops,
|
||||
.of_match_table = of_match_ptr(st_lis2du12_spi_of_match),
|
||||
},
|
||||
.probe = st_lis2du12_spi_probe,
|
||||
.id_table = st_lis2du12_spi_id_table,
|
||||
};
|
||||
module_spi_driver(st_lis2du12_driver);
|
||||
|
||||
MODULE_AUTHOR("MEMS Software Solutions Team");
|
||||
MODULE_DESCRIPTION("STMicroelectronics st_lis2du12 spi driver");
|
||||
MODULE_LICENSE("GPL v2");
|
4
stm_iio_configs/lis2du12_defconfig
Normal file
4
stm_iio_configs/lis2du12_defconfig
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_IIO_ST_LIS2DU12=m
|
||||
CONFIG_IIO_ST_LIS2DU12_I2C=m
|
||||
CONFIG_IIO_ST_LIS2DU12_SPI=m
|
||||
CONFIG_IIO_ST_LIS2DU12_I3C=m
|
Loading…
Reference in New Issue
Block a user