driver/sensor: add LIS2DS12 sensor support

Add support to STM LIS2DS12 3-axis accelerometer driver.
The driver support I2C and SPI bus communication and both
polling and drdy trigger mode.
Currently it uses high resolution only as power mode.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2019-01-15 14:59:12 +01:00 committed by Maureen Helm
commit fdce786c07
14 changed files with 1078 additions and 0 deletions

View file

@ -21,6 +21,7 @@ add_subdirectory_ifdef(CONFIG_HP206C hp206c)
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_LIS2MDL lis2mdl)
add_subdirectory_ifdef(CONFIG_LIS3DH lis3dh)
add_subdirectory_ifdef(CONFIG_LIS3MDL lis3mdl)

View file

@ -71,6 +71,8 @@ source "drivers/sensor/isl29035/Kconfig"
source "drivers/sensor/lis2dh/Kconfig"
source "drivers/sensor/lis2ds12/Kconfig"
source "drivers/sensor/lis2mdl/Kconfig"
source "drivers/sensor/lis3dh/Kconfig"

View file

@ -0,0 +1,6 @@
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_LIS2DS12 lis2ds12)
zephyr_library_sources_ifdef(CONFIG_LIS2DS12 lis2ds12_i2c.c)
zephyr_library_sources_ifdef(CONFIG_LIS2DS12 lis2ds12_spi.c)
zephyr_library_sources_ifdef(CONFIG_LIS2DS12_TRIGGER lis2ds12_trigger.c)

View file

@ -0,0 +1,90 @@
# ST Microelectronics LIS2DS12 3-axis accelerometer driver
#
# Copyright (c) 2019 STMicroelectronics
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig LIS2DS12
bool "LIS2DS12 I2C/SPI accelerometer sensor driver"
depends on (I2C && HAS_DTS_I2C) || (SPI && HAS_DTS_SPI)
help
Enable driver for LIS2DS12 accelerometer sensor driver
if LIS2DS12
choice LIS2DS12_TRIGGER_MODE
prompt "Trigger mode"
help
Specify the type of triggering to be used by the driver.
config LIS2DS12_TRIGGER_NONE
bool "No trigger"
config LIS2DS12_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
select LIS2DS12_TRIGGER
config LIS2DS12_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
select LIS2DS12_TRIGGER
endchoice
config LIS2DS12_TRIGGER
bool
config LIS2DS12_THREAD_PRIORITY
int "Thread priority"
depends on LIS2DS12_TRIGGER_OWN_THREAD
default 10
help
Priority of thread used by the driver to handle interrupts.
config LIS2DS12_THREAD_STACK_SIZE
int "Thread stack size"
depends on LIS2DS12_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
config LIS2DS12_ENABLE_TEMP
bool "Enable temperature"
help
Enable/disable temperature
menu "Attributes"
config LIS2DS12_FS
int "Accelerometer full-scale range"
default 0
help
Specify the default accelerometer full-scale range.
An X value for the config represents a range of +/- X G. Valid values
are:
0: Full Scale selected at runtime
2: +/- 2g
4: +/- 4g
8: +/- 8g
16: +/- 16g
config LIS2DS12_ODR
int "Accelerometer Output data rate frequency"
range 0 10
default 0
help
Specify the default accelerometer output data rate expressed in
samples per second (Hz).
0: ODR selected at runtime
1: 12.5Hz
2: 25Hz
3: 50Hz
4: 100Hz
5: 200Hz
6: 400Hz
7: 800Hz
endmenu
endif # LIS2DS12

View file

