1 /*
2 * Copyright (c) 2023 Elektronikutvecklingsbyrån EUB AB
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/device.h>
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(bmi270);
10
11 #include "bmi270.h"
12
13 enum {
14 INT_FLAGS_INT1,
15 INT_FLAGS_INT2,
16 };
17
bmi270_raise_int_flag(const struct device * dev,int bit)18 static void bmi270_raise_int_flag(const struct device *dev, int bit)
19 {
20 struct bmi270_data *data = dev->data;
21
22 atomic_set_bit(&data->int_flags, bit);
23
24 #if defined(CONFIG_BMI270_TRIGGER_OWN_THREAD)
25 k_sem_give(&data->trig_sem);
26 #elif defined(CONFIG_BMI270_TRIGGER_GLOBAL_THREAD)
27 k_work_submit(&data->trig_work);
28 #endif
29 }
30
bmi270_int1_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)31 static void bmi270_int1_callback(const struct device *dev,
32 struct gpio_callback *cb, uint32_t pins)
33 {
34 struct bmi270_data *data =
35 CONTAINER_OF(cb, struct bmi270_data, int1_cb);
36 bmi270_raise_int_flag(data->dev, INT_FLAGS_INT1);
37 }
38
bmi270_int2_callback(const struct device * dev,struct gpio_callback * cb,uint32_t pins)39 static void bmi270_int2_callback(const struct device *dev,
40 struct gpio_callback *cb, uint32_t pins)
41 {
42 struct bmi270_data *data =
43 CONTAINER_OF(cb, struct bmi270_data, int2_cb);
44 bmi270_raise_int_flag(data->dev, INT_FLAGS_INT2);
45 }
46
47
bmi270_thread_cb(const struct device * dev)48 static void bmi270_thread_cb(const struct device *dev)
49 {
50 struct bmi270_data *data = dev->data;
51 int ret;
52
53 /* INT1 is used for feature interrupts */
54 if (atomic_test_and_clear_bit(&data->int_flags, INT_FLAGS_INT1)) {
55 uint16_t int_status;
56
57 ret = bmi270_reg_read(dev, BMI270_REG_INT_STATUS_0,
58 (uint8_t *)&int_status, sizeof(int_status));
59 if (ret < 0) {
60 LOG_ERR("read interrupt status returned %d", ret);
61 return;
62 }
63
64 k_mutex_lock(&data->trigger_mutex, K_FOREVER);
65
66 if (data->motion_handler != NULL) {
67 if (int_status & BMI270_INT_STATUS_ANY_MOTION) {
68 data->motion_handler(dev, data->motion_trigger);
69 }
70 }
71
72 k_mutex_unlock(&data->trigger_mutex);
73 }
74
75 /* INT2 is used for data ready interrupts */
76 if (atomic_test_and_clear_bit(&data->int_flags, INT_FLAGS_INT2)) {
77 k_mutex_lock(&data->trigger_mutex, K_FOREVER);
78
79 if (data->drdy_handler != NULL) {
80 data->drdy_handler(dev, data->drdy_trigger);
81 }
82
83 k_mutex_unlock(&data->trigger_mutex);
84 }
85 }
86
87 #ifdef CONFIG_BMI270_TRIGGER_OWN_THREAD
bmi270_thread(void * p1,void * p2,void * p3)88 static void bmi270_thread(void *p1, void *p2, void *p3)
89 {
90 ARG_UNUSED(p2);
91 ARG_UNUSED(p3);
92
93 struct bmi270_data *data = p1;
94
95 while (1) {
96 k_sem_take(&data->trig_sem, K_FOREVER);
97 bmi270_thread_cb(data->dev);
98 }
99 }
100 #endif
101
102 #ifdef CONFIG_BMI270_TRIGGER_GLOBAL_THREAD
bmi270_trig_work_cb(struct k_work * work)103 static void bmi270_trig_work_cb(struct k_work *work)
104 {
105 struct bmi270_data *data =
106 CONTAINER_OF(work, struct bmi270_data, trig_work);
107
108 bmi270_thread_cb(data->dev);
109 }
110 #endif
111
bmi270_feature_reg_write(const struct device * dev,const struct bmi270_feature_reg * reg,uint16_t value)112 static int bmi270_feature_reg_write(const struct device *dev,
113 const struct bmi270_feature_reg *reg,
114 uint16_t value)
115 {
116 int ret;
117 uint8_t feat_page = reg->page;
118
119 ret = bmi270_reg_write(dev, BMI270_REG_FEAT_PAGE, &feat_page, 1);
120 if (ret < 0) {
121 LOG_ERR("bmi270_reg_write (0x%02x) failed: %d", BMI270_REG_FEAT_PAGE, ret);
122 return ret;
123 }
124
125 LOG_DBG("feature reg[0x%02x]@%d = 0x%04x", reg->addr, reg->page, value);
126
127 ret = bmi270_reg_write(dev, reg->addr, (uint8_t *)&value, 2);
128 if (ret < 0) {
129 LOG_ERR("bmi270_reg_write (0x%02x) failed: %d", reg->addr, ret);
130 return ret;
131 }
132
133 return 0;
134 }
135
bmi270_init_int_pin(const struct gpio_dt_spec * pin,struct gpio_callback * pin_cb,gpio_callback_handler_t handler)136 static int bmi270_init_int_pin(const struct gpio_dt_spec *pin,
137 struct gpio_callback *pin_cb,
138 gpio_callback_handler_t handler)
139 {
140 int ret;
141
142 if (!pin->port) {
143 return 0;
144 }
145
146 if (!device_is_ready(pin->port)) {
147 LOG_DBG("%s not ready", pin->port->name);
148 return -ENODEV;
149 }
150
151 gpio_init_callback(pin_cb, handler, BIT(pin->pin));
152
153 ret = gpio_pin_configure_dt(pin, GPIO_INPUT);
154 if (ret) {
155 return ret;
156 }
157
158 ret = gpio_pin_interrupt_configure_dt(pin, GPIO_INT_EDGE_TO_ACTIVE);
159 if (ret) {
160 return ret;
161 }
162
163 ret = gpio_add_callback(pin->port, pin_cb);
164 if (ret) {
165 return ret;
166 }
167
168 return 0;
169 }
170
171
bmi270_init_interrupts(const struct device * dev)172 int bmi270_init_interrupts(const struct device *dev)
173 {
174 const struct bmi270_config *cfg = dev->config;
175 struct bmi270_data *data = dev->data;
176 int ret;
177
178 #if CONFIG_BMI270_TRIGGER_OWN_THREAD
179 k_sem_init(&data->trig_sem, 0, 1);
180 k_thread_create(&data->thread, data->thread_stack, CONFIG_BMI270_THREAD_STACK_SIZE,
181 bmi270_thread, data, NULL, NULL,
182 K_PRIO_COOP(CONFIG_BMI270_THREAD_PRIORITY), 0, K_NO_WAIT);
183 #elif CONFIG_BMI270_TRIGGER_GLOBAL_THREAD
184 k_work_init(&data->trig_work, bmi270_trig_work_cb);
185 #endif
186
187 ret = bmi270_init_int_pin(&cfg->int1, &data->int1_cb,
188 bmi270_int1_callback);
189 if (ret) {
190 LOG_ERR("Failed to initialize INT1");
191 return -EINVAL;
192 }
193
194 ret = bmi270_init_int_pin(&cfg->int2, &data->int2_cb,
195 bmi270_int2_callback);
196 if (ret) {
197 LOG_ERR("Failed to initialize INT2");
198 return -EINVAL;
199 }
200
201 if (cfg->int1.port) {
202 uint8_t int1_io_ctrl = BMI270_INT_IO_CTRL_OUTPUT_EN;
203
204 ret = bmi270_reg_write(dev, BMI270_REG_INT1_IO_CTRL, &int1_io_ctrl, 1);
205 if (ret < 0) {
206 LOG_ERR("failed configuring INT1_IO_CTRL (%d)", ret);
207 return ret;
208 }
209 }
210
211 if (cfg->int2.port) {
212 uint8_t int2_io_ctrl = BMI270_INT_IO_CTRL_OUTPUT_EN;
213
214 ret = bmi270_reg_write(dev, BMI270_REG_INT2_IO_CTRL, &int2_io_ctrl, 1);
215 if (ret < 0) {
216 LOG_ERR("failed configuring INT2_IO_CTRL (%d)", ret);
217 return ret;
218 }
219 }
220
221 return 0;
222 }
223
bmi270_anymo_config(const struct device * dev,bool enable)224 static int bmi270_anymo_config(const struct device *dev, bool enable)
225 {
226 const struct bmi270_config *cfg = dev->config;
227 struct bmi270_data *data = dev->data;
228 uint16_t anymo_2;
229 int ret;
230
231 if (enable) {
232 ret = bmi270_feature_reg_write(dev, cfg->feature->anymo_1,
233 data->anymo_1);
234 if (ret < 0) {
235 return ret;
236 }
237 }
238
239 anymo_2 = data->anymo_2;
240 if (enable) {
241 anymo_2 |= BMI270_ANYMO_2_ENABLE;
242 }
243
244 ret = bmi270_feature_reg_write(dev, cfg->feature->anymo_2, anymo_2);
245 if (ret < 0) {
246 return ret;
247 }
248
249 uint8_t int1_map_feat = 0;
250
251 if (enable) {
252 int1_map_feat |= BMI270_INT_MAP_ANY_MOTION;
253 }
254
255 ret = bmi270_reg_write(dev, BMI270_REG_INT1_MAP_FEAT, &int1_map_feat, 1);
256 if (ret < 0) {
257 LOG_ERR("failed configuring INT1_MAP_FEAT (%d)", ret);
258 return ret;
259 }
260
261 return 0;
262 }
263
bmi270_drdy_config(const struct device * dev,bool enable)264 static int bmi270_drdy_config(const struct device *dev, bool enable)
265 {
266 int ret;
267
268 uint8_t int_map_data = 0;
269
270 if (enable) {
271 int_map_data |= BMI270_INT_MAP_DATA_DRDY_INT2;
272 }
273
274 ret = bmi270_reg_write(dev, BMI270_REG_INT_MAP_DATA, &int_map_data, 1);
275 if (ret < 0) {
276 LOG_ERR("failed configuring INT_MAP_DATA (%d)", ret);
277 return ret;
278 }
279
280 return 0;
281 }
282
bmi270_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)283 int bmi270_trigger_set(const struct device *dev,
284 const struct sensor_trigger *trig,
285 sensor_trigger_handler_t handler)
286 {
287 struct bmi270_data *data = dev->data;
288 const struct bmi270_config *cfg = dev->config;
289
290 switch (trig->type) {
291 case SENSOR_TRIG_MOTION:
292 if (!cfg->int1.port) {
293 return -ENOTSUP;
294 }
295
296 k_mutex_lock(&data->trigger_mutex, K_FOREVER);
297 data->motion_handler = handler;
298 data->motion_trigger = trig;
299 k_mutex_unlock(&data->trigger_mutex);
300 return bmi270_anymo_config(dev, handler != NULL);
301
302 case SENSOR_TRIG_DATA_READY:
303 if (!cfg->int2.port) {
304 return -ENOTSUP;
305 }
306
307 k_mutex_lock(&data->trigger_mutex, K_FOREVER);
308 data->drdy_handler = handler;
309 data->drdy_trigger = trig;
310 k_mutex_unlock(&data->trigger_mutex);
311 return bmi270_drdy_config(dev, handler != NULL);
312 default:
313 return -ENOTSUP;
314 }
315
316 return 0;
317 }
318