drivers/sensors: Add iis2dh accelerometer sensor support

Add support to STM IIS2DH the ultra-low-power highperformance
three-axis linear accelerometer.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2020-04-09 15:33:25 +02:00 committed by Maureen Helm
commit 485f2d410c
16 changed files with 954 additions and 0 deletions

View file

@ -27,6 +27,7 @@ add_subdirectory_ifdef(CONFIG_TI_HDC ti_hdc)
add_subdirectory_ifdef(CONFIG_HMC5883L hmc5883l)
add_subdirectory_ifdef(CONFIG_HP206C hp206c)
add_subdirectory_ifdef(CONFIG_HTS221 hts221)
add_subdirectory_ifdef(CONFIG_IIS2DH iis2dh)
add_subdirectory_ifdef(CONFIG_IIS2DLPC iis2dlpc)
add_subdirectory_ifdef(CONFIG_IIS2MDC iis2mdc)
add_subdirectory_ifdef(CONFIG_IIS3DHHC iis3dhhc)

View file

@ -83,6 +83,8 @@ source "drivers/sensor/hp206c/Kconfig"
source "drivers/sensor/hts221/Kconfig"
source "drivers/sensor/iis2dh/Kconfig"
source "drivers/sensor/iis2dlpc/Kconfig"
source "drivers/sensor/iis2mdc/Kconfig"

View file

@ -0,0 +1,12 @@
# ST Microelectronics IIS2DH 3-axis accelerometer driver
#
# Copyright (c) 2020 STMicroelectronics
#
# SPDX-License-Identifier: Apache-2.0
#
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_IIS2DH iis2dh)
zephyr_library_sources_ifdef(CONFIG_IIS2DH iis2dh_i2c.c)
zephyr_library_sources_ifdef(CONFIG_IIS2DH iis2dh_spi.c)
zephyr_library_sources_ifdef(CONFIG_IIS2DH_TRIGGER iis2dh_trigger.c)

View file

@ -0,0 +1,97 @@
# ST Microelectronics IIS2DH 3-axis accelerometer driver
# Copyright (c) 2020 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
menuconfig IIS2DH
bool "IIS2DH I2C/SPI accelerometer sensor driver"
depends on (I2C && HAS_DTS_I2C) || SPI
select HAS_STMEMSC
select USE_STDC_IIS2DH
help
Enable driver for IIS2DH accelerometer sensor driver
if IIS2DH
choice IIS2DH_TRIGGER_MODE
prompt "Trigger mode"
help
Specify the type of triggering to be used by the driver.
config IIS2DH_TRIGGER_NONE
bool "No trigger"
config IIS2DH_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
select IIS2DH_TRIGGER
config IIS2DH_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
select IIS2DH_TRIGGER
endchoice
config IIS2DH_TRIGGER
bool
if IIS2DH_TRIGGER
config IIS2DH_THREAD_PRIORITY
int "Thread priority"
depends on IIS2DH_TRIGGER_OWN_THREAD
default 10
help
Priority of thread used by the driver to handle interrupts.
config IIS2DH_THREAD_STACK_SIZE
int "Thread stack size"
depends on IIS2DH_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
endif # IIS2DH_TRIGGER
config IIS2DH_RANGE
int "Accelerometer Full-scale range setting"
default 0
help
Specify the default accelerometer full-scale range.
Valid values are:
0: Full Scale selected at runtime
2: +/- 2g
4: +/- 4g
8: +/- 8g
16: +/- 16g
config IIS2DH_ODR
int "Accelerometer sampling frequency (ODR)"
range 0 9
default 0
help
Specify the default accelerometer output data rate expressed in
samples per second (Hz).
0: ODR selected at runtime
1: 1 Hz
2: 10 Hz
3: 25 Hz
4: 50 Hz
5: 100 Hz
6: 200 Hz
7: 400 Hz
8: 1620 Hz (only LP)
9: Depends by mode. LP: 5376 Hz - NORM or HR: 1344 Hz
config IIS2DH_POWER_MODE
int "Sensor Power Modes"
range 0 2
default 0
help
Specify the sensor power mode
0: High Resolution mode
1: Normal mode
2: Low Power mode
endif # IIS2DH

View file

