driver/sensor: add LIS2DW12 sensor support
Add support to STM LIS2DW12 3-axis accelerometer driver. The driver support I2C and SPI bus communication and both polling and drdy trigger mode. Co-authored-by: Mario Tesi <mario.tesi@st.com> Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
parent
c7606609be
commit
208f565bce
14 changed files with 1248 additions and 0 deletions
|
@ -22,6 +22,7 @@ add_subdirectory_ifdef(CONFIG_HTS221 hts221)
|
|||
add_subdirectory_ifdef(CONFIG_ISL29035 isl29035)
|
||||
add_subdirectory_ifdef(CONFIG_LIS2DH lis2dh)
|
||||
add_subdirectory_ifdef(CONFIG_LIS2DS12 lis2ds12)
|
||||
add_subdirectory_ifdef(CONFIG_LIS2DW12 lis2dw12)
|
||||
add_subdirectory_ifdef(CONFIG_LIS2MDL lis2mdl)
|
||||
add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl)
|
||||
add_subdirectory_ifdef(CONFIG_LPS22HB lps22hb)
|
||||
|
|
|
@ -73,6 +73,8 @@ source "drivers/sensor/lis2dh/Kconfig"
|
|||
|
||||
source "drivers/sensor/lis2ds12/Kconfig"
|
||||
|
||||
source "drivers/sensor/lis2dw12/Kconfig"
|
||||
|
||||
source "drivers/sensor/lis2mdl/Kconfig"
|
||||
|
||||
source "drivers/sensor/lis3mdl/Kconfig"
|
||||
|
|
12
drivers/sensor/lis2dw12/CMakeLists.txt
Normal file
12
drivers/sensor/lis2dw12/CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
# ST Microelectronics LIS2DW12 3-axis accelerometer driver
|
||||
#
|
||||
# Copyright (c) 2019 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
zephyr_library()
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_LIS2DW12 lis2dw12)
|
||||
zephyr_library_sources_ifdef(CONFIG_LIS2DW12 lis2dw12_i2c.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LIS2DW12 lis2dw12_spi.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_LIS2DW12_TRIGGER lis2dw12_trigger.c)
|
141
drivers/sensor/lis2dw12/Kconfig
Normal file
141
drivers/sensor/lis2dw12/Kconfig
Normal file
|
@ -0,0 +1,141 @@
|
|||
# ST Microelectronics LIS2DW12 3-axis accelerometer driver
|
||||
#
|
||||
# Copyright (c) 2019 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
menuconfig LIS2DW12
|
||||
bool "LIS2DW12 I2C/SPI accelerometer sensor driver"
|
||||
depends on (I2C && HAS_DTS_I2C) || (SPI && HAS_DTS_SPI)
|
||||
help
|
||||
Enable driver for LIS2DW12 accelerometer sensor driver
|
||||
|
||||
if LIS2DW12
|
||||
|
||||
choice LIS2DW12_TRIGGER_MODE
|
||||
prompt "Trigger mode"
|
||||
help
|
||||
Specify the type of triggering to be used by the driver.
|
||||
|
||||
config LIS2DW12_TRIGGER_NONE
|
||||
bool "No trigger"
|
||||
|
||||
config LIS2DW12_TRIGGER_GLOBAL_THREAD
|
||||
bool "Use global thread"
|
||||
depends on GPIO
|
||||
select LIS2DW12_TRIGGER
|
||||
|
||||
config LIS2DW12_TRIGGER_OWN_THREAD
|
||||
bool "Use own thread"
|
||||
depends on GPIO
|
||||
select LIS2DW12_TRIGGER
|
||||
|
||||
endchoice
|
||||
|
||||
config LIS2DW12_TRIGGER
|
||||
bool
|
||||
|
||||
if LIS2DW12_TRIGGER
|
||||
|
||||
config LIS2DW12_THREAD_PRIORITY
|
||||
int "Thread priority"
|
||||
depends on LIS2DW12_TRIGGER_OWN_THREAD
|
||||
default 10
|
||||
help
|
||||
Priority of thread used by the driver to handle interrupts.
|
||||
|
||||
config LIS2DW12_THREAD_STACK_SIZE
|
||||
int "Thread stack size"
|
||||
depends on LIS2DW12_TRIGGER_OWN_THREAD
|
||||
default 1024
|
||||
help
|
||||
Stack size of thread used by the driver to handle interrupts.
|
||||
|
||||
choice
|
||||
prompt "Sensor INT pin number"
|
||||
default LIS2DW12_INT_PIN_1
|
||||
help
|
||||
The number of LIS2DW12 int pin used to generate interrupt to cpu.
|
||||
Supported values are int1 or int2
|
||||
|
||||
config LIS2DW12_INT_PIN_1
|
||||
bool "int1"
|
||||
|
||||
config LIS2DW12_INT_PIN_2
|
||||
bool "int2"
|
||||
endchoice
|
||||
|
||||
endif # LIS2DW12_TRIGGER
|
||||
|
||||
choice
|
||||
prompt "Accelerometer Full-scale range setting"
|
||||
depends on LIS2DW12
|
||||
default LIS2DW12_ACCEL_RANGE_RUNTIME
|
||||
|
||||
config LIS2DW12_ACCEL_RANGE_RUNTIME
|
||||
bool "Set at runtime (Default 2G)"
|
||||
|
||||
config LIS2DW12_ACCEL_RANGE_2G
|
||||
bool "2G"
|
||||
|
||||
config LIS2DW12_ACCEL_RANGE_4G
|
||||
bool "4G"
|
||||
|
||||
config LIS2DW12_ACCEL_RANGE_8G
|
||||
bool "8G"
|
||||
|
||||
config LIS2DW12_ACCEL_RANGE_16G
|
||||
bool "16G"
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Accelerometer sampling frequency (ODR)"
|
||||
depends on LIS2DW12
|
||||
default LIS2DW12_ODR_RUNTIME
|
||||
|
||||
config LIS2DW12_ODR_RUNTIME
|
||||
bool "Set at runtime (Default 100 Hz)"
|
||||
|
||||
config LIS2DW12_ODR_1_6
|
||||
bool "1.6 Hz"
|
||||
|
||||
config LIS2DW12_ODR_12_5
|
||||
bool "12.5 Hz"
|
||||
|
||||
config LIS2DW12_ODR_25
|
||||
bool "25 Hz"
|
||||
|
||||
config LIS2DW12_ODR_50
|
||||
bool "50 Hz"
|
||||
|
||||
config LIS2DW12_ODR_100
|
||||
bool "100 Hz"
|
||||
|
||||
config LIS2DW12_ODR_200
|
||||
bool "200 Hz"
|
||||
|
||||
config LIS2DW12_ODR_400
|
||||
bool "400 Hz"
|
||||
|
||||
config LIS2DW12_ODR_800
|
||||
bool "800 Hz"
|
||||
|
||||
config LIS2DW12_ODR_1600
|
||||
bool "1600 Hz"
|
||||
|
||||
endchoice
|
||||
|
||||
config LIS2DW12_POWER_MODE
|
||||
int "Sensor Power Modes"
|
||||
range 0 4
|
||||
default 0
|
||||
help
|
||||
Specify the sensor power mode
|
||||
0: Low Power M1
|
||||
1: Low Power M2
|
||||
2: Low Power M3
|
||||
3: Low Power M4
|
||||
4: High Performance
|
||||
|
||||
endif # LIS2DW12
|
367
drivers/sensor/lis2dw12/lis2dw12.c
Normal file
367
drivers/sensor/lis2dw12/lis2dw12.c
Normal file
|
@ -0,0 +1,367 @@
|
|||
/* ST Microelectronics LIS2DW12 3-axis accelerometer driver
|
||||
*
|
||||
* Copyright (c) 2019 STMicroelectronics
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Datasheet:
|
||||
* https://www.st.com/resource/en/datasheet/lis2dw12.pdf
|
||||
*/
|
||||
|
||||
#include <init.h>
|
||||
#include <misc/__assert.h>
|
||||
#include <misc/byteorder.h>
|
||||
#include <logging/log.h>
|
||||
#include <sensor.h>
|
||||
|
||||
#if defined(DT_ST_LIS2DW12_BUS_SPI)
|
||||
#include <spi.h>
|
||||
#elif defined(DT_ST_LIS2DW12_BUS_I2C)
|
||||
#include <i2c.h>
|
||||
#endif
|
||||
|
||||
#include "lis2dw12.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
|
||||
LOG_MODULE_REGISTER(LIS2DW12);
|
||||
|
||||
/**
|
||||
* lis2dw12_set_range - set full scale range for acc
|
||||
* @dev: Pointer to instance of struct device (I2C or SPI)
|
||||
* @range: Full scale range (2, 4, 8 and 16 G)
|
||||
*/
|
||||
static int lis2dw12_set_range(struct device *dev, u16_t range)
|
||||
{
|
||||
int err;
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
u8_t shift_gain = 0;
|
||||
|
||||
err = lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL6_ADDR,
|
||||
LIS2DW12_FS_MASK,
|
||||
LIS2DW12_FS_TO_REG(range));
|
||||
|
||||
if (cfg->pm == LIS2DW12_LOW_POWER_M1) {
|
||||
shift_gain = LIS2DW12_SHFT_GAIN_NOLP1;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
/* save internally gain for optimization */
|
||||
lis2dw12->gain =
|
||||
LIS2DW12_FS_TO_GAIN(LIS2DW12_FS_TO_REG(range),
|
||||
shift_gain);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* lis2dw12_set_odr - set new sampling frequency
|
||||
* @dev: Pointer to instance of struct device (I2C or SPI)
|
||||
* @odr: Output data rate
|
||||
*/
|
||||
static int lis2dw12_set_odr(struct device *dev, u16_t odr)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
|
||||
/* check if power off */
|
||||
if (odr == 0) {
|
||||
return lis2dw12->hw_tf->update_reg(lis2dw12,
|
||||
LIS2DW12_CTRL1_ADDR,
|
||||
LIS2DW12_ODR_MASK,
|
||||
LIS2DW12_ODR_POWER_OFF_VAL);
|
||||
}
|
||||
|
||||
if (odr > LIS2DW12_MAX_ODR) {
|
||||
LOG_ERR("ODR too high");
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL1_ADDR,
|
||||
LIS2DW12_ODR_MASK,
|
||||
LIS2DW12_ODR_TO_REG(odr));
|
||||
}
|
||||
|
||||
static inline void lis2dw12_convert(struct sensor_value *val, int raw_val,
|
||||
float gain)
|
||||
{
|
||||
s64_t dval;
|
||||
|
||||
/* Gain is in ug/LSB */
|
||||
/* Convert to m/s^2 */
|
||||
dval = ((s64_t)raw_val * gain * SENSOR_G) / 1000000LL;
|
||||
val->val1 = dval / 1000000LL;
|
||||
val->val2 = dval % 1000000LL;
|
||||
}
|
||||
|
||||
static inline void lis2dw12_channel_get_acc(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
int i;
|
||||
u8_t ofs_start, ofs_stop;
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
struct sensor_value *pval = val;
|
||||
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
ofs_start = ofs_stop = 0;
|
||||
break;
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
ofs_start = ofs_stop = 1;
|
||||
break;
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
ofs_start = ofs_stop = 2;
|
||||
break;
|
||||
default:
|
||||
ofs_start = 0; ofs_stop = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = ofs_start; i <= ofs_stop ; i++) {
|
||||
lis2dw12_convert(pval++, lis2dw12->acc[i], lis2dw12->gain);
|
||||
}
|
||||
}
|
||||
|
||||
static int lis2dw12_channel_get(struct device *dev,
|
||||
enum sensor_channel chan,
|
||||
struct sensor_value *val)
|
||||
{
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
case SENSOR_CHAN_ACCEL_XYZ:
|
||||
lis2dw12_channel_get_acc(dev, chan, val);
|
||||
return 0;
|
||||
default:
|
||||
LOG_DBG("Channel not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int lis2dw12_config(struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
switch (attr) {
|
||||
case SENSOR_ATTR_FULL_SCALE:
|
||||
return lis2dw12_set_range(dev, sensor_ms2_to_g(val));
|
||||
case SENSOR_ATTR_SAMPLING_FREQUENCY:
|
||||
return lis2dw12_set_odr(dev, val->val1);
|
||||
default:
|
||||
LOG_DBG("Acc attribute not supported");
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int lis2dw12_attr_set(struct device *dev, enum sensor_channel chan,
|
||||
enum sensor_attribute attr,
|
||||
const struct sensor_value *val)
|
||||
{
|
||||
switch (chan) {
|
||||
case SENSOR_CHAN_ACCEL_X:
|
||||
case SENSOR_CHAN_ACCEL_Y:
|
||||
case SENSOR_CHAN_ACCEL_Z:
|
||||
case SENSOR_CHAN_ACCEL_XYZ:
|
||||
return lis2dw12_config(dev, chan, attr, val);
|
||||
default:
|
||||
LOG_DBG("Attr not supported on %d channel", chan);
|
||||
break;
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int lis2dw12_sample_fetch(struct device *dev, enum sensor_channel chan)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
u8_t shift;
|
||||
union {
|
||||
u8_t raw[6];
|
||||
struct {
|
||||
s16_t a_axis[3];
|
||||
};
|
||||
} buf __aligned(2);
|
||||
u8_t tmp;
|
||||
|
||||
if (lis2dw12->hw_tf->read_reg(lis2dw12, LIS2DW12_STATUS_REG, &tmp)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!(tmp & LIS2DW12_STS_XLDA_UP)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* fetch raw data sample */
|
||||
if (lis2dw12->hw_tf->read_data(lis2dw12, LIS2DW12_OUT_X_L_ADDR,
|
||||
buf.raw, sizeof(buf)) < 0) {
|
||||
LOG_DBG("Failed to fetch raw data sample");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* adjust to resolution */
|
||||
if (cfg->pm == LIS2DW12_LOW_POWER_M1) {
|
||||
shift = LIS2DW12_SHIFT_PM1;
|
||||
} else {
|
||||
shift = LIS2DW12_SHIFT_PMOTHER;
|
||||
}
|
||||
|
||||
lis2dw12->acc[0] = sys_le16_to_cpu(buf.a_axis[0]) >> shift;
|
||||
lis2dw12->acc[1] = sys_le16_to_cpu(buf.a_axis[1]) >> shift;
|
||||
lis2dw12->acc[2] = sys_le16_to_cpu(buf.a_axis[2]) >> shift;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sensor_driver_api lis2dw12_driver_api = {
|
||||
.attr_set = lis2dw12_attr_set,
|
||||
#if CONFIG_LIS2DW12_TRIGGER
|
||||
.trigger_set = lis2dw12_trigger_set,
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
.sample_fetch = lis2dw12_sample_fetch,
|
||||
.channel_get = lis2dw12_channel_get,
|
||||
};
|
||||
|
||||
static int lis2dw12_init_interface(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
|
||||
lis2dw12->bus = device_get_binding(cfg->bus_name);
|
||||
if (!lis2dw12->bus) {
|
||||
LOG_DBG("master bus not found: %s", cfg->bus_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(DT_ST_LIS2DW12_BUS_SPI)
|
||||
lis2dw12_spi_init(dev);
|
||||
#elif defined(DT_ST_LIS2DW12_BUS_I2C)
|
||||
lis2dw12_i2c_init(dev);
|
||||
#else
|
||||
#error "BUS MACRO NOT DEFINED IN DTS"
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2dw12_set_power_mode(struct lis2dw12_data *lis2dw12,
|
||||
enum lis2dh_powermode pm)
|
||||
{
|
||||
u8_t regval = LIS2DW12_LOW_POWER_M1 | LIS2DW12_LOW_POWER_MODE;
|
||||
|
||||
switch (pm) {
|
||||
case LIS2DW12_LOW_POWER_M2:
|
||||
regval = LIS2DW12_LOW_POWER_M2 | LIS2DW12_LOW_POWER_MODE;
|
||||
break;
|
||||
case LIS2DW12_LOW_POWER_M3:
|
||||
regval = LIS2DW12_LOW_POWER_M3 | LIS2DW12_LOW_POWER_MODE;
|
||||
break;
|
||||
case LIS2DW12_LOW_POWER_M4:
|
||||
regval = LIS2DW12_LOW_POWER_M4 | LIS2DW12_LOW_POWER_MODE;
|
||||
break;
|
||||
case LIS2DW12_HIGH_PERF:
|
||||
regval = LIS2DW12_HP_MODE;
|
||||
break;
|
||||
default:
|
||||
LOG_DBG("Apply default Power Mode");
|
||||
break;
|
||||
}
|
||||
|
||||
return lis2dw12->hw_tf->write_reg(lis2dw12, LIS2DW12_CTRL1_ADDR,
|
||||
regval);
|
||||
}
|
||||
|
||||
static int lis2dw12_init(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
u8_t wai;
|
||||
|
||||
if (lis2dw12_init_interface(dev)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check chip ID */
|
||||
if (lis2dw12->hw_tf->read_reg(lis2dw12, LIS2DW12_WHO_AM_I_REG,
|
||||
&wai) < 0) {
|
||||
LOG_ERR("Failed to read chip ID");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (wai != LIS2DW12_WHO_AM_I) {
|
||||
LOG_ERR("Invalid chip ID");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* reset device */
|
||||
if (lis2dw12->hw_tf->write_reg(lis2dw12, LIS2DW12_CTRL2_ADDR,
|
||||
LIS2DW12_RESET_MASK)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
k_busy_wait(100);
|
||||
|
||||
if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL2_ADDR,
|
||||
LIS2DW12_BDU_MASK, LIS2DW12_EN_BIT)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* set power mode */
|
||||
if (lis2dw12_set_power_mode(lis2dw12, CONFIG_LIS2DW12_POWER_MODE)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* set default odr and full scale for acc */
|
||||
if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL1_ADDR,
|
||||
LIS2DW12_ODR_MASK,
|
||||
LIS2DW12_DEFAULT_ODR)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL6_ADDR,
|
||||
LIS2DW12_FS_MASK,
|
||||
LIS2DW12_ACC_FS)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
lis2dw12->gain =
|
||||
LIS2DW12_FS_TO_GAIN(LIS2DW12_ACC_FS,
|
||||
cfg->pm == LIS2DW12_LOW_POWER_M1 ?
|
||||
LIS2DW12_SHFT_GAIN_NOLP1 : 0);
|
||||
|
||||
#ifdef CONFIG_LIS2DW12_TRIGGER
|
||||
if (lis2dw12_init_interrupt(dev) < 0) {
|
||||
LOG_ERR("Failed to initialize interrupts");
|
||||
return -EIO;
|
||||
}
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct lis2dw12_device_config lis2dw12_cfg = {
|
||||
.bus_name = DT_ST_LIS2DW12_0_BUS_NAME,
|
||||
.pm = CONFIG_LIS2DW12_POWER_MODE,
|
||||
#ifdef CONFIG_LIS2DW12_TRIGGER
|
||||
.int_gpio_port = DT_ST_LIS2DW12_0_IRQ_GPIOS_CONTROLLER,
|
||||
.int_gpio_pin = DT_ST_LIS2DW12_0_IRQ_GPIOS_PIN,
|
||||
#if defined(CONFIG_LIS2DW12_INT_PIN_1)
|
||||
.int_pin = 1,
|
||||
#elif defined(CONFIG_LIS2DW12_INT_PIN_2)
|
||||
.int_pin = 2,
|
||||
#endif /* CONFIG_LIS2DW12_INT_PIN */
|
||||
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
};
|
||||
|
||||
struct lis2dw12_data lis2dw12_data;
|
||||
|
||||
DEVICE_AND_API_INIT(lis2dw12, DT_ST_LIS2DW12_0_LABEL, lis2dw12_init,
|
||||
&lis2dw12_data, &lis2dw12_cfg, POST_KERNEL,
|
||||
CONFIG_SENSOR_INIT_PRIORITY, &lis2dw12_driver_api);
|
221
drivers/sensor/lis2dw12/lis2dw12.h
Normal file
221
drivers/sensor/lis2dw12/lis2dw12.h
Normal file
|
@ -0,0 +1,221 @@
|
|||
/* ST Microelectronics LIS2DW12 3-axis accelerometer driver
|
||||
*
|
||||
* Copyright (c) 2019 STMicroelectronics
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Datasheet:
|
||||
* https://www.st.com/resource/en/datasheet/lis2dw12.pdf
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DW12_LIS2DW12_H_
|
||||
#define ZEPHYR_DRIVERS_SENSOR_LIS2DW12_LIS2DW12_H_
|
||||
|
||||
#include <spi.h>
|
||||
#include <gpio.h>
|
||||
#include <misc/util.h>
|
||||
#include <sensor.h>
|
||||
|
||||
/* COMMON DEFINE FOR ACCEL SENSOR */
|
||||
#define LIS2DW12_EN_BIT 0x01
|
||||
#define LIS2DW12_DIS_BIT 0x00
|
||||
#define LIS2DW12_OUT_LEN 6
|
||||
|
||||
/* temperature sensor */
|
||||
#define LIS2DW12_OUT_TEMP_L_ADDR 0x0d
|
||||
|
||||
/* Who Am I */
|
||||
#define LIS2DW12_WHO_AM_I_REG 0x0f
|
||||
#define LIS2DW12_WHO_AM_I 0x44
|
||||
|
||||
#define LIS2DW12_CTRL1_ADDR 0x20
|
||||
#define LIS2DW12_LOW_POWER_MASK 0x03
|
||||
#define LIS2DW12_POWER_MODE_MASK 0x0c
|
||||
#define LIS2DW12_LOW_POWER_MODE 0x00
|
||||
#define LIS2DW12_HP_MODE 0x04
|
||||
#define LIS2DW12_ODR_MASK 0xf0
|
||||
|
||||
enum lis2dh_powermode {
|
||||
LIS2DW12_LOW_POWER_M1,
|
||||
LIS2DW12_LOW_POWER_M2,
|
||||
LIS2DW12_LOW_POWER_M3,
|
||||
LIS2DW12_LOW_POWER_M4,
|
||||
LIS2DW12_HIGH_PERF
|
||||
};
|
||||
|
||||
/* Acc data rate for Low Power mode */
|
||||
#define LIS2DW12_MAX_ODR 1600
|
||||
|
||||
enum lis2dh_odr {
|
||||
LIS2DW12_ODR_POWER_OFF_VAL,
|
||||
LIS2DW12_ODR_1_6HZ_VAL,
|
||||
LIS2DW12_ODR_12_5HZ_VAL,
|
||||
LIS2DW12_ODR_25HZ_VAL,
|
||||
LIS2DW12_ODR_50HZ_VAL,
|
||||
LIS2DW12_ODR_100HZ_VAL,
|
||||
LIS2DW12_ODR_200HZ_VAL,
|
||||
LIS2DW12_ODR_400HZ_VAL,
|
||||
LIS2DW12_ODR_800HZ_VAL,
|
||||
LIS2DW12_ODR_1600HZ_VAL
|
||||
};
|
||||
|
||||
#if defined(CONFIG_LIS2DW12_ODR_1_6)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_1_6HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_12_5)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_12_5HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_25)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_25HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_50)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_50HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_100) || \
|
||||
defined(CONFIG_LIS2DW12_ODR_RUNTIME)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_100HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_200)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_200HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_400)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_400HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_800)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_800HZ_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ODR_1600)
|
||||
#define LIS2DW12_DEFAULT_ODR LIS2DW12_ODR_1600HZ_VAL
|
||||
#endif
|
||||
|
||||
/* Return ODR reg value based on data rate set */
|
||||
#define LIS2DW12_ODR_TO_REG(_odr) \
|
||||
((_odr <= 1) ? LIS2DW12_ODR_1_6HZ_VAL : \
|
||||
(_odr <= 12) ? LIS2DW12_ODR_12_5HZ_VAL : \
|
||||
((31 - __builtin_clz(_odr / 25))) + 3)
|
||||
|
||||
#define LIS2DW12_CTRL2_ADDR 0x21
|
||||
#define LIS2DW12_BDU_MASK BIT(3)
|
||||
#define LIS2DW12_RESET_MASK BIT(6)
|
||||
#define LIS2DW12_BOOT_MASK BIT(7)
|
||||
#define LIS2DW12_CTRL3_ADDR 0x22
|
||||
#define LIS2DW12_LIR_MASK BIT(4)
|
||||
|
||||
#define LIS2DW12_CTRL4_ADDR 0x23
|
||||
#define LIS2DW12_INT1_DRDY BIT(0)
|
||||
|
||||
#define LIS2DW12_CTRL5_ADDR 0x24
|
||||
#define LIS2DW12_INT2_DRDY BIT(0)
|
||||
|
||||
#define LIS2DW12_CTRL6_ADDR 0x25
|
||||
#define LIS2DW12_FS_MASK 0x30
|
||||
|
||||
enum lis2dh_fs {
|
||||
LIS2DW12_FS_2G_VAL,
|
||||
LIS2DW12_FS_4G_VAL,
|
||||
LIS2DW12_FS_8G_VAL,
|
||||
LIS2DW12_FS_16G_VAL
|
||||
};
|
||||
|
||||
/* FS reg value from Full Scale */
|
||||
#define LIS2DW12_FS_TO_REG(_fs) (30 - __builtin_clz(_fs))
|
||||
|
||||
#if defined(CONFIG_LIS2DW12_ACCEL_RANGE_RUNTIME) || \
|
||||
defined(CONFIG_LIS2DW12_ACCEL_RANGE_2G)
|
||||
#define LIS2DW12_ACC_FS LIS2DW12_FS_2G_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ACCEL_RANGE_4G)
|
||||
#define LIS2DW12_ACC_FS LIS2DW12_FS_4G_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ACCEL_RANGE_8G)
|
||||
#define LIS2DW12_ACC_FS LIS2DW12_FS_8G_VAL
|
||||
#elif defined(CONFIG_LIS2DW12_ACCEL_RANGE_16G)
|
||||
#define LIS2DW12_ACC_FS LIS2DW12_FS_16G_VAL
|
||||
#endif
|
||||
|
||||
#define LIS2DW12_OUT_T_REG 0x26
|
||||
|
||||
#define LIS2DW12_STATUS_REG 0x27
|
||||
#define LIS2DW12_STS_XLDA_UP 0x01
|
||||
|
||||
#define LIS2DW12_OUT_X_L_ADDR 0x28
|
||||
|
||||
/* Acc Gain value in ug/LSB in High Perf mode */
|
||||
#define LIS2DW12_FS_2G_GAIN 244
|
||||
#define LIS2DW12_FS_4G_GAIN 488
|
||||
#define LIS2DW12_FS_8G_GAIN 976
|
||||
#define LIS2DW12_FS_16G_GAIN 1952
|
||||
|
||||
#define LIS2DW12_SHFT_GAIN_NOLP1 2
|
||||
#define LIS2DW12_ACCEL_GAIN_DEFAULT_VAL LIS2DW12_FS_2G_GAIN
|
||||
#define LIS2DW12_FS_TO_GAIN(_fs, _lp1) \
|
||||
(LIS2DW12_FS_2G_GAIN << ((_fs) + (_lp1)))
|
||||
|
||||
/* shift value for power mode */
|
||||
#define LIS2DW12_SHIFT_PM1 4
|
||||
#define LIS2DW12_SHIFT_PMOTHER 2
|
||||
|
||||
/**
|
||||
* struct lis2dw12_device_config - lis2dw12 hw configuration
|
||||
* @bus_name: Pointer to bus master identifier.
|
||||
* @pm: Power mode (lis2dh_powermode).
|
||||
* @int_gpio_port: Pointer to GPIO PORT identifier.
|
||||
* @int_gpio_pin: GPIO pin number connecter to sensor int pin.
|
||||
* @int_pin: Sensor int pin (int1/int2).
|
||||
*/
|
||||
struct lis2dw12_device_config {
|
||||
const char *bus_name;
|
||||
enum lis2dh_powermode pm;
|
||||
#ifdef CONFIG_LIS2DW12_TRIGGER
|
||||
const char *int_gpio_port;
|
||||
u8_t int_gpio_pin;
|
||||
u8_t int_pin;
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
};
|
||||
|
||||
/* sensor data forward declaration (member definition is below) */
|
||||
struct lis2dw12_data;
|
||||
|
||||
/* transmission function interface */
|
||||
struct lis2dw12_tf {
|
||||
int (*read_data)(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len);
|
||||
int (*write_data)(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len);
|
||||
int (*read_reg)(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value);
|
||||
int (*write_reg)(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t value);
|
||||
int (*update_reg)(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t mask, u8_t value);
|
||||
};
|
||||
|
||||
/* sensor data */
|
||||
struct lis2dw12_data {
|
||||
struct device *bus;
|
||||
s16_t acc[3];
|
||||
|
||||
/* save sensitivity */
|
||||
u16_t gain;
|
||||
|
||||
const struct lis2dw12_tf *hw_tf;
|
||||
#ifdef CONFIG_LIS2DW12_TRIGGER
|
||||
struct device *gpio;
|
||||
struct gpio_callback gpio_cb;
|
||||
sensor_trigger_handler_t handler_drdy;
|
||||
|
||||
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
|
||||
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_LIS2DW12_THREAD_STACK_SIZE);
|
||||
struct k_thread thread;
|
||||
struct k_sem gpio_sem;
|
||||
#elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD)
|
||||
struct k_work work;
|
||||
struct device *dev;
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD */
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
#if defined(DT_ST_LIS2DW12_0_CS_GPIO_CONTROLLER)
|
||||
struct spi_cs_control cs_ctrl;
|
||||
#endif
|
||||
};
|
||||
|
||||
int lis2dw12_i2c_init(struct device *dev);
|
||||
int lis2dw12_spi_init(struct device *dev);
|
||||
|
||||
#ifdef CONFIG_LIS2DW12_TRIGGER
|
||||
int lis2dw12_init_interrupt(struct device *dev);
|
||||
int lis2dw12_trigger_set(struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler);
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER */
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DW12_LIS2DW12_H_ */
|
76
drivers/sensor/lis2dw12/lis2dw12_i2c.c
Normal file
76
drivers/sensor/lis2dw12/lis2dw12_i2c.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* ST Microelectronics LIS2DW12 3-axis accelerometer driver
|
||||
*
|
||||
* Copyright (c) 2019 STMicroelectronics
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Datasheet:
|
||||
* https://www.st.com/resource/en/datasheet/lis2dw12.pdf
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <i2c.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#include "lis2dw12.h"
|
||||
|
||||
#ifdef DT_ST_LIS2DW12_BUS_I2C
|
||||
|
||||
static u16_t lis2dw12_i2c_slave_addr = DT_ST_LIS2DW12_0_BASE_ADDRESS;
|
||||
|
||||
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
|
||||
LOG_MODULE_DECLARE(LIS2DW12);
|
||||
|
||||
static int lis2dw12_i2c_read_data(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len)
|
||||
{
|
||||
return i2c_burst_read(data->bus, lis2dw12_i2c_slave_addr,
|
||||
reg_addr, value, len);
|
||||
}
|
||||
|
||||
static int lis2dw12_i2c_write_data(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len)
|
||||
{
|
||||
return i2c_burst_write(data->bus, lis2dw12_i2c_slave_addr,
|
||||
reg_addr, value, len);
|
||||
}
|
||||
|
||||
static int lis2dw12_i2c_read_reg(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value)
|
||||
{
|
||||
return i2c_reg_read_byte(data->bus, lis2dw12_i2c_slave_addr,
|
||||
reg_addr, value);
|
||||
}
|
||||
|
||||
static int lis2dw12_i2c_write_reg(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t value)
|
||||
{
|
||||
return i2c_reg_write_byte(data->bus, lis2dw12_i2c_slave_addr,
|
||||
reg_addr, value);
|
||||
}
|
||||
|
||||
static int lis2dw12_i2c_update_reg(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t mask, u8_t value)
|
||||
{
|
||||
return i2c_reg_update_byte(data->bus, lis2dw12_i2c_slave_addr,
|
||||
reg_addr, mask,
|
||||
value << __builtin_ctz(mask));
|
||||
}
|
||||
|
||||
static const struct lis2dw12_tf lis2dw12_i2c_transfer_fn = {
|
||||
.read_data = lis2dw12_i2c_read_data,
|
||||
.write_data = lis2dw12_i2c_write_data,
|
||||
.read_reg = lis2dw12_i2c_read_reg,
|
||||
.write_reg = lis2dw12_i2c_write_reg,
|
||||
.update_reg = lis2dw12_i2c_update_reg,
|
||||
};
|
||||
|
||||
int lis2dw12_i2c_init(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *data = dev->driver_data;
|
||||
|
||||
data->hw_tf = &lis2dw12_i2c_transfer_fn;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DT_ST_LIS2DW12_BUS_I2C */
|
175
drivers/sensor/lis2dw12/lis2dw12_spi.c
Normal file
175
drivers/sensor/lis2dw12/lis2dw12_spi.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
/* ST Microelectronics LIS2DW12 3-axis accelerometer driver
|
||||
*
|
||||
* Copyright (c) 2019 STMicroelectronics
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Datasheet:
|
||||
* https://www.st.com/resource/en/datasheet/lis2dw12.pdf
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "lis2dw12.h"
|
||||
#include <logging/log.h>
|
||||
|
||||
#ifdef DT_ST_LIS2DW12_BUS_SPI
|
||||
|
||||
#define LIS2DW12_SPI_READ (1 << 7)
|
||||
|
||||
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
|
||||
LOG_MODULE_DECLARE(LIS2DW12);
|
||||
|
||||
static struct spi_config lis2dw12_spi_conf = {
|
||||
.frequency = DT_ST_LIS2DW12_0_SPI_MAX_FREQUENCY,
|
||||
.operation = (SPI_OP_MODE_MASTER | SPI_MODE_CPOL |
|
||||
SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_LINES_SINGLE),
|
||||
.slave = DT_ST_LIS2DW12_0_BASE_ADDRESS,
|
||||
.cs = NULL,
|
||||
};
|
||||
|
||||
static int lis2dw12_raw_read(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len)
|
||||
{
|
||||
struct spi_config *spi_cfg = &lis2dw12_spi_conf;
|
||||
u8_t buffer_tx[2] = { reg_addr | LIS2DW12_SPI_READ, 0 };
|
||||
const struct spi_buf tx_buf = {
|
||||
.buf = buffer_tx,
|
||||
.len = 2,
|
||||
};
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = &tx_buf,
|
||||
.count = 1
|
||||
};
|
||||
const struct spi_buf rx_buf[2] = {
|
||||
{
|
||||
.buf = NULL,
|
||||
.len = 1,
|
||||
},
|
||||
{
|
||||
.buf = value,
|
||||
.len = len,
|
||||
}
|
||||
};
|
||||
const struct spi_buf_set rx = {
|
||||
.buffers = rx_buf,
|
||||
.count = 2
|
||||
};
|
||||
|
||||
|
||||
if (len > 64) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (spi_transceive(data->bus, spi_cfg, &tx, &rx)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2dw12_raw_write(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len)
|
||||
{
|
||||
struct spi_config *spi_cfg = &lis2dw12_spi_conf;
|
||||
u8_t buffer_tx[1] = { reg_addr & ~LIS2DW12_SPI_READ };
|
||||
const struct spi_buf tx_buf[2] = {
|
||||
{
|
||||
.buf = buffer_tx,
|
||||
.len = 1,
|
||||
},
|
||||
{
|
||||
.buf = value,
|
||||
.len = len,
|
||||
}
|
||||
};
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = tx_buf,
|
||||
.count = 2
|
||||
};
|
||||
|
||||
|
||||
if (len > 64) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (spi_write(data->bus, spi_cfg, &tx)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis2dw12_spi_read_data(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len)
|
||||
{
|
||||
return lis2dw12_raw_read(data, reg_addr, value, len);
|
||||
}
|
||||
|
||||
static int lis2dw12_spi_write_data(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value, u8_t len)
|
||||
{
|
||||
return lis2dw12_raw_write(data, reg_addr, value, len);
|
||||
}
|
||||
|
||||
static int lis2dw12_spi_read_reg(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t *value)
|
||||
{
|
||||
return lis2dw12_raw_read(data, reg_addr, value, 1);
|
||||
}
|
||||
|
||||
static int lis2dw12_spi_write_reg(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t value)
|
||||
{
|
||||
u8_t tmp_val = value;
|
||||
|
||||
return lis2dw12_raw_write(data, reg_addr, &tmp_val, 1);
|
||||
}
|
||||
|
||||
static int lis2dw12_spi_update_reg(struct lis2dw12_data *data, u8_t reg_addr,
|
||||
u8_t mask, u8_t value)
|
||||
{
|
||||
u8_t tmp_val;
|
||||
|
||||
lis2dw12_raw_read(data, reg_addr, &tmp_val, 1);
|
||||
tmp_val = (tmp_val & ~mask) | ((value << __builtin_ctz(mask)) & mask);
|
||||
|
||||
return lis2dw12_raw_write(data, reg_addr, &tmp_val, 1);
|
||||
}
|
||||
|
||||
static const struct lis2dw12_tf lis2dw12_spi_transfer_fn = {
|
||||
.read_data = lis2dw12_spi_read_data,
|
||||
.write_data = lis2dw12_spi_write_data,
|
||||
.read_reg = lis2dw12_spi_read_reg,
|
||||
.write_reg = lis2dw12_spi_write_reg,
|
||||
.update_reg = lis2dw12_spi_update_reg,
|
||||
};
|
||||
|
||||
int lis2dw12_spi_init(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *data = dev->driver_data;
|
||||
|
||||
data->hw_tf = &lis2dw12_spi_transfer_fn;
|
||||
|
||||
#if defined(DT_ST_LIS2DW12_0_CS_GPIO_CONTROLLER)
|
||||
/* handle SPI CS thru GPIO if it is the case */
|
||||
data->cs_ctrl.gpio_dev = device_get_binding(
|
||||
DT_ST_LIS2DW12_0_CS_GPIO_CONTROLLER);
|
||||
if (!data->cs_ctrl.gpio_dev) {
|
||||
LOG_ERR("Unable to get GPIO SPI CS device");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data->cs_ctrl.gpio_pin = DT_ST_LIS2DW12_0_CS_GPIO_PIN;
|
||||
data->cs_ctrl.delay = 0;
|
||||
|
||||
lis2dw12_spi_conf.cs = &data->cs_ctrl;
|
||||
|
||||
LOG_DBG("SPI GPIO CS configured on %s:%u",
|
||||
DT_ST_LIS2DW12_0_CS_GPIO_CONTROLLER,
|
||||
DT_ST_LIS2DW12_0_CS_GPIO_PIN);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DT_ST_LIS2DW12_BUS_SPI */
|
182
drivers/sensor/lis2dw12/lis2dw12_trigger.c
Normal file
182
drivers/sensor/lis2dw12/lis2dw12_trigger.c
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* ST Microelectronics LIS2DW12 3-axis accelerometer driver
|
||||
*
|
||||
* Copyright (c) 2019 STMicroelectronics
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Datasheet:
|
||||
* https://www.st.com/resource/en/datasheet/lis2dw12.pdf
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <sensor.h>
|
||||
#include <gpio.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#include "lis2dw12.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
|
||||
LOG_MODULE_DECLARE(LIS2DW12);
|
||||
|
||||
/**
|
||||
* lis2dw12_enable_int - enable selected int pin to generate interrupt
|
||||
*/
|
||||
static int lis2dw12_enable_int(struct device *dev, int enable)
|
||||
{
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
|
||||
/* set interrupt */
|
||||
if (cfg->int_pin == 1)
|
||||
return lis2dw12->hw_tf->update_reg(lis2dw12,
|
||||
LIS2DW12_CTRL4_ADDR,
|
||||
LIS2DW12_INT1_DRDY,
|
||||
enable);
|
||||
|
||||
return lis2dw12->hw_tf->update_reg(lis2dw12,
|
||||
LIS2DW12_CTRL5_ADDR,
|
||||
LIS2DW12_INT2_DRDY,
|
||||
enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* lis2dw12_trigger_set - link external trigger to event data ready
|
||||
*/
|
||||
int lis2dw12_trigger_set(struct device *dev,
|
||||
const struct sensor_trigger *trig,
|
||||
sensor_trigger_handler_t handler)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
u8_t raw[6];
|
||||
|
||||
if (trig->chan == SENSOR_CHAN_ACCEL_XYZ) {
|
||||
lis2dw12->handler_drdy = handler;
|
||||
if (handler) {
|
||||
/* dummy read: re-trigger interrupt */
|
||||
lis2dw12->hw_tf->read_data(lis2dw12,
|
||||
LIS2DW12_OUT_X_L_ADDR, raw,
|
||||
sizeof(raw));
|
||||
return lis2dw12_enable_int(dev, LIS2DW12_EN_BIT);
|
||||
} else {
|
||||
return lis2dw12_enable_int(dev, LIS2DW12_DIS_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* lis2dw12_handle_interrupt - handle the drdy event
|
||||
* read data and call handler if registered any
|
||||
*/
|
||||
static void lis2dw12_handle_interrupt(void *arg)
|
||||
{
|
||||
struct device *dev = arg;
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
struct sensor_trigger drdy_trigger = {
|
||||
.type = SENSOR_TRIG_DATA_READY,
|
||||
};
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
|
||||
if (lis2dw12->handler_drdy != NULL) {
|
||||
lis2dw12->handler_drdy(dev, &drdy_trigger);
|
||||
}
|
||||
|
||||
gpio_pin_enable_callback(lis2dw12->gpio, cfg->int_gpio_pin);
|
||||
}
|
||||
|
||||
static void lis2dw12_gpio_callback(struct device *dev,
|
||||
struct gpio_callback *cb, u32_t pins)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 =
|
||||
CONTAINER_OF(cb, struct lis2dw12_data, gpio_cb);
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
|
||||
ARG_UNUSED(pins);
|
||||
|
||||
gpio_pin_disable_callback(dev, cfg->int_gpio_pin);
|
||||
|
||||
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
|
||||
k_sem_give(&lis2dw12->gpio_sem);
|
||||
#elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD)
|
||||
k_work_submit(&lis2dw12->work);
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIS2DW12_TRIGGER_OWN_THREAD
|
||||
static void lis2dw12_thread(int dev_ptr, int unused)
|
||||
{
|
||||
struct device *dev = INT_TO_POINTER(dev_ptr);
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
while (1) {
|
||||
k_sem_take(&lis2dw12->gpio_sem, K_FOREVER);
|
||||
lis2dw12_handle_interrupt(dev);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
|
||||
|
||||
#ifdef CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD
|
||||
static void lis2dw12_work_cb(struct k_work *work)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 =
|
||||
CONTAINER_OF(work, struct lis2dw12_data, work);
|
||||
|
||||
lis2dw12_handle_interrupt(lis2dw12->dev);
|
||||
}
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD */
|
||||
|
||||
int lis2dw12_init_interrupt(struct device *dev)
|
||||
{
|
||||
struct lis2dw12_data *lis2dw12 = dev->driver_data;
|
||||
const struct lis2dw12_device_config *cfg = dev->config->config_info;
|
||||
int ret;
|
||||
|
||||
/* setup data ready gpio interrupt (INT1 or INT2) */
|
||||
lis2dw12->gpio = device_get_binding(cfg->int_gpio_port);
|
||||
if (lis2dw12->gpio == NULL) {
|
||||
LOG_DBG("Cannot get pointer to %s device",
|
||||
cfg->int_gpio_port);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_LIS2DW12_TRIGGER_OWN_THREAD)
|
||||
k_sem_init(&lis2dw12->gpio_sem, 0, UINT_MAX);
|
||||
|
||||
k_thread_create(&lis2dw12->thread, lis2dw12->thread_stack,
|
||||
CONFIG_LIS2DW12_THREAD_STACK_SIZE,
|
||||
(k_thread_entry_t)lis2dw12_thread, dev,
|
||||
0, NULL, K_PRIO_COOP(CONFIG_LIS2DW12_THREAD_PRIORITY),
|
||||
0, 0);
|
||||
#elif defined(CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD)
|
||||
lis2dw12->work.handler = lis2dw12_work_cb;
|
||||
lis2dw12->dev = dev;
|
||||
#endif /* CONFIG_LIS2DW12_TRIGGER_OWN_THREAD */
|
||||
|
||||
ret = gpio_pin_configure(lis2dw12->gpio, cfg->int_gpio_pin,
|
||||
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
|
||||
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
|
||||
if (ret < 0) {
|
||||
LOG_DBG("Could not configure gpio");
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_init_callback(&lis2dw12->gpio_cb,
|
||||
lis2dw12_gpio_callback,
|
||||
BIT(cfg->int_gpio_pin));
|
||||
|
||||
if (gpio_add_callback(lis2dw12->gpio, &lis2dw12->gpio_cb) < 0) {
|
||||
LOG_DBG("Could not set gpio callback");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* enable interrupt on int1/int2 in pulse mode */
|
||||
if (lis2dw12->hw_tf->update_reg(lis2dw12, LIS2DW12_CTRL3_ADDR,
|
||||
LIS2DW12_LIR_MASK, LIS2DW12_DIS_BIT)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return gpio_pin_enable_callback(lis2dw12->gpio, cfg->int_gpio_pin);
|
||||
}
|
24
dts/bindings/sensor/st,lis2dw12-i2c.yaml
Normal file
24
dts/bindings/sensor/st,lis2dw12-i2c.yaml
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# Copyright (c) 2019 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
---
|
||||
title: STMicroelectronics MEMS sensors LIS2DW12
|
||||
version: 0.1
|
||||
|
||||
description: >
|
||||
This binding gives a base representation of LIS2DW12 3-axis accelerometer
|
||||
|
||||
inherits:
|
||||
!include i2c-device.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
constraint: "st,lis2dw12"
|
||||
|
||||
irq-gpios:
|
||||
type: compound
|
||||
category: required
|
||||
generation: define, use-prop-name
|
||||
...
|
25
dts/bindings/sensor/st,lis2dw12-spi.yaml
Normal file
25
dts/bindings/sensor/st,lis2dw12-spi.yaml
Normal file
|
@ -0,0 +1,25 @@
|
|||
#
|
||||
# Copyright (c) 2019 STMicroelectronics
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
---
|
||||
title: STMicroelectronics MEMS sensors LIS2DW12 SPI
|
||||
version: 0.1
|
||||
|
||||
description: >
|
||||
This binding gives a base representation of LIS2DW12 3-axis accelerometer
|
||||
accessed through SPI bus
|
||||
|
||||
inherits:
|
||||
!include spi-device.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
constraint: "st,lis2dw12"
|
||||
|
||||
irq-gpios:
|
||||
type: compound
|
||||
category: required
|
||||
generation: define, use-prop-name
|
||||
...
|
|
@ -158,6 +158,15 @@
|
|||
#define DT_ST_LIS2MDL_MAGN_0_IRQ_GPIOS_PIN 0
|
||||
#endif
|
||||
|
||||
#ifndef DT_ST_LIS2DW12_0_LABEL
|
||||
#define DT_ST_LIS2DW12_0_LABEL ""
|
||||
#define DT_ST_LIS2DW12_0_BUS_NAME ""
|
||||
#define DT_ST_LIS2DW12_0_BASE_ADDRESS 0x19
|
||||
#define DT_ST_LIS2DW12_0_IRQ_GPIOS_CONTROLLER ""
|
||||
#define DT_ST_LIS2DW12_0_IRQ_GPIOS_PIN 0
|
||||
#define DT_ST_LIS2DW12_BUS_I2C 1
|
||||
#endif
|
||||
|
||||
#ifndef DT_LSM9DS0_MFD_DEV_NAME
|
||||
#define DT_LSM9DS0_MFD_DEV_NAME ""
|
||||
#define DT_LSM9DS0_MFD_I2C_ADDRESS 0x1d
|
||||
|
@ -222,6 +231,16 @@
|
|||
#define DT_ST_LIS2DS12_BUS_SPI 1
|
||||
#endif
|
||||
|
||||
#ifndef DT_ST_LIS2DW12_0_LABEL
|
||||
#define DT_ST_LIS2DW12_0_LABEL ""
|
||||
#define DT_ST_LIS2DW12_0_BUS_NAME ""
|
||||
#define DT_ST_LIS2DW12_0_SPI_MAX_FREQUENCY 100000
|
||||
#define DT_ST_LIS2DW12_0_BASE_ADDRESS 1
|
||||
#define DT_ST_LIS2DW12_0_IRQ_GPIOS_CONTROLLER ""
|
||||
#define DT_ST_LIS2DW12_0_IRQ_GPIOS_PIN 0
|
||||
#define DT_ST_LIS2DW12_BUS_SPI 1
|
||||
#endif
|
||||
|
||||
#ifndef DT_MICROCHIP_ENC28J60_0_LABEL
|
||||
#define DT_MICROCHIP_ENC28J60_0_BASE_ADDRESS 0
|
||||
#define DT_MICROCHIP_ENC28J60_0_BUS_NAME ""
|
||||
|
|
|
@ -8,6 +8,7 @@ CONFIG_SENSOR_LOG_LEVEL_DBG=y
|
|||
CONFIG_ISL29035=y
|
||||
CONFIG_LIS2DH=y
|
||||
CONFIG_LIS2DS12=y
|
||||
CONFIG_LIS2DW12=y
|
||||
CONFIG_LIS2MDL=y
|
||||
CONFIG_LIS3MDL=y
|
||||
CONFIG_LPS22HB=y
|
||||
|
|
|
@ -10,6 +10,8 @@ CONFIG_LIS2DH=y
|
|||
CONFIG_LIS2DH_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LIS2DS12=y
|
||||
CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LIS2DW12=y
|
||||
CONFIG_LIS2DW12_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LIS2MDL=y
|
||||
CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y
|
||||
CONFIG_LSM6DSL=y
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue