drivers:iio:stm:accel: Add support to ST MEMS ISM303DAC
List of supported features: - Configurable ODRs [Power_Off ... 800] Hz - Sensor Event Timestamp support - Read single accel raw data values - FIFO: > Accel data stored in FIFO > HW Watermark configuration > Custom Flush command / event support - TAP and DTAP event recognition - External trigger support Signed-off-by: mario tesi <mario.tesi@st.com> Change-Id: I948c93516fa83c7068e894a1fcc14f265b71067a Reviewed-on: https://sczcxd1104.scz.st.com/gerrit/c/linux/stm-ldd-iio/+/332 Tested-by: aosp-ger <aosp-ger@st.com> Reviewed-by: Denis CIOCCA <denis.ciocca@st.com>
This commit is contained in:
parent
a276e09d44
commit
863aa3c1a2
@ -96,4 +96,35 @@ config IIO_ST_LIS2DW12_SPI
|
||||
depends on IIO_ST_LIS2DW12
|
||||
depends on SPI
|
||||
|
||||
menuconfig IIO_ST_ISM303DAC_ACCEL
|
||||
tristate "STMicroelectronics ISM303DAC Accelerometer Driver"
|
||||
depends on (I2C || SPI_MASTER) && SYSFS
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
select IIO_ST_ISM303DAC_ACCEL_I2C if (I2C)
|
||||
select IIO_ST_ISM303DAC_ACCEL_SPI if (SPI)
|
||||
help
|
||||
Say yes here to build support for the ISM303DAC
|
||||
accelerometers.
|
||||
|
||||
config IIO_ST_ISM303DAC_ACCEL_I2C
|
||||
tristate
|
||||
depends on IIO_ST_ISM303DAC_ACCEL
|
||||
depends on I2C
|
||||
|
||||
config IIO_ST_ISM303DAC_ACCEL_SPI
|
||||
tristate
|
||||
depends on IIO_ST_ISM303DAC_ACCEL
|
||||
depends on SPI
|
||||
|
||||
config ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO
|
||||
int "Limit fifo read lenght (#n byte)"
|
||||
depends on IIO_ST_ISM303DAC_ACCEL
|
||||
range 0 1536
|
||||
default 0
|
||||
help
|
||||
Limit atomic fifo read to #n byte. In some platform i2c/spi read
|
||||
can be limited by software or hardware.
|
||||
|
||||
Set 0 to disable the limit.
|
||||
endmenu
|
||||
|
@ -19,3 +19,10 @@ st_lis2dw12-y:= st_lis2dw12_core.o st_lis2dw12_buffer.o
|
||||
obj-$(CONFIG_IIO_ST_LIS2DW12) += st_lis2dw12.o
|
||||
obj-$(CONFIG_IIO_ST_LIS2DW12_I2C) += st_lis2dw12_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_LIS2DW12_SPI) += st_lis2dw12_spi.o
|
||||
|
||||
ism303dac_accel-y += st_ism303dac_accel_core.o st_ism303dac_accel_buffer.o \
|
||||
st_ism303dac_accel_trigger.o
|
||||
obj-$(CONFIG_IIO_ST_ISM303DAC_ACCEL) += ism303dac_accel.o
|
||||
obj-$(CONFIG_IIO_ST_ISM303DAC_ACCEL_I2C) += st_ism303dac_accel_i2c.o
|
||||
obj-$(CONFIG_IIO_ST_ISM303DAC_ACCEL_SPI) += st_ism303dac_accel_spi.o
|
||||
|
||||
|
303
drivers/iio/stm/accel/st_ism303dac_accel.h
Normal file
303
drivers/iio/stm/accel/st_ism303dac_accel.h
Normal file
@ -0,0 +1,303 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* STMicroelectronics ism303dac driver
|
||||
*
|
||||
* Copyright 2018 STMicroelectronics Inc.
|
||||
*
|
||||
* Giuseppe Barba <giuseppe.barba@st.com>
|
||||
*/
|
||||
|
||||
#ifndef __ISM303DAC_H
|
||||
#define __ISM303DAC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#ifndef CONFIG_OF
|
||||
#include <linux/platform_data/ism303dac.h>
|
||||
#endif
|
||||
|
||||
#define ISM303DAC_WHO_AM_I_ADDR 0x0f
|
||||
#define ISM303DAC_WHO_AM_I_DEF 0x43
|
||||
#define ISM303DAC_CTRL1_ADDR 0x20
|
||||
#define ISM303DAC_CTRL2_ADDR 0x21
|
||||
#define ISM303DAC_CTRL3_ADDR 0x22
|
||||
#define ISM303DAC_CTRL4_INT1_PAD_ADDR 0x23
|
||||
#define ISM303DAC_CTRL5_INT2_PAD_ADDR 0x24
|
||||
#define ISM303DAC_FIFO_CTRL_ADDR 0x25
|
||||
#define ISM303DAC_OUTX_L_ADDR 0x28
|
||||
#define ISM303DAC_OUTY_L_ADDR 0x2a
|
||||
#define ISM303DAC_OUTZ_L_ADDR 0x2c
|
||||
#define ISM303DAC_TAP_THS_6D_ADDR 0x31
|
||||
#define ISM303DAC_WAKE_UP_THS_ADDR 0x33
|
||||
#define ISM303DAC_FREE_FALL_ADDR 0x35
|
||||
#define ISM303DAC_TAP_SRC_ADDR 0x38
|
||||
#define ISM303DAC_FUNC_CTRL_ADDR 0x3f
|
||||
#define ISM303DAC_FIFO_THS_ADDR 0x2e
|
||||
#define ISM303DAC_FIFO_THS_MASK 0xff
|
||||
#define ISM303DAC_ODR_ADDR ISM303DAC_CTRL1_ADDR
|
||||
#define ISM303DAC_ODR_MASK 0xf0
|
||||
#define ISM303DAC_ODR_POWER_OFF_VAL 0x00
|
||||
#define ISM303DAC_ODR_1HZ_LP_VAL 0x08
|
||||
#define ISM303DAC_ODR_12HZ_LP_VAL 0x09
|
||||
#define ISM303DAC_ODR_25HZ_LP_VAL 0x0a
|
||||
#define ISM303DAC_ODR_50HZ_LP_VAL 0x0b
|
||||
#define ISM303DAC_ODR_100HZ_LP_VAL 0x0c
|
||||
#define ISM303DAC_ODR_200HZ_LP_VAL 0x0d
|
||||
#define ISM303DAC_ODR_400HZ_LP_VAL 0x0e
|
||||
#define ISM303DAC_ODR_800HZ_LP_VAL 0x0f
|
||||
#define ISM303DAC_ODR_LP_LIST_NUM 9
|
||||
|
||||
#define ISM303DAC_ODR_12_5HZ_HR_VAL 0x01
|
||||
#define ISM303DAC_ODR_25HZ_HR_VAL 0x02
|
||||
#define ISM303DAC_ODR_50HZ_HR_VAL 0x03
|
||||
#define ISM303DAC_ODR_100HZ_HR_VAL 0x04
|
||||
#define ISM303DAC_ODR_200HZ_HR_VAL 0x05
|
||||
#define ISM303DAC_ODR_400HZ_HR_VAL 0x06
|
||||
#define ISM303DAC_ODR_800HZ_HR_VAL 0x07
|
||||
#define ISM303DAC_ODR_HR_LIST_NUM 8
|
||||
|
||||
#define ISM303DAC_FS_ADDR ISM303DAC_CTRL1_ADDR
|
||||
#define ISM303DAC_FS_MASK 0x0c
|
||||
#define ISM303DAC_FS_2G_VAL 0x00
|
||||
#define ISM303DAC_FS_4G_VAL 0x02
|
||||
#define ISM303DAC_FS_8G_VAL 0x03
|
||||
#define ISM303DAC_FS_16G_VAL 0x01
|
||||
|
||||
/* Advanced Configuration Registers */
|
||||
#define ISM303DAC_FUNC_CFG_ENTER_ADDR ISM303DAC_CTRL2_ADDR
|
||||
#define ISM303DAC_FUNC_CFG_EXIT_ADDR 0x3F
|
||||
#define ISM303DAC_FUNC_CFG_EN_MASK 0x10
|
||||
|
||||
#define ISM303DAC_SIM_ADDR ISM303DAC_CTRL2_ADDR
|
||||
#define ISM303DAC_SIM_MASK 0x01
|
||||
#define ISM303DAC_ADD_INC_MASK 0x04
|
||||
|
||||
/* Sensitivity for the 16-bit data */
|
||||
#define ISM303DAC_FS_2G_GAIN IIO_G_TO_M_S_2(61)
|
||||
#define ISM303DAC_FS_4G_GAIN IIO_G_TO_M_S_2(122)
|
||||
#define ISM303DAC_FS_8G_GAIN IIO_G_TO_M_S_2(244)
|
||||
#define ISM303DAC_FS_16G_GAIN IIO_G_TO_M_S_2(488)
|
||||
|
||||
#define ISM303DAC_MODE_DEFAULT ISM303DAC_HR_MODE
|
||||
#define ISM303DAC_INT1_S_TAP_MASK 0x40
|
||||
#define ISM303DAC_INT1_WAKEUP_MASK 0x20
|
||||
#define ISM303DAC_INT1_FREE_FALL_MASK 0x10
|
||||
#define ISM303DAC_INT1_TAP_MASK 0x08
|
||||
#define ISM303DAC_INT1_6D_MASK 0x04
|
||||
#define ISM303DAC_INT1_FTH_MASK 0x02
|
||||
#define ISM303DAC_INT1_DRDY_MASK 0x01
|
||||
#define ISM303DAC_INT1_EVENTS_MASK (ISM303DAC_INT1_S_TAP_MASK | \
|
||||
ISM303DAC_INT1_WAKEUP_MASK | \
|
||||
ISM303DAC_INT1_FREE_FALL_MASK | \
|
||||
ISM303DAC_INT1_TAP_MASK | \
|
||||
ISM303DAC_INT1_6D_MASK | \
|
||||
ISM303DAC_INT1_FTH_MASK | \
|
||||
ISM303DAC_INT1_DRDY_MASK)
|
||||
#define ISM303DAC_INT2_ON_INT1_MASK 0x20
|
||||
#define ISM303DAC_INT2_FTH_MASK 0x02
|
||||
#define ISM303DAC_INT2_DRDY_MASK 0x01
|
||||
#define ISM303DAC_INT2_EVENTS_MASK (ISM303DAC_INT2_FTH_MASK | \
|
||||
ISM303DAC_INT2_DRDY_MASK)
|
||||
#define ISM303DAC_WAKE_UP_THS_WU_MASK 0x3f
|
||||
#define ISM303DAC_WAKE_UP_THS_WU_DEFAULT 0x02
|
||||
#define ISM303DAC_FREE_FALL_THS_MASK 0x07
|
||||
#define ISM303DAC_FREE_FALL_DUR_MASK 0xF8
|
||||
#define ISM303DAC_FREE_FALL_THS_DEFAULT 0x01
|
||||
#define ISM303DAC_FREE_FALL_DUR_DEFAULT 0x01
|
||||
#define ISM303DAC_BDU_ADDR ISM303DAC_CTRL1_ADDR
|
||||
#define ISM303DAC_BDU_MASK 0x01
|
||||
#define ISM303DAC_SOFT_RESET_ADDR ISM303DAC_CTRL2_ADDR
|
||||
#define ISM303DAC_SOFT_RESET_MASK 0x40
|
||||
#define ISM303DAC_LIR_ADDR ISM303DAC_CTRL3_ADDR
|
||||
#define ISM303DAC_LIR_MASK 0x04
|
||||
#define ISM303DAC_TAP_AXIS_ADDR ISM303DAC_CTRL3_ADDR
|
||||
#define ISM303DAC_TAP_AXIS_MASK 0x38
|
||||
#define ISM303DAC_TAP_AXIS_ANABLE_ALL 0x07
|
||||
#define ISM303DAC_TAP_THS_ADDR ISM303DAC_TAP_THS_6D_ADDR
|
||||
#define ISM303DAC_TAP_THS_MASK 0x1f
|
||||
#define ISM303DAC_TAP_THS_DEFAULT 0x09
|
||||
#define ISM303DAC_INT2_ON_INT1_ADDR ISM303DAC_CTRL5_INT2_PAD_ADDR
|
||||
#define ISM303DAC_INT2_ON_INT1_MASK 0x20
|
||||
#define ISM303DAC_FIFO_MODE_ADDR ISM303DAC_FIFO_CTRL_ADDR
|
||||
#define ISM303DAC_FIFO_MODE_MASK 0xe0
|
||||
#define ISM303DAC_FIFO_MODE_BYPASS 0x00
|
||||
#define ISM303DAC_FIFO_MODE_CONTINUOS 0x06
|
||||
#define ISM303DAC_OUT_XYZ_SIZE 8
|
||||
|
||||
#define ISM303DAC_SELFTEST_ADDR ISM303DAC_CTRL3_ADDR
|
||||
#define ISM303DAC_SELFTEST_MASK 0xc0
|
||||
#define ISM303DAC_SELFTEST_NORMAL 0x00
|
||||
#define ISM303DAC_SELFTEST_POS_SIGN 0x01
|
||||
#define ISM303DAC_SELFTEST_NEG_SIGN 0x02
|
||||
|
||||
#define ISM303DAC_FIFO_SRC 0x2f
|
||||
#define ISM303DAC_FIFO_SRC_DIFF_MASK 0x20
|
||||
|
||||
#define ISM303DAC_FIFO_NUM_AXIS 3
|
||||
#define ISM303DAC_FIFO_BYTE_X_AXIS 2
|
||||
#define ISM303DAC_FIFO_BYTE_FOR_SAMPLE (ISM303DAC_FIFO_NUM_AXIS * \
|
||||
ISM303DAC_FIFO_BYTE_X_AXIS)
|
||||
#define ISM303DAC_TIMESTAMP_SIZE 8
|
||||
|
||||
#define ISM303DAC_STATUS_ADDR 0x27
|
||||
#define ISM303DAC_STATUS_DUP_ADDR 0x36
|
||||
#define ISM303DAC_WAKE_UP_IA_MASK 0x40
|
||||
#define ISM303DAC_DOUBLE_TAP_MASK 0x10
|
||||
#define ISM303DAC_TAP_MASK 0x08
|
||||
#define ISM303DAC_6D_IA_MASK 0x04
|
||||
#define ISM303DAC_FF_IA_MASK 0x02
|
||||
#define ISM303DAC_DRDY_MASK 0x01
|
||||
#define ISM303DAC_EVENT_MASK (ISM303DAC_WAKE_UP_IA_MASK | \
|
||||
ISM303DAC_DOUBLE_TAP_MASK | \
|
||||
ISM303DAC_TAP_MASK | \
|
||||
ISM303DAC_6D_IA_MASK | \
|
||||
ISM303DAC_FF_IA_MASK)
|
||||
#define ISM303DAC_FIFO_SRC_ADDR 0x2f
|
||||
#define ISM303DAC_FIFO_SRC_FTH_MASK 0x80
|
||||
|
||||
#define ISM303DAC_EN_BIT 0x01
|
||||
#define ISM303DAC_DIS_BIT 0x00
|
||||
#define ISM303DAC_ACCEL_ODR 1
|
||||
#define ISM303DAC_DEFAULT_ACCEL_FS 2
|
||||
#define ISM303DAC_FF_ODR 25
|
||||
#define ISM303DAC_TAP_ODR 400
|
||||
#define ISM303DAC_WAKEUP_ODR 25
|
||||
#define ISM303DAC_ACTIVITY_ODR 12
|
||||
#define ISM303DAC_MAX_FIFO_LENGHT 256
|
||||
#define ISM303DAC_MAX_FIFO_THS (ISM303DAC_MAX_FIFO_LENGHT - 1)
|
||||
#define ISM303DAC_MAX_CHANNEL_SPEC 5
|
||||
#define ISM303DAC_EVENT_CHANNEL_SPEC_SIZE 2
|
||||
#define ISM303DAC_MIN_DURATION_MS 1638
|
||||
|
||||
#define ISM303DAC_DEV_NAME "ism303dac_accel"
|
||||
#define SET_BIT(a, b) {a |= (1 << b);}
|
||||
#define RESET_BIT(a, b) {a &= ~(1 << b);}
|
||||
#define CHECK_BIT(a, b) (a & (1 << b))
|
||||
|
||||
enum {
|
||||
ISM303DAC_ACCEL = 0,
|
||||
ISM303DAC_TAP,
|
||||
ISM303DAC_DOUBLE_TAP,
|
||||
ISM303DAC_SENSORS_NUMB,
|
||||
};
|
||||
|
||||
#define ST_ISM303DAC_FLUSH_CHANNEL(device_type) \
|
||||
{ \
|
||||
.type = device_type, \
|
||||
.modified = 0, \
|
||||
.scan_index = -1, \
|
||||
.indexed = -1, \
|
||||
.event_spec = &ism303dac_fifo_flush_event,\
|
||||
.num_event_specs = 1, \
|
||||
}
|
||||
|
||||
#define ST_ISM303DAC_HWFIFO_ENABLED() \
|
||||
IIO_DEVICE_ATTR(hwfifo_enabled, S_IWUSR | S_IRUGO, \
|
||||
ism303dac_sysfs_get_hwfifo_enabled,\
|
||||
ism303dac_sysfs_set_hwfifo_enabled, 0);
|
||||
|
||||
#define ST_ISM303DAC_HWFIFO_WATERMARK() \
|
||||
IIO_DEVICE_ATTR(hwfifo_watermark, S_IWUSR | S_IRUGO, \
|
||||
ism303dac_sysfs_get_hwfifo_watermark,\
|
||||
ism303dac_sysfs_set_hwfifo_watermark, 0);
|
||||
|
||||
#define ST_ISM303DAC_HWFIFO_WATERMARK_MIN() \
|
||||
IIO_DEVICE_ATTR(hwfifo_watermark_min, S_IRUGO, \
|
||||
ism303dac_sysfs_get_hwfifo_watermark_min, NULL, 0);
|
||||
|
||||
#define ST_ISM303DAC_HWFIFO_WATERMARK_MAX() \
|
||||
IIO_DEVICE_ATTR(hwfifo_watermark_max, S_IRUGO, \
|
||||
ism303dac_sysfs_get_hwfifo_watermark_max, NULL, 0);
|
||||
|
||||
#define ST_ISM303DAC_HWFIFO_FLUSH() \
|
||||
IIO_DEVICE_ATTR(hwfifo_flush, S_IWUSR, NULL, \
|
||||
ism303dac_sysfs_flush_fifo, 0);
|
||||
|
||||
enum fifo_mode {
|
||||
BYPASS = 0,
|
||||
CONTINUOS,
|
||||
};
|
||||
|
||||
#define ISM303DAC_TX_MAX_LENGTH 12
|
||||
#define ISM303DAC_RX_MAX_LENGTH 8193
|
||||
#define ISM303DAC_EWMA_DIV 128
|
||||
|
||||
struct ism303dac_transfer_buffer {
|
||||
struct mutex buf_lock;
|
||||
u8 rx_buf[ISM303DAC_RX_MAX_LENGTH];
|
||||
u8 tx_buf[ISM303DAC_TX_MAX_LENGTH] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
struct ism303dac_data;
|
||||
|
||||
struct ism303dac_transfer_function {
|
||||
int (*write)(struct ism303dac_data *cdata, u8 reg_addr, int len,
|
||||
u8 *data, bool b_lock);
|
||||
int (*read)(struct ism303dac_data *cdata, u8 reg_addr, int len,
|
||||
u8 *data, bool b_lock);
|
||||
};
|
||||
|
||||
struct ism303dac_sensor_data {
|
||||
struct ism303dac_data *cdata;
|
||||
const char *name;
|
||||
s64 timestamp;
|
||||
u8 enabled;
|
||||
u32 odr;
|
||||
u32 gain;
|
||||
u8 sindex;
|
||||
u8 sample_to_discard;
|
||||
};
|
||||
|
||||
struct ism303dac_data {
|
||||
const char *name;
|
||||
u8 drdy_int_pin;
|
||||
bool spi_3wire;
|
||||
u8 selftest_status;
|
||||
u8 hwfifo_enabled;
|
||||
u8 hwfifo_watermark;
|
||||
u8 power_mode;
|
||||
u8 enabled_sensor;
|
||||
u32 common_odr;
|
||||
int irq;
|
||||
s64 timestamp;
|
||||
s64 accel_deltatime;
|
||||
s64 sample_timestamp;
|
||||
u8 *fifo_data;
|
||||
u16 fifo_size;
|
||||
u64 samples;
|
||||
u8 std_level;
|
||||
struct mutex fifo_lock;
|
||||
struct device *dev;
|
||||
struct iio_dev *iio_sensors_dev[ISM303DAC_SENSORS_NUMB];
|
||||
struct iio_trigger *iio_trig[ISM303DAC_SENSORS_NUMB];
|
||||
struct mutex regs_lock;
|
||||
const struct ism303dac_transfer_function *tf;
|
||||
struct ism303dac_transfer_buffer tb;
|
||||
};
|
||||
|
||||
static inline s64 ism303dac_get_time_ns(struct iio_dev *iio_sensors_dev)
|
||||
{
|
||||
return iio_get_time_ns(iio_sensors_dev);
|
||||
}
|
||||
|
||||
int ism303dac_common_probe(struct ism303dac_data *cdata, int irq);
|
||||
#ifdef CONFIG_PM
|
||||
int ism303dac_common_suspend(struct ism303dac_data *cdata);
|
||||
int ism303dac_common_resume(struct ism303dac_data *cdata);
|
||||
#endif
|
||||
int ism303dac_allocate_rings(struct ism303dac_data *cdata);
|
||||
int ism303dac_allocate_triggers(struct ism303dac_data *cdata,
|
||||
const struct iio_trigger_ops *trigger_ops);
|
||||
int ism303dac_trig_set_state(struct iio_trigger *trig, bool state);
|
||||
int ism303dac_read_register(struct ism303dac_data *cdata, u8 reg_addr,
|
||||
int data_len, u8 *data, bool b_lock);
|
||||
int ism303dac_update_drdy_irq(struct ism303dac_sensor_data *sdata, bool state);
|
||||
int ism303dac_set_enable(struct ism303dac_sensor_data *sdata, bool enable);
|
||||
void ism303dac_common_remove(struct ism303dac_data *cdata, int irq);
|
||||
void ism303dac_read_xyz(struct ism303dac_data *cdata);
|
||||
void ism303dac_read_fifo(struct ism303dac_data *cdata, bool check_fifo_len);
|
||||
void ism303dac_deallocate_rings(struct ism303dac_data *cdata);
|
||||
void ism303dac_deallocate_triggers(struct ism303dac_data *cdata);
|
||||
|
||||
#endif /* __ISM303DAC_H */
|
212
drivers/iio/stm/accel/st_ism303dac_accel_buffer.c
Normal file
212
drivers/iio/stm/accel/st_ism303dac_accel_buffer.c
Normal file
@ -0,0 +1,212 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics ism303dac driver
|
||||
*
|
||||
* Copyright 2018 STMicroelectronics Inc.
|
||||
*
|
||||
* Giuseppe Barba <giuseppe.barba@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#include "st_ism303dac_accel.h"
|
||||
|
||||
#define ISM303DAC_ACCEL_BUFFER_SIZE \
|
||||
ALIGN(ISM303DAC_FIFO_BYTE_FOR_SAMPLE + ISM303DAC_TIMESTAMP_SIZE, \
|
||||
ISM303DAC_TIMESTAMP_SIZE)
|
||||
|
||||
static void ism303dac_push_accel_data(struct ism303dac_data *cdata,
|
||||
u8 *acc_buf, u16 read_length)
|
||||
{
|
||||
size_t offset;
|
||||
uint16_t i, j, k;
|
||||
u8 buffer[ISM303DAC_ACCEL_BUFFER_SIZE], out_buf_index;
|
||||
struct iio_dev *indio_dev = cdata->iio_sensors_dev[ISM303DAC_ACCEL];
|
||||
u32 delta_ts = div_s64(cdata->accel_deltatime, cdata->hwfifo_watermark);
|
||||
|
||||
for (i = 0; i < read_length; i += ISM303DAC_FIFO_BYTE_FOR_SAMPLE) {
|
||||
/* Skip first samples. */
|
||||
if (unlikely(++cdata->samples <= cdata->std_level)) {
|
||||
cdata->sample_timestamp += delta_ts;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0, out_buf_index = 0; j < ISM303DAC_FIFO_NUM_AXIS;
|
||||
j++) {
|
||||
k = i + ISM303DAC_FIFO_BYTE_X_AXIS * j;
|
||||
if (test_bit(j, indio_dev->active_scan_mask)) {
|
||||
memcpy(&buffer[out_buf_index],
|
||||
&acc_buf[k],
|
||||
ISM303DAC_FIFO_BYTE_X_AXIS);
|
||||
out_buf_index += ISM303DAC_FIFO_BYTE_X_AXIS;
|
||||
}
|
||||
}
|
||||
|
||||
if (indio_dev->scan_timestamp) {
|
||||
offset = indio_dev->scan_bytes / sizeof(s64) - 1;
|
||||
((s64 *)buffer)[offset] = cdata->sample_timestamp;
|
||||
cdata->sample_timestamp += delta_ts;
|
||||
}
|
||||
|
||||
iio_push_to_buffers(indio_dev, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void ism303dac_read_xyz(struct ism303dac_data *cdata)
|
||||
{
|
||||
int err;
|
||||
u8 xyz_buf[ISM303DAC_FIFO_BYTE_FOR_SAMPLE];
|
||||
|
||||
err = ism303dac_read_register(cdata, ISM303DAC_OUTX_L_ADDR,
|
||||
ISM303DAC_FIFO_BYTE_FOR_SAMPLE, xyz_buf, true);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
cdata->sample_timestamp = cdata->timestamp;
|
||||
ism303dac_push_accel_data(cdata, xyz_buf, ISM303DAC_FIFO_BYTE_FOR_SAMPLE);
|
||||
}
|
||||
|
||||
void ism303dac_read_fifo(struct ism303dac_data *cdata, bool check_fifo_len)
|
||||
{
|
||||
int err;
|
||||
u8 fifo_src[2];
|
||||
u16 read_len;
|
||||
#if (CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO > 0)
|
||||
u16 data_remaining, data_to_read, extra_bytes;
|
||||
#endif /* CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO */
|
||||
|
||||
err = ism303dac_read_register(cdata, ISM303DAC_FIFO_SRC, 2,
|
||||
fifo_src, true);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
read_len = (fifo_src[0] & ISM303DAC_FIFO_SRC_DIFF_MASK) ? (1 << 8) : 0;
|
||||
read_len |= fifo_src[1];
|
||||
read_len *= ISM303DAC_FIFO_BYTE_FOR_SAMPLE;
|
||||
|
||||
if (read_len == 0)
|
||||
return;
|
||||
|
||||
#if (CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO == 0)
|
||||
err = ism303dac_read_register(cdata, ISM303DAC_OUTX_L_ADDR, read_len,
|
||||
cdata->fifo_data, true);
|
||||
if (err < 0)
|
||||
return;
|
||||
#else /* CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO */
|
||||
data_remaining = read_len;
|
||||
|
||||
do {
|
||||
if (data_remaining > CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO)
|
||||
data_to_read = CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO;
|
||||
else
|
||||
data_to_read = data_remaining;
|
||||
|
||||
extra_bytes = (data_to_read % ISM303DAC_FIFO_BYTE_FOR_SAMPLE);
|
||||
if (extra_bytes != 0) {
|
||||
data_to_read -= extra_bytes;
|
||||
|
||||
if (data_to_read < ISM303DAC_FIFO_BYTE_FOR_SAMPLE)
|
||||
data_to_read = ISM303DAC_FIFO_BYTE_FOR_SAMPLE;
|
||||
}
|
||||
|
||||
err = ism303dac_read_register(cdata, ISM303DAC_OUTX_L_ADDR, data_to_read,
|
||||
&cdata->fifo_data[read_len - data_remaining], true);
|
||||
if (err < 0)
|
||||
return;
|
||||
|
||||
data_remaining -= data_to_read;
|
||||
} while (data_remaining > 0);
|
||||
#endif /* CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO */
|
||||
|
||||
ism303dac_push_accel_data(cdata, cdata->fifo_data, read_len);
|
||||
}
|
||||
|
||||
static inline irqreturn_t ism303dac_handler_empty(int irq, void *p)
|
||||
{
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int ism303dac_trig_set_state(struct iio_trigger *trig, bool state)
|
||||
{
|
||||
int err;
|
||||
struct ism303dac_sensor_data *sdata;
|
||||
|
||||
sdata = iio_priv(iio_trigger_get_drvdata(trig));
|
||||
err = ism303dac_update_drdy_irq(sdata, state);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
static int ism303dac_buffer_preenable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int err;
|
||||
struct ism303dac_sensor_data *sdata = iio_priv(indio_dev);
|
||||
|
||||
err = ism303dac_set_enable(sdata, true);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ism303dac_buffer_postdisable(struct iio_dev *indio_dev)
|
||||
{
|
||||
int err;
|
||||
struct ism303dac_sensor_data *sdata = iio_priv(indio_dev);
|
||||
|
||||
err = ism303dac_set_enable(sdata, false);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops ism303dac_buffer_setup_ops = {
|
||||
.preenable = &ism303dac_buffer_preenable,
|
||||
.postdisable = &ism303dac_buffer_postdisable,
|
||||
};
|
||||
|
||||
int ism303dac_allocate_rings(struct ism303dac_data *cdata)
|
||||
{
|
||||
int err, i;
|
||||
|
||||
for (i = 0; i < ISM303DAC_SENSORS_NUMB; i++) {
|
||||
err = iio_triggered_buffer_setup(
|
||||
cdata->iio_sensors_dev[i],
|
||||
&ism303dac_handler_empty,
|
||||
NULL,
|
||||
&ism303dac_buffer_setup_ops);
|
||||
if (err < 0)
|
||||
goto buffer_cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
buffer_cleanup:
|
||||
for (i--; i >= 0; i--)
|
||||
iio_triggered_buffer_cleanup(cdata->iio_sensors_dev[i]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void ism303dac_deallocate_rings(struct ism303dac_data *cdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ISM303DAC_SENSORS_NUMB; i++)
|
||||
iio_triggered_buffer_cleanup(cdata->iio_sensors_dev[i]);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics ism303dac iio buffer driver");
|
||||
MODULE_AUTHOR("Giuseppe Barba");
|
||||
MODULE_LICENSE("GPL v2");
|
1266
drivers/iio/stm/accel/st_ism303dac_accel_core.c
Normal file
1266
drivers/iio/stm/accel/st_ism303dac_accel_core.c
Normal file
File diff suppressed because it is too large
Load Diff
171
drivers/iio/stm/accel/st_ism303dac_accel_i2c.c
Normal file
171
drivers/iio/stm/accel/st_ism303dac_accel_i2c.c
Normal file
@ -0,0 +1,171 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics ism303dac i2c driver
|
||||
*
|
||||
* Copyright 2018 STMicroelectronics Inc.
|
||||
*
|
||||
* Giuseppe Barba <giuseppe.barba@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "st_ism303dac_accel.h"
|
||||
|
||||
static int ism303dac_i2c_read(struct ism303dac_data *cdata, u8 reg_addr, int len,
|
||||
u8 * data, bool b_lock)
|
||||
{
|
||||
int err = 0;
|
||||
struct i2c_msg msg[2];
|
||||
struct i2c_client *client = to_i2c_client(cdata->dev);
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = client->flags;
|
||||
msg[0].len = 1;
|
||||
msg[0].buf = ®_addr;
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].flags = client->flags | I2C_M_RD;
|
||||
msg[1].len = len;
|
||||
msg[1].buf = data;
|
||||
|
||||
if (b_lock) {
|
||||
mutex_lock(&cdata->regs_lock);
|
||||
err = i2c_transfer(client->adapter, msg, 2);
|
||||
mutex_unlock(&cdata->regs_lock);
|
||||
} else
|
||||
err = i2c_transfer(client->adapter, msg, 2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ism303dac_i2c_write(struct ism303dac_data *cdata, u8 reg_addr, int len,
|
||||
u8 * data, bool b_lock)
|
||||
{
|
||||
int err = 0;
|
||||
u8 send[len + 1];
|
||||
struct i2c_msg msg;
|
||||
struct i2c_client *client = to_i2c_client(cdata->dev);
|
||||
|
||||
send[0] = reg_addr;
|
||||
memcpy(&send[1], data, len * sizeof(u8));
|
||||
len++;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags;
|
||||
msg.len = len;
|
||||
msg.buf = send;
|
||||
|
||||
if (b_lock) {
|
||||
mutex_lock(&cdata->regs_lock);
|
||||
err = i2c_transfer(client->adapter, &msg, 1);
|
||||
mutex_unlock(&cdata->regs_lock);
|
||||
} else
|
||||
err = i2c_transfer(client->adapter, &msg, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct ism303dac_transfer_function ism303dac_tf_i2c = {
|
||||
.write = ism303dac_i2c_write,
|
||||
.read = ism303dac_i2c_read,
|
||||
};
|
||||
|
||||
static int ism303dac_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int err;
|
||||
struct ism303dac_data *cdata;
|
||||
|
||||
cdata = kzalloc(sizeof(*cdata), GFP_KERNEL);
|
||||
if (!cdata)
|
||||
return -ENOMEM;
|
||||
|
||||
cdata->dev = &client->dev;
|
||||
cdata->name = client->name;
|
||||
cdata->tf = &ism303dac_tf_i2c;
|
||||
i2c_set_clientdata(client, cdata);
|
||||
|
||||
err = ism303dac_common_probe(cdata, client->irq);
|
||||
if (err < 0)
|
||||
goto free_data;
|
||||
|
||||
return 0;
|
||||
|
||||
free_data:
|
||||
kfree(cdata);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ism303dac_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ism303dac_data *cdata = i2c_get_clientdata(client);
|
||||
|
||||
ism303dac_common_remove(cdata, client->irq);
|
||||
dev_info(cdata->dev, "%s: removed\n", ISM303DAC_DEV_NAME);
|
||||
kfree(cdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int __maybe_unused ism303dac_suspend(struct device *dev)
|
||||
{
|
||||
struct ism303dac_data *cdata = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
return ism303dac_common_suspend(cdata);
|
||||
}
|
||||
|
||||
static int __maybe_unused ism303dac_resume(struct device *dev)
|
||||
{
|
||||
struct ism303dac_data *cdata = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
return ism303dac_common_resume(cdata);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ism303dac_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ism303dac_suspend, ism303dac_resume)
|
||||
};
|
||||
|
||||
#define ISM303DAC_PM_OPS (&ism303dac_pm_ops)
|
||||
#else /* CONFIG_PM */
|
||||
#define ISM303DAC_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct i2c_device_id ism303dac_ids[] = {
|
||||
{ ISM303DAC_DEV_NAME, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, ism303dac_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ism303dac_id_table[] = {
|
||||
{.compatible = "st,ism303dac_accel",},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, ism303dac_id_table);
|
||||
#endif
|
||||
|
||||
static struct i2c_driver ism303dac_i2c_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = ISM303DAC_DEV_NAME,
|
||||
.pm = ISM303DAC_PM_OPS,
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = ism303dac_id_table,
|
||||
#endif
|
||||
},
|
||||
.probe = ism303dac_i2c_probe,
|
||||
.remove = ism303dac_i2c_remove,
|
||||
.id_table = ism303dac_ids,
|
||||
};
|
||||
|
||||
module_i2c_driver(ism303dac_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics ism303dac i2c driver");
|
||||
MODULE_AUTHOR("Giuseppe Barba");
|
||||
MODULE_LICENSE("GPL v2");
|
193
drivers/iio/stm/accel/st_ism303dac_accel_spi.c
Normal file
193
drivers/iio/stm/accel/st_ism303dac_accel_spi.c
Normal file
@ -0,0 +1,193 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics ism303dac spi driver
|
||||
*
|
||||
* Copyright 2018 STMicroelectronics Inc.
|
||||
*
|
||||
* Armando Visconti <armando.visconti@st.com>
|
||||
* Giuseppe Barba <giuseppe.barba@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "st_ism303dac_accel.h"
|
||||
|
||||
#define ST_SENSORS_SPI_READ 0x80
|
||||
|
||||
static int ism303dac_spi_read(struct ism303dac_data *cdata,
|
||||
u8 reg_addr, int len, u8 *data, bool b_lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
struct spi_transfer xfers[] = {
|
||||
{
|
||||
.tx_buf = cdata->tb.tx_buf,
|
||||
.bits_per_word = 8,
|
||||
.len = 1,
|
||||
},
|
||||
{
|
||||
.rx_buf = cdata->tb.rx_buf,
|
||||
.bits_per_word = 8,
|
||||
.len = len,
|
||||
}
|
||||
};
|
||||
|
||||
if (b_lock)
|
||||
mutex_lock(&cdata->regs_lock);
|
||||
|
||||
mutex_lock(&cdata->tb.buf_lock);
|
||||
cdata->tb.tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
|
||||
|
||||
err = spi_sync_transfer(to_spi_device(cdata->dev),
|
||||
xfers, ARRAY_SIZE(xfers));
|
||||
if (err)
|
||||
goto acc_spi_read_error;
|
||||
|
||||
memcpy(data, cdata->tb.rx_buf, len*sizeof(u8));
|
||||
mutex_unlock(&cdata->tb.buf_lock);
|
||||
if (b_lock)
|
||||
mutex_unlock(&cdata->regs_lock);
|
||||
|
||||
return len;
|
||||
|
||||
acc_spi_read_error:
|
||||
mutex_unlock(&cdata->tb.buf_lock);
|
||||
if (b_lock)
|
||||
mutex_unlock(&cdata->regs_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ism303dac_spi_write(struct ism303dac_data *cdata,
|
||||
u8 reg_addr, int len, u8 *data, bool b_lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
struct spi_transfer xfers = {
|
||||
.tx_buf = cdata->tb.tx_buf,
|
||||
.bits_per_word = 8,
|
||||
.len = len + 1,
|
||||
};
|
||||
|
||||
if (len >= ISM303DAC_RX_MAX_LENGTH)
|
||||
return -ENOMEM;
|
||||
|
||||
if (b_lock)
|
||||
mutex_lock(&cdata->regs_lock);
|
||||
|
||||
mutex_lock(&cdata->tb.buf_lock);
|
||||
cdata->tb.tx_buf[0] = reg_addr;
|
||||
|
||||
memcpy(&cdata->tb.tx_buf[1], data, len);
|
||||
|
||||
err = spi_sync_transfer(to_spi_device(cdata->dev), &xfers, 1);
|
||||
mutex_unlock(&cdata->tb.buf_lock);
|
||||
if (b_lock)
|
||||
mutex_unlock(&cdata->regs_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct ism303dac_transfer_function ism303dac_tf_spi = {
|
||||
.write = ism303dac_spi_write,
|
||||
.read = ism303dac_spi_read,
|
||||
};
|
||||
|
||||
static int ism303dac_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
int err;
|
||||
struct ism303dac_data *cdata;
|
||||
|
||||
cdata = kzalloc(sizeof(*cdata), GFP_KERNEL);
|
||||
if (!cdata)
|
||||
return -ENOMEM;
|
||||
|
||||
cdata->dev = &spi->dev;
|
||||
cdata->name = spi->modalias;
|
||||
cdata->tf = &ism303dac_tf_spi;
|
||||
spi_set_drvdata(spi, cdata);
|
||||
|
||||
err = ism303dac_common_probe(cdata, spi->irq);
|
||||
if (err < 0)
|
||||
goto free_data;
|
||||
|
||||
return 0;
|
||||
|
||||
free_data:
|
||||
kfree(cdata);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ism303dac_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct ism303dac_data *cdata = spi_get_drvdata(spi);
|
||||
|
||||
ism303dac_common_remove(cdata, spi->irq);
|
||||
dev_info(cdata->dev, "%s: removed\n", ISM303DAC_DEV_NAME);
|
||||
kfree(cdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int __maybe_unused ism303dac_suspend(struct device *dev)
|
||||
{
|
||||
struct ism303dac_data *cdata = spi_get_drvdata(to_spi_device(dev));
|
||||
|
||||
return ism303dac_common_suspend(cdata);
|
||||
}
|
||||
|
||||
static int __maybe_unused ism303dac_resume(struct device *dev)
|
||||
{
|
||||
struct ism303dac_data *cdata = spi_get_drvdata(to_spi_device(dev));
|
||||
|
||||
return ism303dac_common_resume(cdata);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ism303dac_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(ism303dac_suspend, ism303dac_resume)
|
||||
};
|
||||
|
||||
#define ISM303DAC_PM_OPS (&ism303dac_pm_ops)
|
||||
#else /* CONFIG_PM */
|
||||
#define ISM303DAC_PM_OPS NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct spi_device_id ism303dac_ids[] = {
|
||||
{ ISM303DAC_DEV_NAME, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(spi, ism303dac_ids);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id ism303dac_id_table[] = {
|
||||
{.compatible = "st,ism303dac_accel",},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, ism303dac_id_table);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static struct spi_driver ism303dac_spi_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = ISM303DAC_DEV_NAME,
|
||||
.pm = ISM303DAC_PM_OPS,
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = ism303dac_id_table,
|
||||
#endif /* CONFIG_OF */
|
||||
},
|
||||
.probe = ism303dac_spi_probe,
|
||||
.remove = ism303dac_spi_remove,
|
||||
.id_table = ism303dac_ids,
|
||||
};
|
||||
|
||||
module_spi_driver(ism303dac_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics ism303dac spi driver");
|
||||
MODULE_AUTHOR("Armando Visconti <armando.visconti@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
162
drivers/iio/stm/accel/st_ism303dac_accel_trigger.c
Normal file
162
drivers/iio/stm/accel/st_ism303dac_accel_trigger.c
Normal file
@ -0,0 +1,162 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* STMicroelectronics ism303dac driver
|
||||
*
|
||||
* Copyright 2018 STMicroelectronics Inc.
|
||||
*
|
||||
* Giuseppe Barba <giuseppe.barba@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iio/events.h>
|
||||
|
||||
#include "st_ism303dac_accel.h"
|
||||
|
||||
static void ism303dac_event_management(struct ism303dac_data *cdata,
|
||||
u8 int_reg_val)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
/* Must read TAP_SRC to remove irq bits */
|
||||
cdata->tf->read(cdata, ISM303DAC_TAP_SRC_ADDR, 1, &status, true);
|
||||
|
||||
if (CHECK_BIT(cdata->enabled_sensor, ISM303DAC_TAP) &&
|
||||
(int_reg_val & ISM303DAC_TAP_MASK))
|
||||
iio_push_event(cdata->iio_sensors_dev[ISM303DAC_TAP],
|
||||
IIO_UNMOD_EVENT_CODE(IIO_TAP, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
cdata->timestamp);
|
||||
|
||||
if (CHECK_BIT(cdata->enabled_sensor, ISM303DAC_DOUBLE_TAP) &&
|
||||
(int_reg_val & ISM303DAC_DOUBLE_TAP_MASK))
|
||||
iio_push_event(cdata->iio_sensors_dev[ISM303DAC_DOUBLE_TAP],
|
||||
IIO_UNMOD_EVENT_CODE(IIO_TAP_TAP, 0,
|
||||
IIO_EV_TYPE_THRESH,
|
||||
IIO_EV_DIR_EITHER),
|
||||
cdata->timestamp);
|
||||
}
|
||||
|
||||
static inline s64 st_ism303dac_ewma(s64 old, s64 new, int weight)
|
||||
{
|
||||
s64 diff, incr;
|
||||
|
||||
diff = new - old;
|
||||
incr = div_s64((ISM303DAC_EWMA_DIV - weight) *
|
||||
diff, ISM303DAC_EWMA_DIV);
|
||||
|
||||
return old + incr;
|
||||
}
|
||||
|
||||
static irqreturn_t ism303dac_irq_handler(int irq, void *private)
|
||||
{
|
||||
u8 ewma_level;
|
||||
struct ism303dac_data *cdata = private;
|
||||
s64 ts;
|
||||
|
||||
ewma_level = (cdata->common_odr >= 100) ? 120 : 96;
|
||||
ts = ism303dac_get_time_ns(cdata->iio_sensors_dev[ISM303DAC_ACCEL]);
|
||||
cdata->accel_deltatime = st_ism303dac_ewma(cdata->accel_deltatime,
|
||||
ts - cdata->timestamp,
|
||||
ewma_level);
|
||||
cdata->timestamp = ts;
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t ism303dac_irq_thread(int irq, void *private)
|
||||
{
|
||||
u8 status;
|
||||
struct ism303dac_data *cdata = private;
|
||||
|
||||
if (CHECK_BIT(cdata->enabled_sensor, ISM303DAC_ACCEL)) {
|
||||
if (cdata->hwfifo_enabled) {
|
||||
mutex_lock(&cdata->fifo_lock);
|
||||
ism303dac_read_fifo(cdata, true);
|
||||
mutex_unlock(&cdata->fifo_lock);
|
||||
} else {
|
||||
cdata->tf->read(cdata, ISM303DAC_STATUS_DUP_ADDR, 1, &status, true);
|
||||
if (status & (ISM303DAC_DRDY_MASK))
|
||||
ism303dac_read_xyz(cdata);
|
||||
}
|
||||
}
|
||||
|
||||
if (cdata->enabled_sensor & ~(1 << ISM303DAC_ACCEL)) {
|
||||
cdata->tf->read(cdata, ISM303DAC_STATUS_DUP_ADDR, 1, &status, true);
|
||||
if (status & ISM303DAC_EVENT_MASK)
|
||||
ism303dac_event_management(cdata, status);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int ism303dac_allocate_triggers(struct ism303dac_data *cdata,
|
||||
const struct iio_trigger_ops *trigger_ops)
|
||||
{
|
||||
int err, i, n;
|
||||
|
||||
for (i = 0; i < ISM303DAC_SENSORS_NUMB; i++) {
|
||||
cdata->iio_trig[i] = iio_trigger_alloc("%s-trigger",
|
||||
cdata->iio_sensors_dev[i]->name);
|
||||
if (!cdata->iio_trig[i]) {
|
||||
dev_err(cdata->dev, "failed to allocate iio trigger.\n");
|
||||
err = -ENOMEM;
|
||||
|
||||
goto deallocate_trigger;
|
||||
}
|
||||
iio_trigger_set_drvdata(cdata->iio_trig[i],
|
||||
cdata->iio_sensors_dev[i]);
|
||||
cdata->iio_trig[i]->ops = trigger_ops;
|
||||
cdata->iio_trig[i]->dev.parent = cdata->dev;
|
||||
}
|
||||
|
||||
err = request_threaded_irq(cdata->irq,
|
||||
ism303dac_irq_handler,
|
||||
ism303dac_irq_thread,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
cdata->name, cdata);
|
||||
if (err)
|
||||
goto deallocate_trigger;
|
||||
|
||||
for (n = 0; n < ISM303DAC_SENSORS_NUMB; n++) {
|
||||
err = iio_trigger_register(cdata->iio_trig[n]);
|
||||
if (err < 0) {
|
||||
dev_err(cdata->dev, "failed to register iio trigger.\n");
|
||||
|
||||
goto free_irq;
|
||||
}
|
||||
|
||||
cdata->iio_sensors_dev[n]->trig = cdata->iio_trig[n];
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_irq:
|
||||
free_irq(cdata->irq, cdata);
|
||||
for (n--; n >= 0; n--)
|
||||
iio_trigger_unregister(cdata->iio_trig[n]);
|
||||
deallocate_trigger:
|
||||
for (i--; i >= 0; i--)
|
||||
iio_trigger_free(cdata->iio_trig[i]);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void ism303dac_deallocate_triggers(struct ism303dac_data *cdata)
|
||||
{
|
||||
int i;
|
||||
|
||||
free_irq(cdata->irq, cdata);
|
||||
|
||||
for (i = 0; i < ISM303DAC_SENSORS_NUMB; i++)
|
||||
iio_trigger_unregister(cdata->iio_trig[i]);
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("STMicroelectronics ism303dac iio trigger driver");
|
||||
MODULE_AUTHOR("Giuseppe Barba");
|
||||
MODULE_LICENSE("GPL v2");
|
4
stm_iio_configs/ism303dac_defconfig
Normal file
4
stm_iio_configs/ism303dac_defconfig
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_IIO_ST_ISM303DAC_ACCEL=m
|
||||
CONFIG_IIO_ST_ISM303DAC_ACCEL_I2C=m
|
||||
CONFIG_IIO_ST_ISM303DAC_ACCEL_SPI=m
|
||||
CONFIG_ST_ISM303DAC_ACCEL_IIO_LIMIT_FIFO=0
|
Loading…
Reference in New Issue
Block a user