drivers: sensor: lsm6dsl: add trigger support

Add DATA_READY trigger support to ST LSM6DSL driver.

Signed-off-by: Armando Visconti <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2018-03-06 16:52:59 +01:00 committed by Maureen Helm
commit 6fb326ce06
5 changed files with 245 additions and 0 deletions

View file

@ -1,3 +1,4 @@
zephyr_sources_ifdef(CONFIG_LSM6DSL lsm6dsl.c)
zephyr_sources_ifdef(CONFIG_LSM6DSL_SPI lsm6dsl_spi.c)
zephyr_sources_ifdef(CONFIG_LSM6DSL_I2C lsm6dsl_i2c.c)
zephyr_sources_ifdef(CONFIG_LSM6DSL_TRIGGER lsm6dsl_trigger.c)

View file

@ -107,6 +107,67 @@ config LSM6DSL_SPI_GPIO_CS_PIN
This option is mandatory to set which GPIO pin to use in order
to actually emulate the SPI CS.
choice
prompt "Trigger mode"
depends on LSM6DSL
default LSM6DSL_TRIGGER_NONE
help
Specify the type of triggering to be used by the driver.
config LSM6DSL_TRIGGER_NONE
bool
prompt "No trigger"
config LSM6DSL_TRIGGER_GLOBAL_THREAD
bool
prompt "Use global thread"
depends on GPIO
select LSM6DSL_TRIGGER
config LSM6DSL_TRIGGER_OWN_THREAD
bool
prompt "Use own thread"
depends on GPIO
select LSM6DSL_TRIGGER
endchoice
config LSM6DSL_TRIGGER
bool
depends on LSM6DSL
config LSM6DSL_GPIO_DEV_NAME
string
prompt "GPIO device"
depends on LSM6DSL && LSM6DSL_TRIGGER
help
The device name of the GPIO device to which the LSM6DSL interrupt pin
is connected.
config LSM6DSL_GPIO_PIN_NUM
int
prompt "Interrupt GPIO pin number"
depends on LSM6DSL && LSM6DSL_TRIGGER
help
The number of the GPIO on which the interrupt signal from the LSM6DSL
chip will be received.
config LSM6DSL_THREAD_PRIORITY
int
prompt "Thread priority"
depends on LSM6DSL && LSM6DSL_TRIGGER_OWN_THREAD
default 10
help
Priority of thread used by the driver to handle interrupts.
config LSM6DSL_THREAD_STACK_SIZE
int
prompt "Thread stack size"
depends on LSM6DSL && LSM6DSL_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
config LSM6DSL_ENABLE_TEMP
bool "Enable temperature"
depends on LSM6DSL

View file

@ -327,6 +327,9 @@ static int lsm6dsl_channel_get(struct device *dev,
}
static const struct sensor_driver_api lsm6dsl_api_funcs = {
#if CONFIG_LSM6DSL_TRIGGER
.trigger_set = lsm6dsl_trigger_set,
#endif
.sample_fetch = lsm6dsl_sample_fetch,
.channel_get = lsm6dsl_channel_get,
};
@ -424,6 +427,13 @@ static int lsm6dsl_init(struct device *dev)
lsm6dsl_i2c_init(dev);
#endif
#ifdef CONFIG_LSM6DSL_TRIGGER
if (lsm6dsl_init_interrupt(dev) < 0) {
SYS_LOG_ERR("Failed to initialize interrupt.");
return -EIO;
}
#endif
if (lsm6dsl_init_chip(dev) < 0) {
SYS_LOG_DBG("failed to initialize chip");
return -EIO;

View file

@ -11,7 +11,9 @@
#ifndef __SENSOR_LSM6DSL_H__
#define __SENSOR_LSM6DSL_H__
#include <sensor.h>
#include <zephyr/types.h>
#include <gpio.h>
#include <misc/util.h>
@ -716,11 +718,37 @@ struct lsm6dsl_data {
int temp_sample;
#endif
const struct lsm6dsl_transfer_function *hw_tf;
#ifdef CONFIG_LSM6DSL_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_LSM6DSL_TRIGGER_OWN_THREAD)
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_LSM6DSL_THREAD_STACK_SIZE);
struct k_thread thread;
struct k_sem gpio_sem;
#elif defined(CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD)
struct k_work work;
struct device *dev;
#endif
#endif /* CONFIG_LSM6DSL_TRIGGER */
};
int lsm6dsl_spi_init(struct device *dev);
int lsm6dsl_i2c_init(struct device *dev);
#ifdef CONFIG_LSM6DSL_TRIGGER
int lsm6dsl_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int lsm6dsl_init_interrupt(struct device *dev);
#endif
#define SYS_LOG_DOMAIN "LSM6DSL"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_SENSOR_LEVEL
#include <logging/sys_log.h>

View file

