1 /* Bosch BMG160 gyro driver, trigger implementation
2 *
3 * Copyright (c) 2016 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Datasheet:
8 * http://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMG160-DS000-09.pdf
9 */
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/drivers/sensor.h>
13
14 #include "bmg160.h"
15
16 extern struct bmg160_device_data bmg160_data;
17
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_DECLARE(BMG160, CONFIG_SENSOR_LOG_LEVEL);
20
setup_int(const struct device * dev,bool enable)21 static inline int setup_int(const struct device *dev,
22 bool enable)
23 {
24 const struct bmg160_device_config *cfg = dev->config;
25
26 return gpio_pin_interrupt_configure_dt(&cfg->int_gpio,
27 enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE);
28 }
29
bmg160_gpio_callback(const struct device * port,struct gpio_callback * cb,uint32_t pin)30 static void bmg160_gpio_callback(const struct device *port,
31 struct gpio_callback *cb,
32 uint32_t pin)
33 {
34 struct bmg160_device_data *bmg160 =
35 CONTAINER_OF(cb, struct bmg160_device_data, gpio_cb);
36
37 ARG_UNUSED(port);
38 ARG_UNUSED(pin);
39
40 #if defined(CONFIG_BMG160_TRIGGER_OWN_THREAD)
41 k_sem_give(&bmg160->trig_sem);
42 #elif defined(CONFIG_BMG160_TRIGGER_GLOBAL_THREAD)
43 k_work_submit(&bmg160->work);
44 #endif
45 }
46
bmg160_anymotion_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)47 static int bmg160_anymotion_set(const struct device *dev,
48 const struct sensor_trigger *trig,
49 sensor_trigger_handler_t handler)
50 {
51 struct bmg160_device_data *bmg160 = dev->data;
52 uint8_t anymotion_en = 0U;
53
54 if (handler) {
55 anymotion_en = BMG160_ANY_EN_X |
56 BMG160_ANY_EN_Y |
57 BMG160_ANY_EN_Z;
58 }
59
60 if (bmg160_update_byte(dev, BMG160_REG_ANY_EN,
61 BMG160_ANY_EN_MASK, anymotion_en) < 0) {
62 return -EIO;
63 }
64
65 bmg160->anymotion_handler = handler;
66 bmg160->anymotion_trig = trig;
67
68 return 0;
69 }
70
bmg160_drdy_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)71 static int bmg160_drdy_set(const struct device *dev,
72 const struct sensor_trigger *trig,
73 sensor_trigger_handler_t handler)
74 {
75 struct bmg160_device_data *bmg160 = dev->data;
76
77 if (bmg160_update_byte(dev, BMG160_REG_INT_EN0,
78 BMG160_DATA_EN,
79 handler ? BMG160_DATA_EN : 0) < 0) {
80 return -EIO;
81 }
82
83 bmg160->drdy_handler = handler;
84 bmg160->drdy_trig = trig;
85
86 return 0;
87 }
88
bmg160_slope_config(const struct device * dev,enum sensor_attribute attr,const struct sensor_value * val)89 int bmg160_slope_config(const struct device *dev, enum sensor_attribute attr,
90 const struct sensor_value *val)
91 {
92 struct bmg160_device_data *bmg160 = dev->data;
93
94 if (attr == SENSOR_ATTR_SLOPE_TH) {
95 uint16_t any_th_dps, range_dps;
96 uint8_t any_th_reg_val;
97
98 any_th_dps = sensor_rad_to_degrees(val);
99 range_dps = BMG160_SCALE_TO_RANGE(bmg160->scale);
100 any_th_reg_val = any_th_dps * 2000U / range_dps;
101
102 /* the maximum slope depends on selected range */
103 if (any_th_dps > range_dps / 16U) {
104 return -ENOTSUP;
105 }
106
107 return bmg160_write_byte(dev, BMG160_REG_THRES,
108 any_th_dps & BMG160_THRES_MASK);
109 } else if (attr == SENSOR_ATTR_SLOPE_DUR) {
110 /* slope duration can be 4, 8, 12 or 16 samples */
111 if (val->val1 != 4 && val->val1 != 8 &&
112 val->val1 != 12 && val->val1 != 16) {
113 return -ENOTSUP;
114 }
115
116 return bmg160_write_byte(dev, BMG160_REG_ANY_EN,
117 (val->val1 << BMG160_ANY_DURSAMPLE_POS) &
118 BMG160_ANY_DURSAMPLE_MASK);
119 }
120
121 return -ENOTSUP;
122 }
123
bmg160_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)124 int bmg160_trigger_set(const struct device *dev,
125 const struct sensor_trigger *trig,
126 sensor_trigger_handler_t handler)
127 {
128 const struct bmg160_device_config *config = dev->config;
129
130 if (!config->int_gpio.port) {
131 return -ENOTSUP;
132 }
133
134 if (trig->type == SENSOR_TRIG_DELTA) {
135 return bmg160_anymotion_set(dev, trig, handler);
136 } else if (trig->type == SENSOR_TRIG_DATA_READY) {
137 return bmg160_drdy_set(dev, trig, handler);
138 }
139
140 return -ENOTSUP;
141 }
142
bmg160_handle_anymotion_int(const struct device * dev)143 static int bmg160_handle_anymotion_int(const struct device *dev)
144 {
145 struct bmg160_device_data *bmg160 = dev->data;
146
147 if (bmg160->anymotion_handler) {
148 bmg160->anymotion_handler(dev, bmg160->anymotion_trig);
149 }
150
151 return 0;
152 }
153
bmg160_handle_dataready_int(const struct device * dev)154 static int bmg160_handle_dataready_int(const struct device *dev)
155 {
156 struct bmg160_device_data *bmg160 = dev->data;
157
158 if (bmg160->drdy_handler) {
159 bmg160->drdy_handler(dev, bmg160->drdy_trig);
160 }
161
162 return 0;
163 }
164
bmg160_handle_int(const struct device * dev)165 static void bmg160_handle_int(const struct device *dev)
166 {
167 uint8_t status_int[4];
168
169 if (bmg160_read(dev, BMG160_REG_INT_STATUS0, status_int, 4) < 0) {
170 return;
171 }
172
173 if (status_int[0] & BMG160_ANY_INT) {
174 bmg160_handle_anymotion_int(dev);
175 } else {
176 bmg160_handle_dataready_int(dev);
177 }
178 }
179
180 #ifdef CONFIG_BMG160_TRIGGER_OWN_THREAD
181 static K_KERNEL_STACK_DEFINE(bmg160_thread_stack, CONFIG_BMG160_THREAD_STACK_SIZE);
182 static struct k_thread bmg160_thread;
183
bmg160_thread_main(void * p1,void * p2,void * p3)184 static void bmg160_thread_main(void *p1, void *p2, void *p3)
185 {
186 ARG_UNUSED(p2);
187 ARG_UNUSED(p3);
188
189 struct bmg160_device_data *bmg160 = p1;
190
191 while (true) {
192 k_sem_take(&bmg160->trig_sem, K_FOREVER);
193
194 bmg160_handle_int(bmg160->dev);
195 }
196 }
197 #endif
198
199 #ifdef CONFIG_BMG160_TRIGGER_GLOBAL_THREAD
bmg160_work_cb(struct k_work * work)200 static void bmg160_work_cb(struct k_work *work)
201 {
202 struct bmg160_device_data *bmg160 =
203 CONTAINER_OF(work, struct bmg160_device_data, work);
204
205 bmg160_handle_int(bmg160->dev);
206 }
207 #endif
208
bmg160_trigger_init(const struct device * dev)209 int bmg160_trigger_init(const struct device *dev)
210 {
211 const struct bmg160_device_config *cfg = dev->config;
212 struct bmg160_device_data *bmg160 = dev->data;
213 int ret;
214
215 /* set INT1 pin to: push-pull, active low */
216 if (bmg160_write_byte(dev, BMG160_REG_INT_EN1, 0) < 0) {
217 LOG_DBG("Failed to select interrupt pins type.");
218 return -EIO;
219 }
220
221 /* set interrupt mode to non-latched */
222 if (bmg160_write_byte(dev, BMG160_REG_INT_RST_LATCH, 0) < 0) {
223 LOG_DBG("Failed to set the interrupt mode.");
224 return -EIO;
225 }
226
227 /* map anymotion and high rate interrupts to INT1 pin */
228 if (bmg160_write_byte(dev, BMG160_REG_INT_MAP0,
229 BMG160_INT1_ANY | BMG160_INT1_HIGH) < 0) {
230 LOG_DBG("Unable to map interrupts.");
231 return -EIO;
232 }
233
234 /* map data ready, FIFO and FastOffset interrupts to INT1 pin */
235 if (bmg160_write_byte(dev, BMG160_REG_INT_MAP1,
236 BMG160_INT1_DATA | BMG160_INT1_FIFO |
237 BMG160_INT1_FAST_OFFSET) < 0) {
238 LOG_DBG("Unable to map interrupts.");
239 return -EIO;
240 }
241
242 if (!gpio_is_ready_dt(&cfg->int_gpio)) {
243 LOG_ERR("GPIO device not ready");
244 return -ENODEV;
245 }
246
247 bmg160->dev = dev;
248
249 #if defined(CONFIG_BMG160_TRIGGER_OWN_THREAD)
250 k_sem_init(&bmg160->trig_sem, 0, K_SEM_MAX_LIMIT);
251 k_thread_create(&bmg160_thread, bmg160_thread_stack,
252 CONFIG_BMG160_THREAD_STACK_SIZE,
253 bmg160_thread_main,
254 bmg160, NULL, NULL,
255 K_PRIO_COOP(CONFIG_BMG160_THREAD_PRIORITY), 0,
256 K_NO_WAIT);
257
258 #elif defined(CONFIG_BMG160_TRIGGER_GLOBAL_THREAD)
259 bmg160->work.handler = bmg160_work_cb;
260 #endif
261
262 ret = gpio_pin_configure_dt(&cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
263 if (ret < 0) {
264 return ret;
265 }
266
267 gpio_init_callback(&bmg160->gpio_cb, bmg160_gpio_callback,
268 BIT(cfg->int_gpio.pin));
269
270 ret = gpio_add_callback(cfg->int_gpio.port, &bmg160->gpio_cb);
271 if (ret < 0) {
272 return ret;
273 }
274
275 return setup_int(dev, true);
276 }
277