@ -0,0 +1,315 @@
/* ST Microelectronics IIS2DH 3-axis accelerometer driver
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2dh.pdf
*/
#define DT_DRV_COMPAT st_iis2dh
#include <init.h>
#include <sys/__assert.h>
#include <sys/byteorder.h>
#include <logging/log.h>
#include <drivers/sensor.h>
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#include <drivers/spi.h>
#elif DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
#include <drivers/i2c.h>
#endif
#include "iis2dh.h"
LOG_MODULE_REGISTER(IIS2DH, CONFIG_SENSOR_LOG_LEVEL);
/* gains in uG/LSB */
static const uint32_t iis2dh_gain[3][4] = {
{
/* HR mode */
980/16, /* 2G */
1950/16, /* 4G */
3910/16, /* 8G */
11720/16, /* 16G */
},
{
/* NM mode */
3910/64, /* 2G */
7810/64, /* 4G */
15630/64, /* 8G */
46950/64, /* 16G */
},
{
/* LP mode */
15630/256, /* 2G */
31250/256, /* 4G */
62500/256, /* 8G */
188680/256, /* 16G */
},
};
static int iis2dh_set_fs_raw(struct iis2dh_data *iis2dh, uint8_t fs)
{
int err;
err = iis2dh_full_scale_set(iis2dh->ctx, fs);
if (!err) {
/* save internally gain for optimization */
iis2dh->gain = iis2dh_gain[IIS2DH_HR_12bit][fs];
}
return err;
}
#if (CONFIG_IIS2DH_RANGE == 0)
/**
* iis2dh_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 iis2dh_set_range(struct device *dev, uint16_t range)
{
int err;
struct iis2dh_data *iis2dh = dev->driver_data;
uint8_t fs = IIS2DH_FS_TO_REG(range);
err = iis2dh_set_fs_raw(iis2dh, fs);
return err;
}
#endif
#if (CONFIG_IIS2DH_ODR == 0)
/**
* iis2dh_set_odr - set new sampling frequency
* @dev: Pointer to instance of struct device (I2C or SPI)
* @odr: Output data rate
*/
static int iis2dh_set_odr(struct device *dev, uint16_t odr)
{
struct iis2dh_data *iis2dh = dev->driver_data;
const struct iis2dh_device_config *cfg = dev->config_info;
iis2dh_odr_t val;
val = IIS2DH_ODR_TO_REG_HR(cfg->pm, odr);
return iis2dh_data_rate_set(iis2dh->ctx, val);
}
#endif
static inline void iis2dh_convert(struct sensor_value *val, int raw_val,
uint32_t gain)
{
int64_t dval;
/* Gain is in ug/LSB */
/* Convert to m/s^2 */
dval = ((int64_t)raw_val * gain * SENSOR_G) / 1000000LL;
val->val1 = dval / 1000000LL;
val->val2 = dval % 1000000LL;
}
static inline void iis2dh_channel_get_acc(struct device *dev,
enum sensor_channel chan,
struct sensor_value *val)
{
int i;
uint8_t ofs_start, ofs_stop;
struct iis2dh_data *iis2dh = dev->driver_data;
struct sensor_value *pval = val;
switch (chan) {
case SENSOR_CHAN_ACCEL_X:
ofs_start = ofs_stop = 0U;
break;
case SENSOR_CHAN_ACCEL_Y:
ofs_start = ofs_stop = 1U;
break;
case SENSOR_CHAN_ACCEL_Z:
ofs_start = ofs_stop = 2U;
break;
default:
ofs_start = 0U; ofs_stop = 2U;
break;
}
for (i = ofs_start; i <= ofs_stop ; i++) {
iis2dh_convert(pval++, iis2dh->acc[i], iis2dh->gain);
}
}
static int iis2dh_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:
iis2dh_channel_get_acc(dev, chan, val);
return 0;
default:
LOG_DBG("Channel not supported");
break;
}
return -ENOTSUP;
}
static int iis2dh_config(struct device *dev, enum sensor_channel chan,
enum sensor_attribute attr,
const struct sensor_value *val)
{
switch (attr) {
#if (CONFIG_IIS2DH_RANGE == 0)
case SENSOR_ATTR_FULL_SCALE:
return iis2dh_set_range(dev, sensor_ms2_to_g(val));
#endif
#if (CONFIG_IIS2DH_ODR == 0)
case SENSOR_ATTR_SAMPLING_FREQUENCY:
return iis2dh_set_odr(dev, val->val1);
#endif
default:
LOG_DBG("Acc attribute not supported");
break;
}
return -ENOTSUP;
}
static int iis2dh_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 iis2dh_config(dev, chan, attr, val);
default:
LOG_DBG("Attr not supported on %d channel", chan);
break;
}
return -ENOTSUP;
}
static int iis2dh_sample_fetch(struct device *dev, enum sensor_channel chan)
{
struct iis2dh_data *iis2dh = dev->driver_data;
union axis3bit16_t buf;
/* fetch raw data sample */
if (iis2dh_acceleration_raw_get(iis2dh->ctx, buf.u8bit) < 0) {
LOG_DBG("Failed to fetch raw data sample");
return -EIO;
}
iis2dh->acc[0] = sys_le16_to_cpu(buf.i16bit[0]);
iis2dh->acc[1] = sys_le16_to_cpu(buf.i16bit[1]);
iis2dh->acc[2] = sys_le16_to_cpu(buf.i16bit[2]);
return 0;
}
static const struct sensor_driver_api iis2dh_driver_api = {
.attr_set = iis2dh_attr_set,
#if CONFIG_IIS2DH_TRIGGER
.trigger_set = iis2dh_trigger_set,
#endif /* CONFIG_IIS2DH_TRIGGER */
.sample_fetch = iis2dh_sample_fetch,
.channel_get = iis2dh_channel_get,
};
static int iis2dh_init_interface(struct device *dev)
{
struct iis2dh_data *iis2dh = dev->driver_data;
const struct iis2dh_device_config *cfg = dev->config_info;
iis2dh->bus = device_get_binding(cfg->bus_name);
if (!iis2dh->bus) {
LOG_DBG("master bus not found: %s", cfg->bus_name);
return -EINVAL;
}
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
iis2dh_spi_init(dev);
#elif DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
iis2dh_i2c_init(dev);
#else
#error "BUS MACRO NOT DEFINED IN DTS"
#endif
return 0;
}
static int iis2dh_init(struct device *dev)
{
struct iis2dh_data *iis2dh = dev->driver_data;
const struct iis2dh_device_config *cfg = dev->config_info;
uint8_t wai;
if (iis2dh_init_interface(dev)) {
return -EINVAL;
}
/* check chip ID */
if (iis2dh_device_id_get(iis2dh->ctx, &wai) < 0) {
return -EIO;
}
if (wai != IIS2DH_ID) {
LOG_ERR("Invalid chip ID: %02x", wai);
return -EINVAL;
}
if (iis2dh_block_data_update_set(iis2dh->ctx, PROPERTY_ENABLE) < 0) {
return -EIO;
}
if (iis2dh_operating_mode_set(iis2dh->ctx, cfg->pm)) {
return -EIO;
}
#if (CONFIG_IIS2DH_ODR != 0)
/* set default odr and full scale for acc */
if (iis2dh_data_rate_set(iis2dh->ctx, CONFIG_IIS2DH_ODR) < 0) {
return -EIO;
}
#endif
#if (CONFIG_IIS2DH_RANGE != 0)
iis2dh_set_fs_raw(iis2dh, CONFIG_IIS2DH_RANGE);
#endif
#ifdef CONFIG_IIS2DH_TRIGGER
if (iis2dh_init_interrupt(dev) < 0) {
LOG_ERR("Failed to initialize interrupts");
return -EIO;
}
#endif /* CONFIG_IIS2DH_TRIGGER */
return 0;
}
const struct iis2dh_device_config iis2dh_cfg = {
.bus_name = DT_INST_BUS_LABEL(0),
.pm = CONFIG_IIS2DH_POWER_MODE,
#ifdef CONFIG_IIS2DH_TRIGGER
.int_gpio_port = DT_INST_GPIO_LABEL(0, drdy_gpios),
.int_gpio_pin = DT_INST_GPIO_PIN(0, drdy_gpios),
.int_gpio_flags = DT_INST_GPIO_FLAGS(0, drdy_gpios),
#endif /* CONFIG_IIS2DH_TRIGGER */
};
struct iis2dh_data iis2dh_data;
DEVICE_AND_API_INIT(iis2dh, DT_INST_LABEL(0), iis2dh_init,
&iis2dh_data, &iis2dh_cfg, POST_KERNEL,
CONFIG_SENSOR_INIT_PRIORITY, &iis2dh_driver_api);