@ -0,0 +1,317 @@
/* ST Microelectronics LIS2DS12 3-axis accelerometer driver
*
* Copyright (c) 2019 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2ds12.pdf
*/
#include <sensor.h>
#include <kernel.h>
#include <device.h>
#include <init.h>
#include <string.h>
#include <misc/byteorder.h>
#include <misc/__assert.h>
#include <logging/log.h>
#include "lis2ds12.h"
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
LOG_MODULE_REGISTER(LIS2DS12);
static struct lis2ds12_data lis2ds12_data;
static struct lis2ds12_config lis2ds12_config = {
.comm_master_dev_name = DT_ST_LIS2DS12_0_BUS_NAME,
#if defined(DT_ST_LIS2DS12_BUS_SPI)
.bus_init = lis2ds12_spi_init,
#elif defined(DT_ST_LIS2DS12_BUS_I2C)
.bus_init = lis2ds12_i2c_init,
#else
#error "BUS MACRO NOT DEFINED IN DTS"
#endif
};
#if defined(LIS2DS12_ODR_RUNTIME)
static const u16_t lis2ds12_hr_odr_map[] = {0, 12, 25, 50, 100, 200, 400, 800};
static int lis2ds12_freq_to_odr_val(u16_t freq)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(lis2ds12_hr_odr_map); i++) {
if (freq == lis2ds12_hr_odr_map[i]) {
return i;
}
}
return -EINVAL;
}
static int lis2ds12_accel_odr_set(struct device *dev, u16_t freq)
{
struct lis2ds12_data *data = dev->driver_data;
int odr;
odr = lis2ds12_freq_to_odr_val(freq);
if (odr < 0) {
return odr;
}
if (data->hw_tf->update_reg(data,
LIS2DS12_REG_CTRL1,
LIS2DS12_MASK_CTRL1_ODR,
odr << LIS2DS12_SHIFT_CTRL1_ODR) < 0) {
LOG_DBG("failed to set accelerometer sampling rate");
return -EIO;
}
return 0;
}
#endif
#ifdef LIS2DS12_FS_RUNTIME
static const u16_t lis2ds12_accel_fs_map[] = {2, 16, 4, 8};
static const u16_t lis2ds12_accel_fs_sens[] = {1, 8, 2, 4};
static int lis2ds12_accel_range_to_fs_val(s32_t range)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(lis2ds12_accel_fs_map); i++) {
if (range == lis2ds12_accel_fs_map[i]) {
return i;
}
}
return -EINVAL;
}
static int lis2ds12_accel_range_set(struct device *dev, s32_t range)
{
int fs;
struct lis2ds12_data *data = dev->driver_data;
fs = lis2ds12_accel_range_to_fs_val(range);
if (fs < 0) {
return fs;
}
if (data->hw_tf->update_reg(data,
LIS2DS12_REG_CTRL1,
LIS2DS12_MASK_CTRL1_FS,
fs << LIS2DS12_SHIFT_CTRL1_FS) < 0) {
LOG_DBG("failed to set accelerometer full-scale");
return -EIO;
}
data->gain = (float)(lis2ds12_accel_fs_sens[fs] * GAIN_XL);
return 0;
}
#endif
static int lis2ds12_accel_config(struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (attr) {
#ifdef LIS2DS12_FS_RUNTIME
case SENSOR_ATTR_FULL_SCALE:
return lis2ds12_accel_range_set(dev, sensor_ms2_to_g(val));
#endif
#ifdef LIS2DS12_ODR_RUNTIME
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return lis2ds12_accel_odr_set(dev, val->val1);
#endif
default:
LOG_DBG("Accel attribute not supported.");
return -ENOTSUP;
}
return 0;
}
static int lis2ds12_attr_set(struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (chan) {
case SENSOR_CHAN_ACCEL_XYZ:
return lis2ds12_accel_config(dev, chan, attr, val);
default:
LOG_WRN("attr_set() not supported on this channel.");
return -ENOTSUP;
}
return 0;
}
static int lis2ds12_sample_fetch_accel(struct device *dev)
{
struct lis2ds12_data *data = dev->driver_data;
u8_t buf[6];
if (data->hw_tf->read_data(data, LIS2DS12_REG_OUTX_L,
buf, sizeof(buf)) < 0) {
LOG_DBG("failed to read sample");
return -EIO;
}
data->sample_x = (s16_t)((u16_t)(buf[0]) | ((u16_t)(buf[1]) << 8));
data->sample_y = (s16_t)((u16_t)(buf[2]) | ((u16_t)(buf[3]) << 8));
data->sample_z = (s16_t)((u16_t)(buf[4]) | ((u16_t)(buf[5]) << 8));
return 0;
}
static int lis2ds12_sample_fetch(struct device *dev, enum sensor_channel chan)
{
switch (chan) {
case SENSOR_CHAN_ACCEL_XYZ:
lis2ds12_sample_fetch_accel(dev);
break;
#if defined(CONFIG_LIS2DS12_ENABLE_TEMP)
case SENSOR_CHAN_DIE_TEMP:
lis2ds12_sample_fetch_temp(dev);
break;
#endif
case SENSOR_CHAN_ALL:
lis2ds12_sample_fetch_accel(dev);
#if defined(CONFIG_LIS2DS12_ENABLE_TEMP)
lis2ds12_sample_fetch_temp(dev);
#endif
break;
default:
return -ENOTSUP;
}
return 0;
}
static inline void lis2ds12_convert(struct sensor_value *val, int raw_val,
float gain)
{
s64_t dval;
/* Gain is in mg/LSB */
/* Convert to m/s^2 */
dval = ((s64_t)raw_val * gain * SENSOR_G) / 1000;
val->val1 = dval / 1000000LL;
val->val2 = dval % 1000000LL;
}
static inline int lis2ds12_get_channel(enum sensor_channel chan,
struct sensor_value *val,
struct lis2ds12_data *data,
float gain)
{
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
lis2ds12_convert(val, data->sample_x, gain);
break;
case SENSOR_CHAN_ACCEL_Y:
lis2ds12_convert(val, data->sample_y, gain);
break;
case SENSOR_CHAN_ACCEL_Z:
lis2ds12_convert(val, data->sample_z, gain);
break;
case SENSOR_CHAN_ACCEL_XYZ:
lis2ds12_convert(val, data->sample_x, gain);
lis2ds12_convert(val + 1, data->sample_y, gain);
lis2ds12_convert(val + 2, data->sample_z, gain);
break;
default:
return -ENOTSUP;
}
return 0;
}
static int lis2ds12_channel_get(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
struct lis2ds12_data *data = dev->driver_data;
return lis2ds12_get_channel(chan, val, data, data->gain);
}
static const struct sensor_driver_api lis2ds12_api_funcs = {
.attr_set = lis2ds12_attr_set,
#if defined(CONFIG_LIS2DS12_TRIGGER)
.trigger_set = lis2ds12_trigger_set,
#endif
.sample_fetch = lis2ds12_sample_fetch,
.channel_get = lis2ds12_channel_get,
};
static int lis2ds12_init(struct device *dev)
{
const struct lis2ds12_config * const config = dev->config->config_info;
struct lis2ds12_data *data = dev->driver_data;
u8_t chip_id;
data->comm_master = device_get_binding(config->comm_master_dev_name);
if (!data->comm_master) {
LOG_DBG("master not found: %s",
config->comm_master_dev_name);
return -EINVAL;
}
config->bus_init(dev);
/* s/w reset the sensor */
if (data->hw_tf->write_reg(data,
LIS2DS12_REG_CTRL2,
LIS2DS12_SOFT_RESET) < 0) {
LOG_DBG("s/w reset fail");
return -EIO;
}
if (data->hw_tf->read_reg(data, LIS2DS12_REG_WHO_AM_I, &chip_id) < 0) {
LOG_DBG("failed reading chip id");
return -EIO;
}
if (chip_id != LIS2DS12_VAL_WHO_AM_I) {
LOG_DBG("invalid chip id 0x%x", chip_id);
return -EIO;
}
LOG_DBG("chip id 0x%x", chip_id);
#ifdef CONFIG_LIS2DS12_TRIGGER
if (lis2ds12_trigger_init(dev) < 0) {
LOG_ERR("Failed to initialize triggers.");
return -EIO;
}
#endif
/* set sensor default odr */
if (data->hw_tf->update_reg(data,
LIS2DS12_REG_CTRL1,
LIS2DS12_MASK_CTRL1_ODR,
LIS2DS12_DEFAULT_ODR) < 0) {
LOG_DBG("failed setting odr");
return -EIO;
}
/* set sensor default scale */
if (data->hw_tf->update_reg(data,
LIS2DS12_REG_CTRL1,
LIS2DS12_MASK_CTRL1_FS,
LIS2DS12_DEFAULT_FS) < 0) {
LOG_DBG("failed setting scale");
return -EIO;
}
data->gain = LIS2DS12_DEFAULT_GAIN;
return 0;
}
DEVICE_AND_API_INIT(lis2ds12, DT_ST_LIS2DS12_0_LABEL, lis2ds12_init,
&lis2ds12_data, &lis2ds12_config, POST_KERNEL,
CONFIG_SENSOR_INIT_PRIORITY, &lis2ds12_api_funcs);

