Skip to content

Commit b9355d8

Browse files
drivers: sensor: st: Add triggered mode for lsm6dsr
Add support for triggered measurement mode. Triggers can be passed to the application either via global work queue or a dedicated task within the driver. Origin: Original Signed-off-by: Marco Schuler <[email protected]>
1 parent 216c9aa commit b9355d8

File tree

6 files changed

+276
-10
lines changed

6 files changed

+276
-10
lines changed

drivers/sensor/st/lsm6dsr/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ zephyr_library()
55
zephyr_library_sources(lsm6dsr.c)
66
zephyr_library_sources(lsm6dsr_spi.c)
77
zephyr_library_sources(lsm6dsr_i2c.c)
8+
zephyr_library_sources_ifdef(CONFIG_LSM6DSR_TRIGGER lsm6dsr_trigger.c)

drivers/sensor/st/lsm6dsr/Kconfig

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,46 @@ menuconfig LSM6DSR
1616

1717
if LSM6DSR
1818

19+
choice LSM6DSR_TRIGGER_MODE
20+
prompt "Trigger mode"
21+
help
22+
Specify the type of triggering to be used by the driver.
23+
24+
config LSM6DSR_TRIGGER_NONE
25+
bool "No trigger"
26+
27+
config LSM6DSR_TRIGGER_GLOBAL_THREAD
28+
bool "Use global thread"
29+
depends on GPIO
30+
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSR),irq-gpios)
31+
select LSM6DSR_TRIGGER
32+
33+
config LSM6DSR_TRIGGER_OWN_THREAD
34+
bool "Use own thread"
35+
depends on GPIO
36+
depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSR),irq-gpios)
37+
select LSM6DSR_TRIGGER
38+
39+
endchoice
40+
41+
config LSM6DSR_TRIGGER
42+
bool
43+
44+
config LSM6DSR_THREAD_PRIORITY
45+
int "Thread priority"
46+
depends on LSM6DSR_TRIGGER_OWN_THREAD
47+
default 10
48+
help
49+
Priority of thread used by the driver to handle interrupts.
50+
51+
config LSM6DSR_THREAD_STACK_SIZE
52+
int "Thread stack size"
53+
depends on LSM6DSR_TRIGGER_OWN_THREAD
54+
default 1024
55+
help
56+
Stack size of thread used by the driver to handle interrupts.
57+
58+
1959
menu "Attributes"
2060

2161
config LSM6DSR_GYRO_FS

drivers/sensor/st/lsm6dsr/lsm6dsr.c

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,9 @@ static int lsm6dsr_channel_get(const struct device *dev, enum sensor_channel cha
482482

483483
static DEVICE_API(sensor, lsm6dsr_driver_api) = {
484484
.attr_set = lsm6dsr_attr_set,
485+
#if CONFIG_LSM6DSR_TRIGGER
486+
.trigger_set = lsm6dsr_trigger_set,
487+
#endif
485488
.sample_fetch = lsm6dsr_sample_fetch,
486489
.channel_get = lsm6dsr_channel_get,
487490
};
@@ -589,6 +592,14 @@ static int lsm6dsr_init(const struct device *dev)
589592
return ret;
590593
}
591594

595+
#ifdef CONFIG_LSM6DSR_TRIGGER
596+
ret = lsm6dsr_init_interrupt(dev);
597+
if (ret < 0) {
598+
LOG_ERR("Failed to initialize interrupt.");
599+
return ret;
600+
}
601+
#endif
602+
592603
return 0;
593604
}
594605

@@ -609,13 +620,19 @@ static int lsm6dsr_init(const struct device *dev)
609620
/*
610621
* Instantiation macros used when a device is on a SPI bus.
611622
*/
623+
624+
#ifdef CONFIG_LSM6DSR_TRIGGER
625+
#define LSM6DSR_CFG_IRQ(inst) .int_gpio = GPIO_DT_SPEC_INST_GET(inst, irq_gpios),
626+
#else
627+
#define LSM6DSR_CFG_IRQ(inst)
628+
#endif /* CONFIG_LSM6DSR_TRIGGER */
629+
612630
#define LSM6DSR_CONFIG_SPI(inst) \
613-
{ \
614-
.bus_init = lsm6dsr_spi_init, \
615-
.bus_cfg.spi = SPI_DT_SPEC_INST_GET( \
616-
inst, \
617-
SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA, 0), \
618-
}
631+
{.bus_init = lsm6dsr_spi_init, \
632+
.bus_cfg.spi = SPI_DT_SPEC_INST_GET( \
633+
inst, SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA, 0), \
634+
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
635+
(LSM6DSR_CFG_IRQ(inst)), ()) }
619636

620637
#define LSM6DSR_DEFINE_SPI(inst) \
621638
static struct lsm6dsr_data lsm6dsr_data_##inst; \
@@ -627,10 +644,10 @@ static int lsm6dsr_init(const struct device *dev)
627644
*/
628645

629646
#define LSM6DSR_CONFIG_I2C(inst) \
630-
{ \
631-
.bus_init = lsm6dsr_i2c_init, \
632-
.bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \
633-
}
647+
{.bus_init = lsm6dsr_i2c_init, \
648+
.bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \
649+
COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \
650+
(LSM6DSR_CFG_IRQ(inst)), ()) }
634651

