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 #ifdef CONFIG_PM_DEVICE
24 enum pm_device_state state;
25
26 (void)pm_device_state_get(dev, &state);
27 if (state != PM_DEVICE_STATE_ACTIVE) {
28 return;
29 }
30 #endif
31
32 if (data->handler_drdy_gyr) {
33 data->handler_drdy_gyr(dev, data->drdy_trig_gyr);
34 }
35 }
36
bmi08x_handle_interrupts_gyr(void * arg)37 static void bmi08x_handle_interrupts_gyr(void *arg)
38 {
39 const struct device *dev = (const struct device *)arg;
40
41 bmi08x_handle_drdy_gyr(dev);
42 }
43
44 #ifdef CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD
bmi08x_gyr_thread_main(void * arg1,void * unused1,void * unused2)45 static void bmi08x_gyr_thread_main(void *arg1, void *unused1, void *unused2)
46 {
47 k_thread_name_set(NULL, "bmi08x_gyr_trig");
48
49 ARG_UNUSED(unused1);
50 ARG_UNUSED(unused2);
51
52 const struct device *dev = (const struct device *)arg1;
53 struct bmi08x_gyro_data *data = dev->data;
54
55 while (1) {
56 k_sem_take(&data->sem, K_FOREVER);
57 bmi08x_handle_interrupts_gyr((void *)dev);
58 }
59 }
60 #endif
61
62 #ifdef CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD
bmi08x_gyr_work_handler(struct k_work * work)63 static void bmi08x_gyr_work_handler(struct k_work *work)
64 {
65 struct bmi08x_gyro_data *data = CONTAINER_OF(work, struct bmi08x_gyro_data, work);
66
67 bmi08x_handle_interrupts_gyr((void *)data->dev);
68 }
69 #endif
70
bmi08x_gyr_gpio_callback(const struct device * port,struct gpio_callback * cb,uint32_t pin)71 static void bmi08x_gyr_gpio_callback(const struct device *port, struct gpio_callback *cb,
72 uint32_t pin)
73 {
74 struct bmi08x_gyro_data *data = CONTAINER_OF(cb, struct bmi08x_gyro_data, gpio_cb);
75
76 ARG_UNUSED(port);
77 ARG_UNUSED(pin);
78
79 #if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD)
80 k_sem_give(&data->sem);
81 #elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD)
82 k_work_submit(&data->work);
83 #endif
84 }
85
bmi08x_trigger_set_gyr(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)86 int bmi08x_trigger_set_gyr(const struct device *dev, const struct sensor_trigger *trig,
87 sensor_trigger_handler_t handler)
88 {
89 struct bmi08x_gyro_data *data = dev->data;
90
91 if ((trig->chan == SENSOR_CHAN_GYRO_XYZ) && (trig->type == SENSOR_TRIG_DATA_READY)) {
92 data->handler_drdy_gyr = handler;
93 data->drdy_trig_gyr = trig;
94 return 0;
95 }
96
97 return -ENOTSUP;
98 }
99
bmi08x_gyr_trigger_mode_init(const struct device * dev)100 int bmi08x_gyr_trigger_mode_init(const struct device *dev)
101 {
102 struct bmi08x_gyro_data *data = dev->data;
103 const struct bmi08x_gyro_config *cfg = dev->config;
104 int ret;
105
106 if (!gpio_is_ready_dt(&cfg->int_gpio)) {
107 LOG_ERR("GPIO device not ready");
108 return -ENODEV;
109 }
110
111 #if defined(CONFIG_BMI08X_GYRO_TRIGGER_OWN_THREAD)
112 k_sem_init(&data->sem, 0, K_SEM_MAX_LIMIT);
113
114 k_thread_create(&data->thread, data->thread_stack,
115 CONFIG_BMI08X_GYRO_THREAD_STACK_SIZE, bmi08x_gyr_thread_main, (void *)dev,
116 NULL, NULL, K_PRIO_COOP(CONFIG_BMI08X_GYRO_THREAD_PRIORITY), 0, K_NO_WAIT);
117 #elif defined(CONFIG_BMI08X_GYRO_TRIGGER_GLOBAL_THREAD)
118 data->work.handler = bmi08x_gyr_work_handler;
119 data->dev = dev;
120 #endif
121
122 gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INPUT);
123
124 gpio_init_callback(&data->gpio_cb, bmi08x_gyr_gpio_callback, BIT(cfg->int_gpio.pin));
125
126 ret = gpio_add_callback(cfg->int_gpio.port, &data->gpio_cb);
127
128 if (ret < 0) {
129 LOG_ERR("Failed to set gpio callback.");
130 return ret;
131 }
132 gpio_pin_interrupt_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
133
134 return ret;
135 }
136