View file

@ -0,0 +1,142 @@
/* ST Microelectronics LIS2DS12 3-axis accelerometer driver
*
* Copyright (c) 2019 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2ds12.pdf
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_LIS2DS12_LIS2DS12_H_
#define ZEPHYR_DRIVERS_SENSOR_LIS2DS12_LIS2DS12_H_
#include <zephyr/types.h>
#include <sensor.h>
#include <gpio.h>
#define LIS2DS12_REG_WHO_AM_I 0x0F
#define LIS2DS12_VAL_WHO_AM_I 0x43
#define LIS2DS12_REG_CTRL1 0x20
#define LIS2DS12_MASK_CTRL1_ODR (BIT(7) | BIT(6) | \
BIT(5) | BIT(4))
#define LIS2DS12_SHIFT_CTRL1_ODR 4
#define LIS2DS12_MASK_CTRL1_FS (BIT(3) | BIT(2))
#define LIS2DS12_SHIFT_CTRL1_FS 2
#define LIS2DS12_MASK_CTRL1_HF_ODR BIT(1)
#define LIS2DS12_MASK_CTRL1_HF_BDU BIT(0)
#define LIS2DS12_REG_CTRL2 0x21
#define LIS2DS12_SOFT_RESET 0x40
#define LIS2DS12_REG_CTRL3 0x22
#define LIS2DS12_SHIFT_LIR 0x02
#define LIS2DS12_MASK_LIR 0x04
#define LIS2DS12_REG_CTRL4 0x23
#define LIS2DS12_SHIFT_INT1_DRDY 0x00
#define LIS2DS12_MASK_INT1_DRDY 0x01
#define LIS2DS12_REG_OUT_T 0x26
#define LIS2DS12_REG_STATUS 0x27
#define LIS2DS12_INT_DRDY 0x01
#define LIS2DS12_REG_OUTX_L 0x28
#define LIS2DS12_REG_OUTX_H 0x29
#define LIS2DS12_REG_OUTY_L 0x2A
#define LIS2DS12_REG_OUTY_H 0x2B
#define LIS2DS12_REG_OUTZ_L 0x2C
#define LIS2DS12_REG_OUTZ_H 0x2D
#if (CONFIG_LIS2DS12_ODR == 0)
#define LIS2DS12_ODR_RUNTIME 1
#define LIS2DS12_DEFAULT_ODR 0
#else
#define LIS2DS12_DEFAULT_ODR (CONFIG_LIS2DS12_ODR << 4)
#endif
/* Accel sensor sensitivity unit is 0.061 mg/LSB */
#define GAIN_XL (61LL / 1000.0)
#if CONFIG_LIS2DS12_FS == 0
#define LIS2DS12_FS_RUNTIME 1
#define LIS2DS12_DEFAULT_FS (0 << 2)
#define LIS2DS12_DEFAULT_GAIN GAIN_XL
#elif CONFIG_LIS2DS12_FS == 2
#define LIS2DS12_DEFAULT_FS (0 << 2)
#define LIS2DS12_DEFAULT_GAIN GAIN_XL
#elif CONFIG_LIS2DS12_FS == 4
#define LIS2DS12_DEFAULT_FS (2 << 2)
#define LIS2DS12_DEFAULT_GAIN (2.0 * GAIN_XL)
#elif CONFIG_LIS2DS12_FS == 8
#define LIS2DS12_DEFAULT_FS (3 << 2)
#define LIS2DS12_DEFAULT_GAIN (4.0 * GAIN_XL)
#elif CONFIG_LIS2DS12_FS == 16
#define LIS2DS12_DEFAULT_FS (1 << 2)
#define LIS2DS12_DEFAULT_GAIN (8.0 * GAIN_XL)
#else
#error "Bad LIS2DS12 FS value (should be 0, 2, 4, 8, 16)"
#endif
struct lis2ds12_config {
char *comm_master_dev_name;
int (*bus_init)(struct device *dev);
};
struct lis2ds12_data;
struct lis2ds12_transfer_function {
int (*read_data)(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len);
int (*write_data)(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len);
int (*read_reg)(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value);
int (*write_reg)(struct lis2ds12_data *data, u8_t reg_addr,
u8_t value);
int (*update_reg)(struct lis2ds12_data *data, u8_t reg_addr,
u8_t mask, u8_t value);
};
struct lis2ds12_data {
struct device *comm_master;
int sample_x;
int sample_y;
int sample_z;
float gain;
const struct lis2ds12_transfer_function *hw_tf;
#ifdef CONFIG_LIS2DS12_TRIGGER
struct device *gpio;
struct gpio_callback gpio_cb;
struct sensor_trigger data_ready_trigger;
sensor_trigger_handler_t data_ready_handler;
#if defined(CONFIG_LIS2DS12_TRIGGER_OWN_THREAD)
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_LIS2DS12_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem trig_sem;
#elif defined(CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD)
struct k_work work;
struct device *dev;
#endif
#endif /* CONFIG_LIS2DS12_TRIGGER */
};
int lis2ds12_spi_init(struct device *dev);
int lis2ds12_i2c_init(struct device *dev);
#ifdef CONFIG_LIS2DS12_TRIGGER
int lis2ds12_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int lis2ds12_trigger_init(struct device *dev);
#endif
#endif /* ZEPHYR_DRIVERS_SENSOR_LIS2DS12_LIS2DS12_H_ */

