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