635652
#define LSM6DSR_DEFINE_I2C(inst) \
636653
static struct lsm6dsr_data lsm6dsr_data_##inst; \

drivers/sensor/st/lsm6dsr/lsm6dsr.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@
3232
#define LSM6DSR_REG_WHO_AM_I 0x0F
3333
#define LSM6DSR_VAL_WHO_AM_I 0x6B
3434

35+
#define LSM6DSR_REG_INT1_CTRL 0x0D
36+
#define LSM6DSR_MASK_INT1_CTRL_FULL BIT(5)
37+
#define LSM6DSR_SHIFT_INT1_CTRL_FULL 5
38+
#define LSM6DSR_MASK_INT1_CTRL_FIFO_OVR BIT(4)
39+
#define LSM6DSR_SHIFT_INT1_CTRL_FIFO_OVR 4
40+
#define LSM6DSR_MASK_INT1_FTH BIT(3)
41+
#define LSM6DSR_SHIFT_INT1_FTH 3
42+
#define LSM6DSR_MASK_INT1_CTRL_BOOT BIT(2)
43+
#define LSM6DSR_SHIFT_INT1_CTRL_BOOT 2
44+
#define LSM6DSR_MASK_INT1_CTRL_DRDY_G BIT(1)
45+
#define LSM6DSR_SHIFT_INT1_CTRL_DRDY_G 1
46+
#define LSM6DSR_MASK_INT1_CTRL_DRDY_XL BIT(0)
47+
#define LSM6DSR_SHIFT_INT1_CTRL_DRDY_XL 0
48+
3549
#define LSM6DSR_REG_CTRL1_XL 0x10
3650
#define LSM6DSR_MASK_CTRL1_XL_ODR_XL (BIT(7) | BIT(6) | BIT(5) | BIT(4))
3751
#define LSM6DSR_SHIFT_CTRL1_XL_ODR_XL 4
@@ -148,6 +162,9 @@ union lsm6dsr_bus_cfg {
148162
struct lsm6dsr_config {
149163
int (*bus_init)(const struct device *dev);
150164
const union lsm6dsr_bus_cfg bus_cfg;
165+
#ifdef CONFIG_LSM6DSR_TRIGGER
166+
struct gpio_dt_spec int_gpio;
167+
#endif
151168
};
152169

153170
struct lsm6dsr_data;
@@ -171,9 +188,33 @@ struct lsm6dsr_data {
171188
const struct lsm6dsr_transfer_function *hw_tf;
172189
uint16_t accel_freq;
173190
uint16_t gyro_freq;
191+
192+
#ifdef CONFIG_LSM6DSR_TRIGGER
193+
const struct device *dev;
194+
struct gpio_callback gpio_cb;
195+
196+
const struct sensor_trigger *data_ready_trigger;
197+
sensor_trigger_handler_t data_ready_handler;
198+
199+
#if defined(CONFIG_LSM6DSR_TRIGGER_OWN_THREAD)
200+
K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LSM6DSR_THREAD_STACK_SIZE);
201+
struct k_thread thread;
202+
struct k_sem gpio_sem;
203+
#elif defined(CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD)
204+
struct k_work work;
205+
#endif
206+
207+
#endif /* CONFIG_LSM6DSR_TRIGGER */
174208
};
175209

176210
int lsm6dsr_spi_init(const struct device *dev);
177211
int lsm6dsr_i2c_init(const struct device *dev);
178212