View file

@ -0,0 +1,75 @@
/* ST Microelectronics LIS2DS12 3-axis accelerometer driver
*
* Copyright (c) 2019 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2ds12.pdf
*/
#include <string.h>
#include <i2c.h>
#include <logging/log.h>
#include "lis2ds12.h"
#ifdef DT_ST_LIS2DS12_BUS_I2C
static u16_t lis2ds12_i2c_slave_addr = DT_ST_LIS2DS12_0_BASE_ADDRESS;
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
LOG_MODULE_DECLARE(LIS2DS12);
static int lis2ds12_i2c_read_data(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len)
{
return i2c_burst_read(data->comm_master, lis2ds12_i2c_slave_addr,
reg_addr, value, len);
}
static int lis2ds12_i2c_write_data(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len)
{
return i2c_burst_write(data->comm_master, lis2ds12_i2c_slave_addr,
reg_addr, value, len);
}
static int lis2ds12_i2c_read_reg(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value)
{
return i2c_reg_read_byte(data->comm_master, lis2ds12_i2c_slave_addr,
reg_addr, value);
}
static int lis2ds12_i2c_write_reg(struct lis2ds12_data *data, u8_t reg_addr,
u8_t value)
{
return i2c_reg_write_byte(data->comm_master, lis2ds12_i2c_slave_addr,
reg_addr, value);
}
static int lis2ds12_i2c_update_reg(struct lis2ds12_data *data, u8_t reg_addr,
u8_t mask, u8_t value)
{
return i2c_reg_update_byte(data->comm_master, lis2ds12_i2c_slave_addr,
reg_addr, mask, value);
}
static const struct lis2ds12_transfer_function lis2ds12_i2c_transfer_fn = {
.read_data = lis2ds12_i2c_read_data,
.write_data = lis2ds12_i2c_write_data,
.read_reg = lis2ds12_i2c_read_reg,
.write_reg = lis2ds12_i2c_write_reg,
.update_reg = lis2ds12_i2c_update_reg,
};
int lis2ds12_i2c_init(struct device *dev)
{
struct lis2ds12_data *data = dev->driver_data;
data->hw_tf = &lis2ds12_i2c_transfer_fn;
return 0;
}
#endif /* DT_ST_LIS2DS12_BUS_I2C */