View file

@ -0,0 +1,95 @@
/* ST Microelectronics IIS2DH 3-axis accelerometer driver
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2dh.pdf
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_IIS2DH_IIS2DH_H_
#define ZEPHYR_DRIVERS_SENSOR_IIS2DH_IIS2DH_H_
#include <drivers/spi.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <drivers/sensor.h>
#include "iis2dh_reg.h"
union axis3bit16_t {
int16_t i16bit[3];
uint8_t u8bit[6];
};
/*
* Return ODR reg value based on data rate set
*/
#define IIS2DH_ODR_TO_REG_HR(_lp, _odr) \
((_odr == 0) ? IIS2DH_POWER_DOWN : \
((_odr < 10) ? IIS2DH_ODR_1Hz : \
((_odr < 25) ? IIS2DH_ODR_10Hz : \
((_lp == IIS2DH_LP_8bit) && (_odr >= 5376) ? IIS2DH_ODR_5kHz376_LP_1kHz344_NM_HP : \
((_lp != IIS2DH_LP_8bit) && (_odr >= 1344) ? IIS2DH_ODR_5kHz376_LP_1kHz344_NM_HP : \
((_lp == IIS2DH_LP_8bit) && (_odr >= 1600) ? IIS2DH_ODR_1kHz620_LP : \
((_lp != IIS2DH_LP_8bit) && (_odr >= 800) ? IIS2DH_ODR_400Hz : \
((31 - __builtin_clz(_odr / 25))) + 3)))))))
/* FS reg value from Full Scale */
#define IIS2DH_FS_TO_REG(_fs) (30 - __builtin_clz(_fs))
/**
* struct iis2dh_device_config - iis2dh 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.
*/
struct iis2dh_device_config {
const char *bus_name;
uint8_t pm;
#ifdef CONFIG_IIS2DH_TRIGGER
const char *int_gpio_port;
uint8_t int_gpio_pin;
uint8_t int_gpio_flags;
uint8_t int_pin;
#endif /* CONFIG_IIS2DH_TRIGGER */
};
/* sensor data */
struct iis2dh_data {
struct device *bus;
int16_t acc[3];
uint32_t gain;
stmdev_ctx_t *ctx;
#ifdef CONFIG_IIS2DH_TRIGGER
struct device *gpio;
uint8_t gpio_pin;
struct gpio_callback gpio_cb;
sensor_trigger_handler_t drdy_handler;
#if defined(CONFIG_IIS2DH_TRIGGER_OWN_THREAD)
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_IIS2DH_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
#elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD)
struct k_work work;
struct device *dev;
#endif /* CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD */
#endif /* CONFIG_IIS2DH_TRIGGER */
#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
struct spi_cs_control cs_ctrl;
#endif
};
int iis2dh_i2c_init(struct device *dev);
int iis2dh_spi_init(struct device *dev);
#ifdef CONFIG_IIS2DH_TRIGGER
int iis2dh_init_interrupt(struct device *dev);
int iis2dh_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
#endif /* CONFIG_IIS2DH_TRIGGER */
#endif /* ZEPHYR_DRIVERS_SENSOR_IIS2DH_IIS2DH_H_ */

