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(struct bmi270_data * data)88 static void bmi270_thread(struct bmi270_data *data)
89 {
90 while (1) {
91 k_sem_take(&data->trig_sem, K_FOREVER);
92 bmi270_thread_cb(data->dev);
93 }
94 }
95 #endif
96
97 #ifdef CONFIG_BMI270_TRIGGER_GLOBAL_THREAD
bmi270_trig_work_cb(struct k_work * work)98 static void bmi270_trig_work_cb(struct k_work *work)
99 {
100 struct bmi270_data *data =
101 CONTAINER_OF(work, struct bmi270_data, trig_work);
102
103 bmi270_thread_cb(data->dev);
104 }
105 #endif
106
bmi270_feature_reg_write(const struct device * dev,const struct bmi270_feature_reg * reg,uint16_t value)107 static int bmi270_feature_reg_write(const struct device *dev,
108 const struct bmi270_feature_reg *reg,
109 uint16_t value)
110 {
111 int ret;
112 uint8_t feat_page = reg->page;
113
114 ret = bmi270_reg_write(dev, BMI270_REG_FEAT_PAGE, &feat_page, 1);
115 if (ret < 0) {
116 LOG_ERR("bmi270_reg_write (0x%02x) failed: %d", BMI270_REG_FEAT_PAGE, ret);
117 return ret;
118 }
119
120 LOG_DBG("feature reg[0x%02x]@%d = 0x%04x", reg->addr, reg->page, value);
121
122 ret = bmi270_reg_write(dev, reg->addr, (uint8_t *)&value, 2);
123 if (ret < 0) {
124 LOG_ERR("bmi270_reg_write (0x%02x) failed: %d", reg->addr, ret);
125 return ret;
126 }
127
128 return 0;
129 }
130
bmi270_init_int_pin(const struct gpio_dt_spec * pin,struct gpio_callback * pin_cb,gpio_callback_handler_t handler)131 static int bmi270_init_int_pin(const struct gpio_dt_spec *pin,
132 struct gpio_callback *pin_cb,
133 gpio_callback_handler_t handler)
134 {
135 int ret;
136
137 if (!pin->port) {
138 return 0;
139 }
140
141 if (!device_is_ready(pin->port)) {
142 LOG_DBG("%s not ready", pin->port->name);
143 return -ENODEV;
144 }
145
146 gpio_init_callback(pin_cb, handler, BIT(pin->pin));
147
148 ret = gpio_pin_configure_dt(pin, GPIO_INPUT);
149 if (ret) {
150 return ret;
151 }
152
153 ret = gpio_pin_interrupt_configure_dt(pin, GPIO_INT_EDGE_TO_ACTIVE);
154 if (ret) {
155 return ret;
156 }
157
158 ret = gpio_add_callback(pin->port, pin_cb);
159 if (ret) {
160 return ret;
161 }
162
163 return 0;
164 }
165
166
bmi270_init_interrupts(const struct device * dev)167 int bmi270_init_interrupts(const struct device *dev)
168 {
169 const struct bmi270_config *cfg = dev->config;
170 struct bmi270_data *data = dev->data;
171 int ret;
172
173 #if CONFIG_BMI270_TRIGGER_OWN_THREAD
174 k_sem_init(&data->trig_sem, 0, 1);
175 k_thread_create(&data->thread, data->thread_stack, CONFIG_BMI270_THREAD_STACK_SIZE,
176 (k_thread_entry_t)bmi270_thread, data, NULL, NULL,
177 K_PRIO_COOP(CONFIG_BMI270_THREAD_PRIORITY), 0, K_NO_WAIT);
178 #elif CONFIG_BMI270_TRIGGER_GLOBAL_THREAD
179 k_work_init(&data->trig_work, bmi270_trig_work_cb);
180 #endif
181
182 ret = bmi270_init_int_pin(&cfg->int1, &data->int1_cb,
183 bmi270_int1_callback);
184 if (ret) {
185 LOG_ERR("Failed to initialize INT1");
186 return -EINVAL;
187 }
188
189 ret = bmi270_init_int_pin(&cfg->int2, &data->int2_cb,
190 bmi270_int2_callback);
191 if (ret) {
192 LOG_ERR("Failed to initialize INT2");
193 return -EINVAL;
194 }
195
196 if (cfg->int1.port) {
197 uint8_t int1_io_ctrl = BMI270_INT_IO_CTRL_OUTPUT_EN;
198
199 ret = bmi270_reg_write(dev, BMI270_REG_INT1_IO_CTRL, &int1_io_ctrl, 1);
200 if (ret < 0) {
201 LOG_ERR("failed configuring INT1_IO_CTRL (%d)", ret);
202 return ret;
203 }
204 }
205
206 if (cfg->int2.port) {
207 uint8_t int2_io_ctrl = BMI270_INT_IO_CTRL_OUTPUT_EN;
208
209 ret = bmi270_reg_write(dev, BMI270_REG_INT2_IO_CTRL, &int2_io_ctrl, 1);
210 if (ret < 0) {
211 LOG_ERR("failed configuring INT2_IO_CTRL (%d)", ret);
212 return ret;
213 }
214 }
215
216 return 0;
217 }
218
bmi270_anymo_config(const struct device * dev,bool enable)219 static int bmi270_anymo_config(const struct device *dev, bool enable)
220 {
221 const struct bmi270_config *cfg = dev->config;
222 struct bmi270_data *data = dev->data;
223 uint16_t anymo_2;
224 int ret;
225
226 if (enable) {
227 ret = bmi270_feature_reg_write(dev, cfg->feature->anymo_1,
228 data->anymo_1);
229 if (ret < 0) {
230 return ret;
231 }
232 }
233
234 anymo_2 = data->anymo_2;
235 if (enable) {
236 anymo_2 |= BMI270_ANYMO_2_ENABLE;
237 }
238
239 ret = bmi270_feature_reg_write(dev, cfg->feature->anymo_2, anymo_2);
240 if (ret < 0) {
241 return ret;
242 }
243
244 uint8_t int1_map_feat = 0;
245
246 if (enable) {
247 int1_map_feat |= BMI270_INT_MAP_ANY_MOTION;
248 }
249
250 ret = bmi270_reg_write(dev, BMI270_REG_INT1_MAP_FEAT, &int1_map_feat, 1);
251 if (ret < 0) {
252 LOG_ERR("failed configuring INT1_MAP_FEAT (%d)", ret);
253 return ret;
254 }
255
256 return 0;
257 }
258
bmi270_drdy_config(const struct device * dev,bool enable)259 static int bmi270_drdy_config(const struct device *dev, bool enable)
260 {
261 int ret;
262
263 uint8_t int_map_data = 0;
264
265 if (enable) {
266 int_map_data |= BMI270_INT_MAP_DATA_DRDY_INT2;
267 }
268
269 ret = bmi270_reg_write(dev, BMI270_REG_INT_MAP_DATA, &int_map_data, 1);
270 if (ret < 0) {
271 LOG_ERR("failed configuring INT_MAP_DATA (%d)", ret);
272 return ret;
273 }
274
275 return 0;
276 }
277
bmi270_trigger_set(const struct device * dev,const struct sensor_trigger * trig,sensor_trigger_handler_t handler)278 int bmi270_trigger_set(const struct device *dev,
279 const struct sensor_trigger *trig,
280 sensor_trigger_handler_t handler)
281 {
282 struct bmi270_data *data = dev->data;
283 const struct bmi270_config *cfg = dev->config;
284
285 switch (trig->type) {
286 case SENSOR_TRIG_MOTION:
287 if (!cfg->int1.port) {
288 return -ENOTSUP;
289 }
290
291 k_mutex_lock(&data->trigger_mutex, K_FOREVER);
292 data->motion_handler = handler;
293 data->motion_trigger = trig;
294 k_mutex_unlock(&data->trigger_mutex);
295 return bmi270_anymo_config(dev, handler != NULL);
296
297 case SENSOR_TRIG_DATA_READY:
298 if (!cfg->int2.port) {
299 return -ENOTSUP;
300 }
301
302 k_mutex_lock(&data->trigger_mutex, K_FOREVER);
303 data->drdy_handler = handler;
304 data->drdy_trigger = trig;
305 k_mutex_unlock(&data->trigger_mutex);
306 return bmi270_drdy_config(dev, handler != NULL);
307 default:
308 return -ENOTSUP;
309 }
310
311 return 0;
312 }
313