View file

@ -0,0 +1,182 @@
/* ST Microelectronics LIS2DS12 3-axis accelerometer driver
*
* Copyright (c) 2019 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2ds12.pdf
*/
#include <string.h>
#include <spi.h>
#include "lis2ds12.h"
#include <logging/log.h>
#ifdef DT_ST_LIS2DS12_BUS_SPI
#define LIS2DS12_SPI_READ (1 << 7)
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
LOG_MODULE_DECLARE(LIS2DS12);
#if defined(CONFIG_LIS2DS12_SPI_GPIO_CS)
static struct spi_cs_control lis2ds12_cs_ctrl;
#endif
static struct spi_config lis2ds12_spi_conf = {
.frequency = DT_ST_LIS2DS12_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_LIS2DS12_0_BASE_ADDRESS,
.cs = NULL,
};
static int lis2ds12_raw_read(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len)
{
struct spi_config *spi_cfg = &lis2ds12_spi_conf;
u8_t buffer_tx[2] = { reg_addr | LIS2DS12_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->comm_master, spi_cfg, &tx, &rx)) {
return -EIO;
}
return 0;
}
static int lis2ds12_raw_write(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len)
{
struct spi_config *spi_cfg = &lis2ds12_spi_conf;
u8_t buffer_tx[1] = { reg_addr & ~LIS2DS12_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->comm_master, spi_cfg, &tx)) {
return -EIO;
}
return 0;
}
static int lis2ds12_spi_read_data(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len)
{
return lis2ds12_raw_read(data, reg_addr, value, len);
}
static int lis2ds12_spi_write_data(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value, u8_t len)
{
return lis2ds12_raw_write(data, reg_addr, value, len);
}
static int lis2ds12_spi_read_reg(struct lis2ds12_data *data, u8_t reg_addr,
u8_t *value)
{
return lis2ds12_raw_read(data, reg_addr, value, 1);
}
static int lis2ds12_spi_write_reg(struct lis2ds12_data *data, u8_t reg_addr,
u8_t value)
{
u8_t tmp_val = value;
return lis2ds12_raw_write(data, reg_addr, &tmp_val, 1);
}
static int lis2ds12_spi_update_reg(struct lis2ds12_data *data, u8_t reg_addr,
u8_t mask, u8_t value)
{
u8_t tmp_val;
lis2ds12_raw_read(data, reg_addr, &tmp_val, 1);
tmp_val = (tmp_val & ~mask) | (value & mask);
return lis2ds12_raw_write(data, reg_addr, &tmp_val, 1);
}
static const struct lis2ds12_transfer_function lis2ds12_spi_transfer_fn = {
.read_data = lis2ds12_spi_read_data,
.write_data = lis2ds12_spi_write_data,
.read_reg = lis2ds12_spi_read_reg,
.write_reg = lis2ds12_spi_write_reg,
.update_reg = lis2ds12_spi_update_reg,
};
int lis2ds12_spi_init(struct device *dev)
{
struct lis2ds12_data *data = dev->driver_data;
data->hw_tf = &lis2ds12_spi_transfer_fn;
#if defined(CONFIG_LIS2DS12_SPI_GPIO_CS)
/* handle SPI CS thru GPIO if it is the case */
if (IS_ENABLED(CONFIG_LIS2DS12_SPI_GPIO_CS)) {
lis2ds12_cs_ctrl.gpio_dev = device_get_binding(
CONFIG_LIS2DS12_SPI_GPIO_CS_DRV_NAME);
if (!lis2ds12_cs_ctrl.gpio_dev) {
LOG_ERR("Unable to get GPIO SPI CS device");
return -ENODEV;
}
lis2ds12_cs_ctrl.gpio_pin = CONFIG_LIS2DS12_SPI_GPIO_CS_PIN;
lis2ds12_cs_ctrl.delay = 0;
lis2ds12_spi_conf.cs = &lis2ds12_cs_ctrl;
LOG_DBG("SPI GPIO CS configured on %s:%u",
CONFIG_LIS2DS12_SPI_GPIO_CS_DRV_NAME,
CONFIG_LIS2DS12_SPI_GPIO_CS_PIN);
}
#endif
return 0;
}
#endif /* DT_ST_LIS2DS12_BUS_SPI */