View file

@ -0,0 +1,53 @@
/* ST Microelectronics IIS2DH 3-axis accelerometer driver
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2dh.pdf
*/
#define DT_DRV_COMPAT st_iis2dh
#include <string.h>
#include <drivers/i2c.h>
#include <logging/log.h>
#include "iis2dh.h"
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
static uint16_t iis2dh_i2c_slave_addr = DT_INST_REG_ADDR(0);
LOG_MODULE_DECLARE(IIS2DH, CONFIG_SENSOR_LOG_LEVEL);
static int iis2dh_i2c_read(struct iis2dh_data *data, uint8_t reg_addr,
uint8_t *value, uint16_t len)
{
return i2c_burst_read(data->bus, iis2dh_i2c_slave_addr,
reg_addr | 0x80, value, len);
}
static int iis2dh_i2c_write(struct iis2dh_data *data, uint8_t reg_addr,
uint8_t *value, uint16_t len)
{
return i2c_burst_write(data->bus, iis2dh_i2c_slave_addr,
reg_addr | 0x80, value, len);
}
stmdev_ctx_t iis2dh_i2c_ctx = {
.read_reg = (stmdev_read_ptr) iis2dh_i2c_read,
.write_reg = (stmdev_write_ptr) iis2dh_i2c_write,
};
int iis2dh_i2c_init(struct device *dev)
{
struct iis2dh_data *data = dev->driver_data;
data->ctx = &iis2dh_i2c_ctx;
data->ctx->handle = data;
return 0;
}
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */

View file

@ -0,0 +1,128 @@
/* ST Microelectronics IIS2DH 3-axis accelerometer driver
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2dh.pdf
*/
#define DT_DRV_COMPAT st_iis2dh
#include <string.h>
#include "iis2dh.h"
#include <logging/log.h>
#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
#define IIS2DH_SPI_READM (3 << 6) /* 0xC0 */
#define IIS2DH_SPI_WRITEM (1 << 6) /* 0x40 */
LOG_MODULE_DECLARE(IIS2DH, CONFIG_SENSOR_LOG_LEVEL);
static struct spi_config iis2dh_spi_conf = {
.frequency = DT_INST_PROP(0, spi_max_frequency),
.operation = (SPI_OP_MODE_MASTER | SPI_MODE_CPOL |
SPI_MODE_CPHA | SPI_WORD_SET(8) | SPI_LINES_SINGLE),
.slave = DT_INST_REG_ADDR(0),
.cs = NULL,
};
static int iis2dh_spi_read(struct iis2dh_data *ctx, uint8_t reg,
uint8_t *data, uint16_t len)
{
struct spi_config *spi_cfg = &iis2dh_spi_conf;
uint8_t buffer_tx[2] = { reg | IIS2DH_SPI_READM, 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 = data,
.len = len,
}
};
const struct spi_buf_set rx = {
.buffers = rx_buf,
.count = 2
};
if (spi_transceive(ctx->bus, spi_cfg, &tx, &rx)) {
return -EIO;
}
return 0;
}
static int iis2dh_spi_write(struct iis2dh_data *ctx, uint8_t reg,
uint8_t *data, uint16_t len)
{
struct spi_config *spi_cfg = &iis2dh_spi_conf;
uint8_t buffer_tx[1] = { reg | IIS2DH_SPI_WRITEM };
const struct spi_buf tx_buf[2] = {
{
.buf = buffer_tx,
.len = 1,
},
{
.buf = data,
.len = len,
}
};
const struct spi_buf_set tx = {
.buffers = tx_buf,
.count = 2
};
if (spi_write(ctx->bus, spi_cfg, &tx)) {
return -EIO;
}
return 0;
}
stmdev_ctx_t iis2dh_spi_ctx = {
.read_reg = (stmdev_read_ptr) iis2dh_spi_read,
.write_reg = (stmdev_write_ptr) iis2dh_spi_write,
};
int iis2dh_spi_init(struct device *dev)
{
struct iis2dh_data *data = dev->driver_data;
data->ctx = &iis2dh_spi_ctx;
data->ctx->handle = data;
#if DT_INST_SPI_DEV_HAS_CS_GPIOS(0)
/* handle SPI CS thru GPIO if it is the case */
data->cs_ctrl.gpio_dev = device_get_binding(
DT_INST_SPI_DEV_CS_GPIOS_LABEL(0));
if (!data->cs_ctrl.gpio_dev) {
LOG_ERR("Unable to get GPIO SPI CS device");
return -ENODEV;
}
data->cs_ctrl.gpio_pin = DT_INST_SPI_DEV_CS_GPIOS_PIN(0);
data->cs_ctrl.delay = 0U;
iis2dh_spi_conf.cs = &data->cs_ctrl;
LOG_DBG("SPI GPIO CS configured on %s:%u",
DT_INST_SPI_DEV_CS_GPIOS_LABEL(0),
DT_INST_SPI_DEV_CS_GPIOS_PIN(0));
#endif
return 0;
}
#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */

View file