213+
#ifdef CONFIG_LSM6DSR_TRIGGER
214+
int lsm6dsr_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
215+
sensor_trigger_handler_t handler);
216+
217+
int lsm6dsr_init_interrupt(const struct device *dev);
218+
#endif
219+
179220
#endif /* ZEPHYR_DRIVERS_SENSOR_LSM6DSR_LSM6DSR_H_ */
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright (c) 2018 STMicroelectronics
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT st_lsm6dsr
8+
9+
#include <zephyr/device.h>
10+
#include <zephyr/drivers/i2c.h>
11+
#include <zephyr/sys/__assert.h>
12+
#include <zephyr/sys/util.h>
13+
#include <zephyr/kernel.h>
14+
#include <zephyr/drivers/sensor.h>
15+
#include <zephyr/logging/log.h>
16+
#include "lsm6dsr.h"
17+
18+
LOG_MODULE_DECLARE(LSM6DSR, CONFIG_SENSOR_LOG_LEVEL);
19+
20+
static inline void setup_irq(const struct device *dev, bool enable)
21+
{
22+
const struct lsm6dsr_config *config = dev->config;
23+
24+
unsigned int flags = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
25+
26+
gpio_pin_interrupt_configure_dt(&config->int_gpio, flags);
27+
}
28+
29+
static inline void handle_irq(const struct device *dev)
30+
{
31+
struct lsm6dsr_data *drv_data = dev->data;
32+
33+
setup_irq(dev, false);
34+
35+
#if defined(CONFIG_LSM6DSR_TRIGGER_OWN_THREAD)
36+
k_sem_give(&drv_data->gpio_sem);
37+
#elif defined(CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD)
38+
k_work_submit(&drv_data->work);
39+
#endif
40+
}
41+
42+
int lsm6dsr_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
43+
sensor_trigger_handler_t handler)
44+
{
45+
const struct lsm6dsr_config *config = dev->config;
46+
struct lsm6dsr_data *drv_data = dev->data;
47+
48+
__ASSERT_NO_MSG(trig->type == SENSOR_TRIG_DATA_READY);
49+
50+
/* If irq_gpio is not configured in DT just return error */
51+
if (!config->int_gpio.port) {
52+
LOG_ERR("triggers not supported");
53+
return -ENOTSUP;
54+
}
55+
56+
setup_irq(dev, false);
57+
58+
drv_data->data_ready_handler = handler;
59+
if (handler == NULL) {
60+
return 0;
61+
}
62+
63+
drv_data->data_ready_trigger = trig;
64+
65+
setup_irq(dev, true);
66+
if (gpio_pin_get_dt(&config->int_gpio) > 0) {
67+
handle_irq(dev);
68+
}
69+
70+
return 0;
71+
}
72+
73+
static void lsm6dsr_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
74+
{
75+
struct lsm6dsr_data *drv_data = CONTAINER_OF(cb, struct lsm6dsr_data, gpio_cb);
76+
77+
ARG_UNUSED(pins);
78+
79+
handle_irq(drv_data->dev);
80+
}
81+
82+
static void lsm6dsr_thread_cb(const struct device *dev)
83+
{
84+
struct lsm6dsr_data *drv_data = dev->data;
85+
86+
if (drv_data->data_ready_handler != NULL) {
87+
drv_data->data_ready_handler(dev, drv_data->data_ready_trigger);
88+
}
89+
90+
setup_irq(dev, true);
91+
}
92+
93+
#ifdef CONFIG_LSM6DSR_TRIGGER_OWN_THREAD
94+
static void lsm6dsr_thread(void *p1, void *p2, void *p3)
95+
{
96+
ARG_UNUSED(p2);
97+
ARG_UNUSED(p3);
98+
99+
const struct device *dev = p1;
100+
struct lsm6dsr_data *drv_data = dev->data;
101+
102+
while (1) {
103+
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
104+
lsm6dsr_thread_cb(dev);
105+
}
106+
}
107+
#endif
108+
109+
#ifdef CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD
110+
static void lsm6dsr_work_cb(struct k_work *work)
111+
{
112+
struct lsm6dsr_data *drv_data = CONTAINER_OF(work, struct lsm6dsr_data, work);
113+
114+
lsm6dsr_thread_cb(drv_data->dev);
115+
}
116+
#endif
117+
118+
int lsm6dsr_init_interrupt(const struct device *dev)
119+
{
120+
const struct lsm6dsr_config *config = dev->config;
121+
struct lsm6dsr_data *drv_data = dev->data;
122+
123+
if (!gpio_is_ready_dt(&config->int_gpio)) {
124+
LOG_ERR("GPIO device not ready");
125+
return -ENODEV;
126+
}
127+
128+
gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
129+
130+
gpio_init_callback(&drv_data->gpio_cb, lsm6dsr_gpio_callback, BIT(config->int_gpio.pin));
131+
132+
if (gpio_add_callback(config->int_gpio.port, &drv_data->gpio_cb) < 0) {
133+
LOG_ERR("Could not set gpio callback.");
134+
return -EIO;
135+
}
136+
137+
/* enable data-ready interrupt */
138+
if (drv_data->hw_tf->update_reg(
139+
dev, LSM6DSR_REG_INT1_CTRL,
140+
LSM6DSR_MASK_INT1_CTRL_DRDY_XL | LSM6DSR_MASK_INT1_CTRL_DRDY_G,
141+
BIT(LSM6DSR_SHIFT_INT1_CTRL_DRDY_XL) | BIT(LSM6DSR_SHIFT_INT1_CTRL_DRDY_G)) <
142+
0) {
143+
LOG_ERR("Could not enable data-ready interrupt.");
144+
return -EIO;
145+
}
146+
147+
drv_data->dev = dev;
148+
149+
#if defined(CONFIG_LSM6DSR_TRIGGER_OWN_THREAD)
150+
k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT);
151+
152+
k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_LSM6DSR_THREAD_STACK_SIZE,
153+
lsm6dsr_thread, (void *)dev, NULL, NULL,
154+
K_PRIO_COOP(CONFIG_LSM6DSR_THREAD_PRIORITY), 0, K_NO_WAIT);
155+
#elif defined(CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD)
156+
drv_data->work.handler = lsm6dsr_work_cb;
157+
#endif
158+
159+
setup_irq(dev, true);
160+
161+
return 0;
162+
}

dts/bindings/sensor/st,lsm6dsr-common.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@
22
# SPDX-License-Identifier: Apache-2.0
33

44
include: sensor-device.yaml
5+
6+
properties:
7+
irq-gpios:
8+
# This signal is active high when produced by the sensor
9+
type: phandle-array

0 commit comments

Comments
 (0)