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