@ -0,0 +1,145 @@
/*
* Copyright (c) 2018 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <device.h>
#include <i2c.h>
#include <misc/__assert.h>
#include <misc/util.h>
#include <kernel.h>
#include <sensor.h>
#include "lsm6dsl.h"
int lsm6dsl_trigger_set(struct device *dev,
const struct sensor_trigger *trig,
sensor_trigger_handler_t handler)
{
struct lsm6dsl_data *drv_data = dev->driver_data;
__ASSERT_NO_MSG(trig->type == SENSOR_TRIG_DATA_READY);
gpio_pin_disable_callback(drv_data->gpio, CONFIG_LSM6DSL_GPIO_PIN_NUM);
drv_data->data_ready_handler = handler;
if (handler == NULL) {
return 0;
}
drv_data->data_ready_trigger = *trig;
gpio_pin_enable_callback(drv_data->gpio, CONFIG_LSM6DSL_GPIO_PIN_NUM);
return 0;
}
static void lsm6dsl_gpio_callback(struct device *dev,
struct gpio_callback *cb, u32_t pins)
{
struct lsm6dsl_data *drv_data =
CONTAINER_OF(cb, struct lsm6dsl_data, gpio_cb);
ARG_UNUSED(pins);
gpio_pin_disable_callback(dev, CONFIG_LSM6DSL_GPIO_PIN_NUM);
#if defined(CONFIG_LSM6DSL_TRIGGER_OWN_THREAD)
k_sem_give(&drv_data->gpio_sem);
#elif defined(CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD)
k_work_submit(&drv_data->work);
#endif
}
static void lsm6dsl_thread_cb(void *arg)
{
struct device *dev = arg;
struct lsm6dsl_data *drv_data = dev->driver_data;
if (drv_data->data_ready_handler != NULL) {
drv_data->data_ready_handler(dev,
&drv_data->data_ready_trigger);
}
gpio_pin_enable_callback(drv_data->gpio, CONFIG_LSM6DSL_GPIO_PIN_NUM);
}
#ifdef CONFIG_LSM6DSL_TRIGGER_OWN_THREAD
static void lsm6dsl_thread(int dev_ptr, int unused)
{
struct device *dev = INT_TO_POINTER(dev_ptr);
struct lsm6dsl_data *drv_data = dev->driver_data;
ARG_UNUSED(unused);
while (1) {
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
lsm6dsl_thread_cb(dev);
}
}
#endif
#ifdef CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD
static void lsm6dsl_work_cb(struct k_work *work)
{
struct lsm6dsl_data *drv_data =
CONTAINER_OF(work, struct lsm6dsl_data, work);
lsm6dsl_thread_cb(drv_data->dev);
}
#endif
int lsm6dsl_init_interrupt(struct device *dev)
{
struct lsm6dsl_data *drv_data = dev->driver_data;
/* setup data ready gpio interrupt */
drv_data->gpio = device_get_binding(CONFIG_LSM6DSL_GPIO_DEV_NAME);
if (drv_data->gpio == NULL) {
SYS_LOG_ERR("Cannot get pointer to %s device.",
CONFIG_LSM6DSL_GPIO_DEV_NAME);
return -EINVAL;
}
gpio_pin_configure(drv_data->gpio, CONFIG_LSM6DSL_GPIO_PIN_NUM,
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE |
GPIO_INT_ACTIVE_HIGH | GPIO_INT_DEBOUNCE);
gpio_init_callback(&drv_data->gpio_cb,
lsm6dsl_gpio_callback,
BIT(CONFIG_LSM6DSL_GPIO_PIN_NUM));
if (gpio_add_callback(drv_data->gpio, &drv_data->gpio_cb) < 0) {
SYS_LOG_ERR("Could not set gpio callback.");
return -EIO;
}
/* enable data-ready interrupt */
if (drv_data->hw_tf->update_reg(drv_data,
LSM6DSL_REG_INT1_CTRL,
LSM6DSL_SHIFT_INT1_CTRL_DRDY_XL |
LSM6DSL_SHIFT_INT1_CTRL_DRDY_G,
(1 << LSM6DSL_SHIFT_INT1_CTRL_DRDY_XL) |
(1 << LSM6DSL_SHIFT_INT1_CTRL_DRDY_G)) < 0) {
SYS_LOG_ERR("Could not enable data-ready interrupt.");
return -EIO;
}
#if defined(CONFIG_LSM6DSL_TRIGGER_OWN_THREAD)
k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
k_thread_create(&drv_data->thread, drv_data->thread_stack,
CONFIG_LSM6DSL_THREAD_STACK_SIZE,
(k_thread_entry_t)lsm6dsl_thread, POINTER_TO_INT(dev),
0, NULL, K_PRIO_COOP(CONFIG_LSM6DSL_THREAD_PRIORITY),
0, 0);
#elif defined(CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD)
drv_data->work.handler = lsm6dsl_work_cb;
drv_data->dev = dev;
#endif
gpio_pin_enable_callback(drv_data->gpio, CONFIG_LSM6DSL_GPIO_PIN_NUM);
return 0;
}