@ -0,0 +1,191 @@
/* ST Microelectronics IIS2DH 3-axis accelerometer driver
*
* Copyright (c) 2020 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*
* Datasheet:
* https://www.st.com/resource/en/datasheet/iis2dh.pdf
*/
#include <kernel.h>
#include <drivers/sensor.h>
#include <drivers/gpio.h>
#include <logging/log.h>
#include "iis2dh.h"
LOG_MODULE_DECLARE(IIS2DH, CONFIG_SENSOR_LOG_LEVEL);
/**
* iis2dh_enable_int - enable selected int pin to generate interrupt
*/
static int iis2dh_enable_drdy(struct device *dev,
enum sensor_trigger_type type, int enable)
{
struct iis2dh_data *iis2dh = dev->driver_data;
iis2dh_ctrl_reg3_t reg3;
/* set interrupt for pin INT1 */
iis2dh_pin_int1_config_get(iis2dh->ctx, &reg3);
reg3.i1_drdy1 = enable;
return iis2dh_pin_int1_config_set(iis2dh->ctx, &reg3);
}
/**
* iis2dh_trigger_set - link external trigger to event data ready
*/
int iis2dh_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct iis2dh_data *iis2dh = dev->driver_data;
union axis3bit16_t raw;
int state = (handler != NULL) ? PROPERTY_ENABLE : PROPERTY_DISABLE;
switch (trig->type) {
case SENSOR_TRIG_DATA_READY:
iis2dh->drdy_handler = handler;
if (state) {
/* dummy read: re-trigger interrupt */
iis2dh_acceleration_raw_get(iis2dh->ctx, raw.u8bit);
}
return iis2dh_enable_drdy(dev, SENSOR_TRIG_DATA_READY, state);
default:
LOG_ERR("Unsupported sensor trigger");
return -ENOTSUP;
}
}
static int iis2dh_handle_drdy_int(struct device *dev)
{
struct iis2dh_data *data = dev->driver_data;
struct sensor_trigger drdy_trig = {
.type = SENSOR_TRIG_DATA_READY,
.chan = SENSOR_CHAN_ALL,
};
if (data->drdy_handler) {
data->drdy_handler(dev, &drdy_trig);
}
return 0;
}
/**
* iis2dh_handle_interrupt - handle the drdy event
* read data and call handler if registered any
*/
static void iis2dh_handle_interrupt(void *arg)
{
struct device *dev = (struct device *)arg;
struct iis2dh_data *iis2dh = dev->driver_data;
const struct iis2dh_device_config *cfg = dev->config_info;
iis2dh_handle_drdy_int(dev);
gpio_pin_interrupt_configure(iis2dh->gpio, cfg->int_gpio_pin,
GPIO_INT_EDGE_TO_ACTIVE);
}
static void iis2dh_gpio_callback(struct device *dev,
struct gpio_callback *cb, uint32_t pins)
{
struct iis2dh_data *iis2dh =
CONTAINER_OF(cb, struct iis2dh_data, gpio_cb);
if ((pins & BIT(iis2dh->gpio_pin)) == 0U) {
return;
}
gpio_pin_interrupt_configure(dev, iis2dh->gpio_pin,
GPIO_INT_DISABLE);
#if defined(CONFIG_IIS2DH_TRIGGER_OWN_THREAD)
k_sem_give(&iis2dh->gpio_sem);
#elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD)
k_work_submit(&iis2dh->work);
#endif /* CONFIG_IIS2DH_TRIGGER_OWN_THREAD */
}
#ifdef CONFIG_IIS2DH_TRIGGER_OWN_THREAD
static void iis2dh_thread(int dev_ptr, int unused)
{
struct device *dev = INT_TO_POINTER(dev_ptr);
struct iis2dh_data *iis2dh = dev->driver_data;
ARG_UNUSED(unused);
while (1) {
k_sem_take(&iis2dh->gpio_sem, K_FOREVER);
iis2dh_handle_interrupt(dev);
}
}
#endif /* CONFIG_IIS2DH_TRIGGER_OWN_THREAD */
#ifdef CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD
static void iis2dh_work_cb(struct k_work *work)
{
struct iis2dh_data *iis2dh =
CONTAINER_OF(work, struct iis2dh_data, work);
iis2dh_handle_interrupt(iis2dh->dev);
}
#endif /* CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD */
int iis2dh_init_interrupt(struct device *dev)
{
struct iis2dh_data *iis2dh = dev->driver_data;
const struct iis2dh_device_config *cfg = dev->config_info;
int ret;
/* setup data ready gpio interrupt */
iis2dh->gpio = device_get_binding(cfg->int_gpio_port);
if (iis2dh->gpio == NULL) {
LOG_DBG("Cannot get pointer to %s device",
cfg->int_gpio_port);
return -EINVAL;
}
#if defined(CONFIG_IIS2DH_TRIGGER_OWN_THREAD)
k_sem_init(&iis2dh->gpio_sem, 0, UINT_MAX);
k_thread_create(&iis2dh->thread, iis2dh->thread_stack,
CONFIG_IIS2DH_THREAD_STACK_SIZE,
(k_thread_entry_t)iis2dh_thread, dev,
0, NULL, K_PRIO_COOP(CONFIG_IIS2DH_THREAD_PRIORITY),
0, K_NO_WAIT);
#elif defined(CONFIG_IIS2DH_TRIGGER_GLOBAL_THREAD)
iis2dh->work.handler = iis2dh_work_cb;
iis2dh->dev = dev;
#endif /* CONFIG_IIS2DH_TRIGGER_OWN_THREAD */
iis2dh->gpio_pin = cfg->int_gpio_pin;
ret = gpio_pin_configure(iis2dh->gpio, cfg->int_gpio_pin,
GPIO_INPUT | cfg->int_gpio_flags);
if (ret < 0) {
LOG_DBG("Could not configure gpio");
return ret;
}
gpio_init_callback(&iis2dh->gpio_cb,
iis2dh_gpio_callback,
BIT(cfg->int_gpio_pin));
if (gpio_add_callback(iis2dh->gpio, &iis2dh->gpio_cb) < 0) {
LOG_DBG("Could not set gpio callback");
return -EIO;
}
/* enable drdy on int1 in pulse mode */
if (iis2dh_int1_pin_notification_mode_set(iis2dh->ctx, IIS2DH_INT1_PULSED)) {
return -EIO;
}
return gpio_pin_interrupt_configure(iis2dh->gpio, cfg->int_gpio_pin,
GPIO_INT_EDGE_TO_ACTIVE);
}

