1 /* Bosch BMI08X inertial measurement unit driver, trigger implementation
2 *
3 * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/drivers/sensor.h>
10 #include <zephyr/pm/device.h>
11 #include <zephyr/kernel.h>
12
13 #define DT_DRV_COMPAT bosch_bmi08x_gyro
14 #include "bmi08x.h"
15
16 #include <zephyr/logging/log.h>
17 LOG_MODULE_DECLARE(BMI08X_GYRO, CONFIG_SENSOR_LOG_LEVEL);
18
bmi08x_handle_drdy_gyr(const struct device * dev)19 static void bmi08x_handle_drdy_gyr(const struct device *dev)
20 {
21 struct bmi08x_gyro_data *data = dev->data;
22
23 if (data->handler_drdy_gyr) {
24 data->handler_drdy_gyr(dev, data->drdy_trig_gyr);
25 }
26 }
27
bmi08x_handle_interrupts_gyr(void * arg)28 static void bmi08x_handle_interrupts_gyr(void *arg)
29 {
30 const struct device *dev = (const struct device *)arg;
31
32 bmi08x_handle_drdy_gyr(dev);
33 }
34
35 #ifdef CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD
bmi08x_gyr_thread_main(void * arg1,void * unused1,void * unused2)36 static void bmi08x_gyr_thread_main(void *arg1, void *unused1, void *unused2)
37 {
38 k_thread_name_set(NULL, "bmi08x_gyr_trig");
39
40 ARG_UNUSED(unused1);
41 ARG_UNUSED(unused2);
42
43 const struct device *dev = (const struct device *)arg1;
44 struct bmi08x_gyro_data *data = dev->data;
45
46 while (1) {
47 k_sem_take(&data->sem, K_FOREVER);
48 bmi08x_handle_interrupts_gyr((void *)dev);
49 }
50 }
51 #endif
52
53 #ifdef CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD
bmi08x_gyr_work_handler(struct k_work * work)54 static void bmi08x_gyr_work_handler(struct k_work *work)
55 {
56 struct bmi08x_gyro_data *data = CONTAINER_OF(work, struct bmi08x_gyro_data, work);
57
58 bmi08x_handle_interrupts_gyr((void *)data->dev);
59 }
60 #endif
61
bmi08x_gyr_gpio_callback(const struct device * port,struct gpio_callback * cb,uint32_t pin)62 static void bmi08x_gyr_gpio_callback(const struct device *port, struct gpio_callback *cb,
63 uint32_t pin)
64 {
65 struct bmi08x_gyro_data *data = CONTAINER_OF(cb, struct bmi08x_gyro_data, gpio_cb);
66
67 ARG_UNUSED(port);
68 ARG_UNUSED(pin);
69
70 #if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD)
71 k_sem_give(&data->sem);
72 #elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD)
73 k_work_submit(&data->work);
74 #endif
75 }
76
bmi08x_trigger_set_gyr(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)77 int bmi08x_trigger_set_gyr(const struct device *dev, const struct sensor_trigger *trig,
78 sensor_trigger_handler_t handler)
79 {
80 struct bmi08x_gyro_data *data = dev->data;
81
82 if ((trig->chan == SENSOR_CHAN_GYRO_XYZ) && (trig->type == SENSOR_TRIG_DATA_READY)) {
83 data->drdy_trig_gyr = trig;
84 data->handler_drdy_gyr = handler;
85 return 0;
86 }
87
88 return -ENOTSUP;
89 }
90
bmi08x_gyr_trigger_mode_init(const struct device * dev)91 int bmi08x_gyr_trigger_mode_init(const struct device *dev)
92 {
93 struct bmi08x_gyro_data *data = dev->data;
94 const struct bmi08x_gyro_config *cfg = dev->config;
95 int ret;
96
97 if (!gpio_is_ready_dt(&cfg->int_gpio)) {
98 LOG_ERR("GPIO device not ready");
99 return -ENODEV;
100 }
101
102 #if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD)
103 k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
104
105 k_thread_create(&data->thread, data->thread_stack,
106 CONFIG_BMI08X_GYRO_THREAD_STACK_SIZE, bmi08x_gyr_thread_main, (void *)dev,
107 NULL, NULL, K_PRIO_COOP(CONFIG_BMI08X_GYRO_THREAD_PRIORITY), 0, K_NO_WAIT);
108 #elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD)
109 data->work.handler = bmi08x_gyr_work_handler;
110 data->dev = dev;
111 #endif
112
113 gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
114
115 gpio_init_callback(&data->gpio_cb, bmi08x_gyr_gpio_callback, BIT(cfg->int_gpio.pin));
116
117 ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
118
119 if (ret < 0) {
120 LOG_ERR("Failed to set gpio callback.");
121 return ret;
122 }
123 gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
124
125 return ret;
126 }
127