View file

@ -0,0 +1,192 @@
/* ST Microelectronics LIS2DS12 3-axis accelerometer driver
*
* Copyright (c) 2019 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/lis2ds12.pdf
*/
#include <device.h>
#include <i2c.h>
#include <misc/__assert.h>
#include <misc/util.h>
#include <kernel.h>
#include <sensor.h>
#include "lis2ds12.h"
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_DECLARE(LIS2DS12);
static void lis2ds12_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct lis2ds12_data *data =
CONTAINER_OF(cb, struct lis2ds12_data, gpio_cb);
ARG_UNUSED(pins);
gpio_pin_disable_callback(dev, DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN);
#if defined(CONFIG_LIS2DS12_TRIGGER_OWN_THREAD)
k_sem_give(&data->trig_sem);
#elif defined(CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD)
k_work_submit(&data->work);
#endif
}
static void lis2ds12_handle_drdy_int(struct device *dev)
{
struct lis2ds12_data *data = dev->driver_data;
if (data->data_ready_handler != NULL) {
data->data_ready_handler(dev, &data->data_ready_trigger);
}
}
static void lis2ds12_handle_int(void *arg)
{
struct device *dev = arg;
struct lis2ds12_data *data = dev->driver_data;
u8_t status;
if (data->hw_tf->read_reg(data, LIS2DS12_REG_STATUS, &status) < 0) {
LOG_ERR("status reading error");
return;
}
if (status & LIS2DS12_INT_DRDY) {
lis2ds12_handle_drdy_int(dev);
}
gpio_pin_enable_callback(data->gpio, DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN);
}
#ifdef CONFIG_LIS2DS12_TRIGGER_OWN_THREAD
static void lis2ds12_thread(int dev_ptr, int unused)
{
struct device *dev = INT_TO_POINTER(dev_ptr);
struct lis2ds12_data *data = dev->driver_data;
ARG_UNUSED(unused);
while (1) {
k_sem_take(&data->trig_sem, K_FOREVER);
lis2ds12_handle_int(dev);
}
}
#endif
#ifdef CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD
static void lis2ds12_work_cb(struct k_work *work)
{
struct lis2ds12_data *data =
CONTAINER_OF(work, struct lis2ds12_data, work);
lis2ds12_handle_int(data->dev);
}
#endif
static int lis2ds12_init_interrupt(struct device *dev)
{
struct lis2ds12_data *data = dev->driver_data;
/* Enable latched mode */
if (data->hw_tf->update_reg(data,
LIS2DS12_REG_CTRL3,
LIS2DS12_MASK_LIR,
(1 << LIS2DS12_SHIFT_LIR)) < 0) {
LOG_ERR("Could not enable LIR mode.");
return -EIO;
}
/* enable data-ready interrupt */
if (data->hw_tf->update_reg(data,
LIS2DS12_REG_CTRL4,
LIS2DS12_MASK_INT1_DRDY,
(1 << LIS2DS12_SHIFT_INT1_DRDY)) < 0) {
LOG_ERR("Could not enable data-ready interrupt.");
return -EIO;
}
return 0;
}
int lis2ds12_trigger_init(struct device *dev)
{
struct lis2ds12_data *data = dev->driver_data;
/* setup data ready gpio interrupt */
data->gpio = device_get_binding(DT_ST_LIS2DS12_0_IRQ_GPIOS_CONTROLLER);
if (data->gpio == NULL) {
LOG_ERR("Cannot get pointer to %s device.",
DT_ST_LIS2DS12_0_IRQ_GPIOS_CONTROLLER);
return -EINVAL;
}
gpio_pin_configure(data->gpio, DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN,
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
gpio_init_callback(&data->gpio_cb,
lis2ds12_gpio_callback,
BIT(DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN));
if (gpio_add_callback(data->gpio, &data->gpio_cb) < 0) {
LOG_ERR("Could not set gpio callback.");
return -EIO;
}
#if defined(CONFIG_LIS2DS12_TRIGGER_OWN_THREAD)
k_sem_init(&data->trig_sem, 0, UINT_MAX);
k_thread_create(&data->thread, data->thread_stack,
CONFIG_LIS2DS12_THREAD_STACK_SIZE,
(k_thread_entry_t)lis2ds12_thread, dev,
0, NULL, K_PRIO_COOP(CONFIG_LIS2DS12_THREAD_PRIORITY),
0, 0);
#elif defined(CONFIG_LIS2DS12_TRIGGER_GLOBAL_THREAD)
data->work.handler = lis2ds12_work_cb;
data->dev = dev;
#endif
gpio_pin_enable_callback(data->gpio, DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN);
return 0;
}
int lis2ds12_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct lis2ds12_data *data = dev->driver_data;
u8_t buf[6];
__ASSERT_NO_MSG(trig->type == SENSOR_TRIG_DATA_READY);
gpio_pin_disable_callback(data->gpio, DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN);
data->data_ready_handler = handler;
if (handler == NULL) {
LOG_WRN("lis2ds12: no handler");
return 0;
}
/* re-trigger lost interrupt */
if (data->hw_tf->read_data(data, LIS2DS12_REG_OUTX_L,
buf, sizeof(buf)) < 0) {
LOG_ERR("status reading error");
return -EIO;
}
data->data_ready_trigger = *trig;
lis2ds12_init_interrupt(dev);
gpio_pin_enable_callback(data->gpio, DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN);
return 0;
}