View file

@ -0,0 +1,19 @@
# Copyright (c) 2020 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
description: |
STMicroelectronics IIS2DH accelerometer accessed through I2C bus
compatible: "st,iis2dh"
include: i2c-device.yaml
properties:
drdy-gpios:
type: phandle-array
required: false
description: DRDY pin
This pin defaults to active high when produced by the sensor.
The property value should ensure the flags properly describe
the signal that is presented to the driver.

View file

@ -0,0 +1,19 @@
# Copyright (c) 2020 STMicroelectronics
# SPDX-License-Identifier: Apache-2.0
description: |
STMicroelectronics IIS2DH accelerometer accessed through SPI bus
compatible: "st,iis2dh"
include: spi-device.yaml
properties:
drdy-gpios:
type: phandle-array
required: false
description: DRDY pin
This pin defaults to active high when produced by the sensor.
The property value should ensure the flags properly describe
the signal that is presented to the driver.

View file

@ -144,3 +144,8 @@
&test_spi_iis3dhhc {
irq-gpios = <&test_gpio 0 0>, <&test_gpio 0 0>;
};
/* disable device to conflict with i2c version */
&test_spi_iis2dh {
status = "disabled";
};

View file

@ -529,3 +529,10 @@ test_i2c_dps310: dps310@48 {
label = "DPS310";
reg = <0x48>;
};
test_i2c_iis2dh: iis2dh@18 {
compatible = "st,iis2dh";
label = "IIS2DH";
reg = <0x18>;
drdy-gpios = <&test_gpio 0 0>;
};

View file

@ -9,4 +9,5 @@ CONFIG_IIS2DLPC=y
CONFIG_LIS2DW12=y
CONFIG_STTS751=y
CONFIG_ISM330DHCX=y
CONFIG_IIS2DH=y
CONFIG_IIS2MDC=y

View file

@ -13,5 +13,7 @@ CONFIG_STTS751=y
CONFIG_STTS751_TRIGGER_OWN_THREAD=y
CONFIG_ISM330DHCX=y
CONFIG_ISM330DHCX_TRIGGER_OWN_THREAD=y
CONFIG_IIS2DH=y
CONFIG_IIS2DH_TRIGGER_OWN_THREAD=y
CONFIG_IIS2MDC=y
CONFIG_IIS2MDC_TRIGGER_OWN_THREAD=y

View file

@ -483,3 +483,10 @@ test_spi_mmc_spi_slot: mmc-spi-slot@2f {
spi-max-frequency = <0>;
};
test_spi_iis2dh: iis2dh@30 {
compatible = "st,iis2dh";
label = "IIS2DH";
reg = <0x30>;
spi-max-frequency = <0>;
drdy-gpios = <&test_gpio 0 0>;
};