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:
Armando Visconti 2018-05-17 15:32:05 +02:00 committed by Maureen Helm
commit 208f565bce
14 changed files with 1248 additions and 0 deletions

View file

@ -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)

View file

@ -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"

View 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)

View 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

View 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);

View 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_ */

View 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 */

View 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 */

View 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);
}

View 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
...

View 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
...

View file

@ -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 ""

View file

@ -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

View file

@ -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