View file

@ -0,0 +1,24 @@
#
# Copyright (c) 2019 STMicroelectronics
#
# SPDX-License-Identifier: Apache-2.0
#
---
title: STMicroelectronics MEMS sensors LIS2DS12
version: 0.1
description: >
This binding gives a base representation of LIS2DS12 3-axis accelerometer
inherits:
!include i2c-device.yaml
properties:
compatible:
constraint: "st,lis2ds12"
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 LIS2DS12 SPI
version: 0.1
description: >
This binding gives a base representation of LIS2DS12 3-axis accelerometer
accessed through SPI bus
inherits:
!include spi-device.yaml
properties:
compatible:
constraint: "st,lis2ds12"
irq-gpios:
type: compound
category: required
generation: define, use-prop-name
...

View file

@ -158,6 +158,15 @@
#define DT_SENSIRION_SHT3XD_0_BUS_NAME ""
#endif
#ifndef DT_ST_LIS2DS12_0_LABEL
#define DT_ST_LIS2DS12_0_LABEL ""
#define DT_ST_LIS2DS12_0_BUS_NAME ""
#define DT_ST_LIS2DS12_0_BASE_ADDRESS 0x19
#define DT_ST_LIS2DS12_0_IRQ_GPIOS_CONTROLLER ""
#define DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN 0
#define DT_ST_LIS2DS12_BUS_I2C 1
#endif
#ifndef DT_LIS3DH_DEV_NAME
#define DT_LIS3DH_DEV_NAME ""
#define DT_LIS3DH_I2C_ADDRESS 0x19
@ -219,6 +228,16 @@
#define DT_LIS2DH_INT2_GPIO_PIN 1
#endif
#ifndef DT_ST_LIS2DS12_0_LABEL
#define DT_ST_LIS2DS12_0_LABEL ""
#define DT_ST_LIS2DS12_0_BUS_NAME ""
#define DT_ST_LIS2DS12_0_SPI_MAX_FREQUENCY 100000
#define DT_ST_LIS2DS12_0_BASE_ADDRESS 1
#define DT_ST_LIS2DS12_0_IRQ_GPIOS_CONTROLLER ""
#define DT_ST_LIS2DS12_0_IRQ_GPIOS_PIN 0
#define DT_ST_LIS2DS12_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

@ -7,6 +7,7 @@ CONFIG_LOG=y
CONFIG_SENSOR_LOG_LEVEL_DBG=y
CONFIG_ISL29035=y
CONFIG_LIS2DH=y
CONFIG_LIS2DS12=y
CONFIG_LIS2MDL=y
CONFIG_LIS3DH=y
CONFIG_LIS3MDL=y

View file

@ -8,6 +8,8 @@ CONFIG_ISL29035=y
CONFIG_ISL29035_TRIGGER_OWN_THREAD=y
CONFIG_LIS2DH=y
CONFIG_LIS2DH_TRIGGER_OWN_THREAD=y
CONFIG_LIS2DS12=y
CONFIG_LIS2DS12_TRIGGER_OWN_THREAD=y
CONFIG_LIS2MDL=y
CONFIG_LIS2MDL_TRIGGER_OWN_THREAD=y
CONFIG_LIS3DH=y