1 /* Bosch BMI08X inertial measurement unit driver
2  *
3  * Copyright (c) 2022 Meta Platforms, Inc. and its affiliates
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/drivers/sensor.h>
9 #include <zephyr/pm/device.h>
10 #include <zephyr/init.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/sys/byteorder.h>
15 
16 #define DT_DRV_COMPAT bosch_bmi08x_accel
17 #include "bmi08x.h"
18 #include "bmi08x_config_file.h"
19 
20 LOG_MODULE_REGISTER(BMI08X_ACCEL, CONFIG_SENSOR_LOG_LEVEL);
21 
22 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c)
23 
bmi08x_accel_transceive_i2c(const struct device * dev,uint8_t reg,bool write,void * data,size_t length)24 static int bmi08x_accel_transceive_i2c(const struct device *dev, uint8_t reg, bool write,
25 				       void *data, size_t length)
26 {
27 	const struct bmi08x_accel_config *bmi08x = dev->config;
28 
29 	if (!write) {
30 		return i2c_write_read_dt(&bmi08x->bus.i2c, &reg, 1, data, length);
31 	}
32 	if (length > CONFIG_BMI08X_I2C_WRITE_BURST_SIZE) {
33 		return -EINVAL;
34 	}
35 	uint8_t buf[1 + CONFIG_BMI08X_I2C_WRITE_BURST_SIZE];
36 
37 	buf[0] = reg;
38 	memcpy(&buf[1], data, length);
39 	return i2c_write_dt(&bmi08x->bus.i2c, buf, 1 + length);
40 }
41 
42 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
bmi08x_stream_transfer_write_i2c(const struct device * dev,uint16_t index,const uint8_t * stream_data,uint16_t stream_length)43 static int bmi08x_stream_transfer_write_i2c(const struct device *dev, uint16_t index,
44 					    const uint8_t *stream_data, uint16_t stream_length)
45 {
46 	uint8_t asic_msb = (uint8_t)((index / 2) >> 4);
47 	uint8_t asic_lsb = ((index / 2) & 0x0F);
48 	int ret;
49 
50 	ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5B_REG, asic_lsb);
51 	if (ret != 0) {
52 		LOG_ERR("Cannot write index");
53 		return ret;
54 	}
55 	ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5C_REG, asic_msb);
56 	if (ret != 0) {
57 		LOG_ERR("Cannot write index");
58 		return ret;
59 	}
60 	ret = bmi08x_accel_write(dev, BMI08X_ACCEL_FEATURE_CFG_REG, (uint8_t *)stream_data,
61 				 stream_length);
62 	if (ret != 0) {
63 		LOG_ERR("Cannot write configuration for accelerometer.");
64 		return ret;
65 	}
66 	return ret;
67 }
68 
bmi08x_write_config_file_i2c(const struct device * dev)69 static int bmi08x_write_config_file_i2c(const struct device *dev)
70 {
71 	const uint8_t *data = bmi08x_config_file;
72 	uint16_t length = sizeof(bmi08x_config_file);
73 	uint16_t index = 0;
74 	int ret = 0;
75 
76 	while (length != 0) {
77 		uint16_t len1 = length;
78 
79 		if (len1 > CONFIG_BMI08X_I2C_WRITE_BURST_SIZE) {
80 			len1 = CONFIG_BMI08X_I2C_WRITE_BURST_SIZE;
81 		}
82 		ret = bmi08x_stream_transfer_write_i2c(dev, index, data, len1);
83 		if (ret != 0) {
84 			return ret;
85 		}
86 		index += len1;
87 		data += len1;
88 		length -= len1;
89 	}
90 	return ret;
91 }
92 #endif
93 
bmi08x_bus_check_i2c(const union bmi08x_bus * bus)94 static int bmi08x_bus_check_i2c(const union bmi08x_bus *bus)
95 {
96 	return i2c_is_ready_dt(&bus->i2c) ? 0 : -ENODEV;
97 }
98 
99 static const struct bmi08x_accel_bus_io bmi08x_i2c_api = {.check = bmi08x_bus_check_i2c,
100 							  .transceive = bmi08x_accel_transceive_i2c,
101 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
102 							  .write_config_file =
103 								  bmi08x_write_config_file_i2c
104 #endif
105 };
106 
107 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */
108 
109 #if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi)
110 
bmi08x_accel_transceive_spi(const struct device * dev,uint8_t reg,bool write,void * data,size_t length)111 static int bmi08x_accel_transceive_spi(const struct device *dev, uint8_t reg, bool write,
112 				       void *data, size_t length)
113 {
114 	const struct bmi08x_accel_config *bmi08x = dev->config;
115 	const struct spi_buf tx_buf[2] = {{.buf = &reg, .len = 1}, {.buf = data, .len = length}};
116 	const struct spi_buf_set tx = {.buffers = tx_buf, .count = write ? 2 : 1};
117 
118 	if (!write) {
119 		uint16_t dummy;
120 		const struct spi_buf rx_buf[2] = {{.buf = &dummy, .len = 2},
121 						  {.buf = data, .len = length}};
122 		const struct spi_buf_set rx = {.buffers = rx_buf, .count = 2};
123 
124 		return spi_transceive_dt(&bmi08x->bus.spi, &tx, &rx);
125 	}
126 
127 	return spi_write_dt(&bmi08x->bus.spi, &tx);
128 }
129 
130 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
bmi08x_write_config_file_spi(const struct device * dev)131 static int bmi08x_write_config_file_spi(const struct device *dev)
132 {
133 	int ret;
134 
135 	ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5B_REG, 0);
136 	if (ret < 0) {
137 		LOG_ERR("Cannot write index");
138 		return ret;
139 	}
140 	ret = bmi08x_accel_byte_write(dev, BMI08X_ACCEL_RESERVED_5C_REG, 0);
141 	if (ret < 0) {
142 		LOG_ERR("Cannot write index");
143 		return ret;
144 	}
145 	/* write config file */
146 	ret = bmi08x_accel_write(dev, BMI08X_ACCEL_FEATURE_CFG_REG, (uint8_t *)bmi08x_config_file,
147 				 sizeof(bmi08x_config_file));
148 	if (ret < 0) {
149 		LOG_ERR("Cannot write configuration for accelerometer.");
150 		return ret;
151 	}
152 	return ret;
153 }
154 #endif
155 
bmi08x_bus_check_spi(const union bmi08x_bus * bus)156 static int bmi08x_bus_check_spi(const union bmi08x_bus *bus)
157 {
158 	return spi_is_ready_dt(&bus->spi) ? 0 : -ENODEV;
159 }
160 
bmi08x_bus_init_spi(const struct device * dev)161 static int bmi08x_bus_init_spi(const struct device *dev)
162 {
163 	uint8_t val;
164 	int ret;
165 	/* do a dummy read from 0x7F to activate SPI */
166 	ret = bmi08x_accel_byte_read(dev, 0x7F, &val);
167 	if (ret < 0) {
168 		LOG_ERR("Cannot read from 0x7F..");
169 		return ret;
170 	}
171 
172 	k_usleep(100);
173 
174 	return ret;
175 }
176 
177 static const struct bmi08x_accel_bus_io bmi08x_spi_api = {.check = bmi08x_bus_check_spi,
178 							  .bus_init = bmi08x_bus_init_spi,
179 							  .transceive = bmi08x_accel_transceive_spi,
180 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
181 							  .write_config_file =
182 								  bmi08x_write_config_file_spi
183 #endif
184 };
185 
186 #endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */
187 
bmi08x_bus_check(const struct device * dev)188 static inline int bmi08x_bus_check(const struct device *dev)
189 {
190 	const struct bmi08x_accel_config *config = dev->config;
191 
192 	return config->api->check(&config->bus);
193 }
194 
bmi08x_bus_init(const struct device * dev)195 static inline int bmi08x_bus_init(const struct device *dev)
196 {
197 	const struct bmi08x_accel_config *config = dev->config;
198 
199 	/* optional, only needed to initialize SPI according to datasheet */
200 	if (config->api->bus_init) {
201 		return config->api->bus_init(dev);
202 	}
203 	return 0;
204 }
205 
bmi08x_accel_transceive(const struct device * dev,uint8_t reg,bool write,void * data,size_t length)206 static int bmi08x_accel_transceive(const struct device *dev, uint8_t reg, bool write, void *data,
207 				   size_t length)
208 {
209 	const struct bmi08x_accel_config *config = dev->config;
210 
211 	return config->api->transceive(dev, reg, write, data, length);
212 }
213 
bmi08x_accel_read(const struct device * dev,uint8_t reg_addr,uint8_t * data,uint8_t len)214 int bmi08x_accel_read(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint8_t len)
215 {
216 	return bmi08x_accel_transceive(dev, reg_addr | BIT(7), false, data, len);
217 }
218 
bmi08x_accel_write(const struct device * dev,uint8_t reg_addr,uint8_t * data,uint16_t len)219 int bmi08x_accel_write(const struct device *dev, uint8_t reg_addr, uint8_t *data, uint16_t len)
220 {
221 	return bmi08x_accel_transceive(dev, reg_addr, true, data, len);
222 }
223 
bmi08x_accel_byte_read(const struct device * dev,uint8_t reg_addr,uint8_t * byte)224 int bmi08x_accel_byte_read(const struct device *dev, uint8_t reg_addr, uint8_t *byte)
225 {
226 	return bmi08x_accel_transceive(dev, reg_addr | BIT(7), false, byte, 1);
227 }
228 
bmi08x_accel_word_read(const struct device * dev,uint8_t reg_addr,uint16_t * word)229 static int bmi08x_accel_word_read(const struct device *dev, uint8_t reg_addr, uint16_t *word)
230 {
231 	int ret;
232 
233 	ret = bmi08x_accel_transceive(dev, reg_addr | BIT(7), false, word, 2);
234 	if (ret != 0) {
235 		return ret;
236 	}
237 
238 	*word = sys_le16_to_cpu(*word);
239 
240 	return ret;
241 }
242 
bmi08x_accel_byte_write(const struct device * dev,uint8_t reg_addr,uint8_t byte)243 int bmi08x_accel_byte_write(const struct device *dev, uint8_t reg_addr, uint8_t byte)
244 {
245 	return bmi08x_accel_transceive(dev, reg_addr & 0x7F, true, &byte, 1);
246 }
247 
bmi08x_accel_word_write(const struct device * dev,uint8_t reg_addr,uint16_t word)248 int bmi08x_accel_word_write(const struct device *dev, uint8_t reg_addr, uint16_t word)
249 {
250 	uint8_t tx_word[2] = {(uint8_t)(word & 0xff), (uint8_t)(word >> 8)};
251 
252 	return bmi08x_accel_transceive(dev, reg_addr & 0x7F, true, tx_word, 2);
253 }
254 
bmi08x_accel_reg_field_update(const struct device * dev,uint8_t reg_addr,uint8_t pos,uint8_t mask,uint8_t val)255 int bmi08x_accel_reg_field_update(const struct device *dev, uint8_t reg_addr, uint8_t pos,
256 				  uint8_t mask, uint8_t val)
257 {
258 	uint8_t old_val;
259 	int ret;
260 
261 	ret = bmi08x_accel_byte_read(dev, reg_addr, &old_val);
262 	if (ret < 0) {
263 		return ret;
264 	}
265 
266 	return bmi08x_accel_byte_write(dev, reg_addr, (old_val & ~mask) | ((val << pos) & mask));
267 }
268 
bmi08x_acc_odr_set(const struct device * dev,uint16_t freq_int,uint16_t freq_milli)269 static int bmi08x_acc_odr_set(const struct device *dev, uint16_t freq_int, uint16_t freq_milli)
270 {
271 	int odr = bmi08x_freq_to_odr_val(freq_int, freq_milli);
272 
273 	if (odr < BMI08X_ACCEL_ODR_12_5_HZ) {
274 		return odr;
275 	}
276 
277 	return bmi08x_accel_reg_field_update(dev, BMI08X_REG_ACCEL_CONF, 0, BMI08X_ACCEL_ODR_MASK,
278 					     (uint8_t)odr);
279 }
280 
281 static const struct bmi08x_range bmi085_acc_range_map[] = {
282 	{2, BMI085_ACCEL_RANGE_2G},
283 	{4, BMI085_ACCEL_RANGE_4G},
284 	{8, BMI085_ACCEL_RANGE_8G},
285 	{16, BMI085_ACCEL_RANGE_16G},
286 };
287 #define BMI085_ACC_RANGE_MAP_SIZE ARRAY_SIZE(bmi085_acc_range_map)
288 
289 static const struct bmi08x_range bmi088_acc_range_map[] = {
290 	{3, BMI088_ACCEL_RANGE_3G},
291 	{6, BMI088_ACCEL_RANGE_6G},
292 	{12, BMI088_ACCEL_RANGE_12G},
293 	{24, BMI088_ACCEL_RANGE_24G},
294 };
295 #define BMI088_ACC_RANGE_MAP_SIZE ARRAY_SIZE(bmi088_acc_range_map)
296 
bmi08x_acc_range_set(const struct device * dev,int32_t range)297 static int bmi08x_acc_range_set(const struct device *dev, int32_t range)
298 {
299 	struct bmi08x_accel_data *data = dev->data;
300 	int32_t reg_val = -1;
301 	int ret;
302 
303 	if (data->accel_chip_id == BMI085_ACCEL_CHIP_ID) {
304 		reg_val = bmi08x_range_to_reg_val(range, bmi085_acc_range_map,
305 						  BMI085_ACC_RANGE_MAP_SIZE);
306 	} else if (data->accel_chip_id == BMI088_ACCEL_CHIP_ID) {
307 		reg_val = bmi08x_range_to_reg_val(range, bmi088_acc_range_map,
308 						  BMI088_ACC_RANGE_MAP_SIZE);
309 	} else {
310 		return -ENODEV;
311 	}
312 
313 	if (reg_val < 0) {
314 		return reg_val;
315 	}
316 
317 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_RANGE, reg_val & 0xff);
318 	if (ret < 0) {
319 		return ret;
320 	}
321 
322 	data->scale = BMI08X_ACC_SCALE(range);
323 
324 	return ret;
325 }
326 
bmi08x_acc_config(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)327 static int bmi08x_acc_config(const struct device *dev, enum sensor_channel chan,
328 			     enum sensor_attribute attr, const struct sensor_value *val)
329 {
330 	switch (attr) {
331 	case SENSOR_ATTR_FULL_SCALE:
332 		return bmi08x_acc_range_set(dev, sensor_ms2_to_g(val));
333 	case SENSOR_ATTR_SAMPLING_FREQUENCY:
334 		return bmi08x_acc_odr_set(dev, val->val1, val->val2 / 1000);
335 	default:
336 		LOG_DBG("Accel attribute not supported.");
337 		return -ENOTSUP;
338 	}
339 }
340 
bmi08x_attr_set(const struct device * dev,enum sensor_channel chan,enum sensor_attribute attr,const struct sensor_value * val)341 static int bmi08x_attr_set(const struct device *dev, enum sensor_channel chan,
342 			   enum sensor_attribute attr, const struct sensor_value *val)
343 {
344 #ifdef CONFIG_PM_DEVICE
345 	enum pm_device_state state;
346 
347 	(void)pm_device_state_get(dev, &state);
348 	if (state != PM_DEVICE_STATE_ACTIVE) {
349 		return -EBUSY;
350 	}
351 #endif
352 
353 	switch (chan) {
354 	case SENSOR_CHAN_ACCEL_X:
355 	case SENSOR_CHAN_ACCEL_Y:
356 	case SENSOR_CHAN_ACCEL_Z:
357 	case SENSOR_CHAN_ACCEL_XYZ:
358 		return bmi08x_acc_config(dev, chan, attr, val);
359 	default:
360 		LOG_DBG("attr_set() not supported on this channel.");
361 		return -ENOTSUP;
362 	}
363 }
364 
bmi08x_sample_fetch(const struct device * dev,enum sensor_channel chan)365 static int bmi08x_sample_fetch(const struct device *dev, enum sensor_channel chan)
366 {
367 	struct bmi08x_accel_data *data = dev->data;
368 	size_t i;
369 	int ret;
370 
371 	if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_ACCEL_XYZ) {
372 		LOG_DBG("Unsupported sensor channel");
373 		return -ENOTSUP;
374 	}
375 
376 #ifdef CONFIG_PM_DEVICE
377 	enum pm_device_state state;
378 
379 	(void)pm_device_state_get(dev, &state);
380 	if (state != PM_DEVICE_STATE_ACTIVE) {
381 		return -EBUSY;
382 	}
383 #endif
384 
385 	pm_device_busy_set(dev);
386 
387 	ret = bmi08x_accel_read(dev, BMI08X_REG_ACCEL_X_LSB, (uint8_t *)data->acc_sample,
388 				sizeof(data->acc_sample));
389 	if (ret < 0) {
390 		pm_device_busy_clear(dev);
391 		return ret;
392 	}
393 
394 	/* convert samples to cpu endianness */
395 	for (i = 0; i < ARRAY_SIZE(data->acc_sample); i++) {
396 		data->acc_sample[i] = sys_le16_to_cpu(data->acc_sample[i]);
397 	}
398 
399 	pm_device_busy_clear(dev);
400 	return ret;
401 }
402 
bmi08x_to_fixed_point(int16_t raw_val,uint16_t scale,struct sensor_value * val)403 static void bmi08x_to_fixed_point(int16_t raw_val, uint16_t scale, struct sensor_value *val)
404 {
405 	int32_t converted_val;
406 
407 	/*
408 	 * maximum converted value we can get is: max(raw_val) * max(scale)
409 	 *	max(raw_val) = +/- 2^15
410 	 *	max(scale) = 4785
411 	 *	max(converted_val) = 156794880 which is less than 2^31
412 	 */
413 	converted_val = raw_val * scale;
414 	val->val1 = converted_val / 1000000;
415 	val->val2 = converted_val % 1000000;
416 }
417 
bmi08x_channel_convert(enum sensor_channel chan,uint16_t scale,uint16_t * raw_xyz,struct sensor_value * val)418 static void bmi08x_channel_convert(enum sensor_channel chan, uint16_t scale, uint16_t *raw_xyz,
419 				   struct sensor_value *val)
420 {
421 	int i;
422 	uint8_t ofs_start, ofs_stop;
423 
424 	switch (chan) {
425 	case SENSOR_CHAN_ACCEL_X:
426 		ofs_start = ofs_stop = 0U;
427 		break;
428 	case SENSOR_CHAN_ACCEL_Y:
429 		ofs_start = ofs_stop = 1U;
430 		break;
431 	case SENSOR_CHAN_ACCEL_Z:
432 		ofs_start = ofs_stop = 2U;
433 		break;
434 	default:
435 		ofs_start = 0U;
436 		ofs_stop = 2U;
437 		break;
438 	}
439 
440 	for (i = ofs_start; i <= ofs_stop; i++, val++) {
441 		bmi08x_to_fixed_point(raw_xyz[i], scale, val);
442 	}
443 }
444 
bmi08x_acc_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)445 static inline void bmi08x_acc_channel_get(const struct device *dev, enum sensor_channel chan,
446 					  struct sensor_value *val)
447 {
448 	struct bmi08x_accel_data *data = dev->data;
449 
450 	bmi08x_channel_convert(chan, data->scale, data->acc_sample, val);
451 }
452 
bmi08x_temp_channel_get(const struct device * dev,struct sensor_value * val)453 static int bmi08x_temp_channel_get(const struct device *dev, struct sensor_value *val)
454 {
455 	uint16_t temp_raw = 0U;
456 	int32_t temp_micro = 0;
457 	int ret;
458 
459 	ret = bmi08x_accel_word_read(dev, BMI08X_REG_TEMP_MSB, &temp_raw);
460 	if (ret < 0) {
461 		return ret;
462 	}
463 
464 	/* the scale is 1/2^5/LSB = 31250 micro degrees */
465 	temp_micro = BMI08X_TEMP_OFFSET * 1000000ULL + temp_raw * 31250ULL;
466 
467 	val->val1 = temp_micro / 1000000ULL;
468 	val->val2 = temp_micro % 1000000ULL;
469 
470 	return ret;
471 }
472 
bmi08x_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)473 static int bmi08x_channel_get(const struct device *dev, enum sensor_channel chan,
474 			      struct sensor_value *val)
475 {
476 #ifdef CONFIG_PM_DEVICE
477 	enum pm_device_state state;
478 
479 	(void)pm_device_state_get(dev, &state);
480 	if (state != PM_DEVICE_STATE_ACTIVE) {
481 		return -EBUSY;
482 	}
483 #endif
484 
485 	switch ((int16_t)chan) {
486 	case SENSOR_CHAN_ACCEL_X:
487 	case SENSOR_CHAN_ACCEL_Y:
488 	case SENSOR_CHAN_ACCEL_Z:
489 	case SENSOR_CHAN_ACCEL_XYZ:
490 		bmi08x_acc_channel_get(dev, chan, val);
491 		return 0;
492 	case SENSOR_CHAN_DIE_TEMP:
493 		return bmi08x_temp_channel_get(dev, val);
494 	default:
495 		LOG_DBG("Channel not supported.");
496 		return -ENOTSUP;
497 	}
498 
499 	return 0;
500 }
501 
502 #ifdef CONFIG_PM_DEVICE
bmi08x_accel_pm_action(const struct device * dev,enum pm_device_action action)503 static int bmi08x_accel_pm_action(const struct device *dev, enum pm_device_action action)
504 {
505 	uint8_t conf_reg_val;
506 	uint8_t ctrl_reg_val;
507 	int ret;
508 
509 	switch (action) {
510 	case PM_DEVICE_ACTION_RESUME:
511 		conf_reg_val = BMI08X_ACCEL_PM_ACTIVE;
512 		ctrl_reg_val = BMI08X_ACCEL_POWER_ENABLE;
513 		break;
514 	case PM_DEVICE_ACTION_SUSPEND:
515 		conf_reg_val = BMI08X_ACCEL_PM_SUSPEND;
516 		ctrl_reg_val = BMI08X_ACCEL_POWER_DISABLE;
517 		break;
518 	default:
519 		return -ENOTSUP;
520 	}
521 
522 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, conf_reg_val);
523 	if (ret < 0) {
524 		LOG_ERR("Failed to set conf power mode");
525 		return ret;
526 	}
527 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
528 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, ctrl_reg_val);
529 	if (ret < 0) {
530 		LOG_ERR("Failed to set ctrl power mode");
531 		return ret;
532 	}
533 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
534 
535 	return ret;
536 }
537 #endif /* CONFIG_PM_DEVICE */
538 
539 static DEVICE_API(sensor, bmi08x_api) = {
540 	.attr_set = bmi08x_attr_set,
541 #ifdef CONFIG_BMI08X_ACCEL_TRIGGER
542 	.trigger_set = bmi08x_trigger_set_acc,
543 #endif
544 	.sample_fetch = bmi08x_sample_fetch,
545 	.channel_get = bmi08x_channel_get,
546 };
547 
548 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
bmi08x_apply_sync_binary_config(const struct device * dev)549 static int bmi08x_apply_sync_binary_config(const struct device *dev)
550 {
551 	const struct bmi08x_accel_config *config = dev->config;
552 	int ret;
553 
554 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, BMI08X_ACCEL_PM_ACTIVE);
555 	if (ret < 0) {
556 		LOG_ERR("Cannot deactivate advanced power save mode.");
557 		return ret;
558 	}
559 	/* required when switching power modes */
560 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
561 
562 	/* deactivate accel, otherwise post processing can not be enabled safely */
563 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_DISABLE);
564 	if (ret < 0) {
565 		LOG_ERR("Cannot deactivate accel.");
566 		return ret;
567 	}
568 	/* required when switching power modes */
569 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
570 	/* disable config loading */
571 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INIT_CTRL,
572 				      BMI08X_ACCEL_INIT_CTRL_DISABLE);
573 	if (ret < 0) {
574 		LOG_ERR("Cannot disable config loading.");
575 		return ret;
576 	}
577 
578 	if (config->api->write_config_file(dev) != 0) {
579 		LOG_ERR("Cannot write configuration for accelerometer.");
580 		return -EIO;
581 	}
582 	k_msleep(5U);
583 
584 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INIT_CTRL,
585 				      BMI08X_ACCEL_INIT_CTRL_ENABLE);
586 	if (ret < 0) {
587 		LOG_ERR("Cannot write configuration for accelerometer.");
588 		return ret;
589 	}
590 	k_msleep(BMI08X_ASIC_INIT_TIME_MS);
591 
592 	/* check config initialization status */
593 	uint8_t val;
594 
595 	ret = bmi08x_accel_byte_read(dev, BMI08X_REG_ACCEL_INTERNAL_STAT, &val);
596 	if (ret < 0) {
597 		LOG_ERR("Cannot write configuration for accelerometer.");
598 		return ret;
599 	}
600 	if (val != 1) {
601 		LOG_ERR("Configuration stream error.");
602 		return -EIO;
603 	}
604 
605 	/* write feature configuration */
606 	uint8_t fdata[8];
607 
608 	ret = bmi08x_accel_read(dev, BMI08X_ACCEL_FEATURE_CFG_REG, fdata, 6);
609 	if (ret < 0) {
610 		LOG_ERR("Cannot read configuration for accelerometer.");
611 		return ret;
612 	}
613 	fdata[4] = config->data_sync;
614 	fdata[5] = 0x00;
615 	ret = bmi08x_accel_write(dev, BMI08X_ACCEL_FEATURE_CFG_REG, fdata, 6);
616 	if (ret < 0) {
617 		LOG_ERR("Cannot write configuration for accelerometer.");
618 		return ret;
619 	}
620 	k_msleep(100U);
621 
622 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_ENABLE);
623 	if (ret < 0) {
624 		LOG_ERR("Cannot activate accel.");
625 		return ret;
626 	}
627 	/* required when switching power modes */
628 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
629 
630 	return ret;
631 }
632 #endif
633 
bmi08x_accel_init(const struct device * dev)634 int bmi08x_accel_init(const struct device *dev)
635 {
636 	const struct bmi08x_accel_config *config = dev->config;
637 	struct bmi08x_accel_data *data = dev->data;
638 	uint8_t val = 0U;
639 	int ret;
640 
641 	ret = bmi08x_bus_check(dev);
642 	if (ret < 0) {
643 		LOG_ERR("Bus not ready for '%s'", dev->name);
644 		return ret;
645 	}
646 
647 	/* reboot the chip */
648 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_SOFTRESET, BMI08X_SOFT_RESET_CMD);
649 	if (ret < 0) {
650 		LOG_ERR("Cannot reboot chip.");
651 		return ret;
652 	}
653 
654 	k_msleep(BMI08X_ACCEL_SOFTRESET_DELAY_MS);
655 
656 	ret = bmi08x_bus_init(dev);
657 	if (ret < 0) {
658 		LOG_ERR("Can't initialize bus for %s", dev->name);
659 		return ret;
660 	}
661 
662 	ret = bmi08x_accel_byte_read(dev, BMI08X_REG_ACCEL_CHIP_ID, &val);
663 	if (ret < 0) {
664 		LOG_ERR("Failed to read chip id.");
665 		return ret;
666 	}
667 
668 	if ((val != BMI085_ACCEL_CHIP_ID) && (val != BMI088_ACCEL_CHIP_ID)) {
669 		LOG_ERR("Unsupported chip detected (0x%02x)!", val);
670 		return -ENODEV;
671 	}
672 	data->accel_chip_id = val;
673 
674 	/* enable power */
675 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, BMI08X_ACCEL_PM_ACTIVE);
676 	if (ret < 0) {
677 		LOG_ERR("Failed to set conf power mode");
678 		return ret;
679 	}
680 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
681 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_ENABLE);
682 	if (ret < 0) {
683 		LOG_ERR("Failed to set ctrl power mode");
684 		return ret;
685 	}
686 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
687 
688 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
689 	if (config->data_sync != 0) {
690 		ret = bmi08x_apply_sync_binary_config(dev);
691 		if (ret < 0) {
692 			return ret;
693 		}
694 	}
695 #endif
696 
697 	/* set accelerometer default range, divide by two because the dts contains both bmi085 and
698 	 * bmi088 valid values even values in the enum are for the bmi085 and odd values are for the
699 	 * bmi088
700 	 */
701 	ret = bmi08x_acc_range_set(dev, config->accel_fs);
702 	if (ret < 0) {
703 		LOG_ERR("Cannot set default range for accelerometer.");
704 		return ret;
705 	}
706 
707 	/* set accelerometer default odr */
708 	/* add 5 to offset from the dts enum */
709 	ret = bmi08x_accel_reg_field_update(dev, BMI08X_REG_ACCEL_CONF, 0, BMI08X_ACCEL_ODR_MASK,
710 					    config->accel_hz);
711 	if (ret < 0) {
712 		LOG_ERR("Failed to set accel's default ODR.");
713 		return ret;
714 	}
715 
716 #ifdef CONFIG_BMI08X_ACCEL_TRIGGER
717 	ret = bmi08x_acc_trigger_mode_init(dev);
718 	if (ret < 0) {
719 		LOG_ERR("Cannot set up trigger mode.");
720 		return ret;
721 	}
722 #endif
723 
724 	return ret;
725 }
726 
727 #define BMI08X_CONFIG_SPI(inst)                                                                    \
728 	.bus.spi = SPI_DT_SPEC_INST_GET(                                                           \
729 		inst, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 2),
730 
731 #define BMI08X_CONFIG_I2C(inst) .bus.i2c = I2C_DT_SPEC_INST_GET(inst),
732 
733 #define BMI08X_ACCEL_TRIG(inst)                                                                    \
734 	.int1_map = DT_INST_PROP(inst, int1_map_io), .int2_map = DT_INST_PROP(inst, int2_map_io),  \
735 	.int1_conf_io = DT_INST_PROP(inst, int1_conf_io),                                          \
736 	.int2_conf_io = DT_INST_PROP(inst, int2_conf_io),
737 
738 /* verify the bmi08x-accel is paired with a bmi08x-gyro */
739 #define BMI08X_VERIFY_DATA_SYNC(inst)                                                              \
740 	BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_INST_PHANDLE(inst, data_sync), bosch_bmi08x_gyro) != 0, \
741 		     "bmi08x-accel data sync not paired with a bmi08x-gyro")
742 /*
743  * verify data sync odr, the only valid odr combinitions with the gyro are
744  *  (gyro-hz == "400_47" and accel-hz == "400") or (gyro-hz == "1000_116" and accel-hz == "800")
745  *  or ((gyro-hz == "2000_230" or gyro-hz == "2000_532") and accel-hz == "1600")
746  */
747 #define BMI08X_GYRO_ODR(inst)  DT_ENUM_IDX(DT_INST_PHANDLE(inst, data_sync), gyro_hz)
748 #define BMI08X_ACCEL_ODR(inst) DT_INST_ENUM_IDX(inst, accel_hz)
749 /* As the dts uses strings to define the definition, ints must be used for comparision */
750 #define BMI08X_VERIFY_DATA_SYNC_ODR(inst)                                                          \
751 	BUILD_ASSERT((BMI08X_GYRO_ODR(inst) == 3 && BMI08X_ACCEL_ODR(inst) == 5) ||                \
752 			     (BMI08X_GYRO_ODR(inst) == 2 && BMI08X_ACCEL_ODR(inst) == 6) ||        \
753 			     ((BMI08X_GYRO_ODR(inst) == 1 || BMI08X_GYRO_ODR(inst) == 0) &&        \
754 			      BMI08X_ACCEL_ODR(inst) == 7),                                        \
755 		     "Invalid gyro and accel odr for data-sync")
756 /* Assert if the gyro does not have data-sync enabled */
757 #define BMI08X_VERIFY_GYRO_DATA_SYNC_EN(inst)                                                      \
758 	BUILD_ASSERT(DT_PROP(DT_INST_PHANDLE(inst, data_sync), data_sync),                         \
759 		     "paired bmi08x-gyro does not have data-sync enabled")
760 
761 /* infer the data-sync value from the gyro and accel odr 2000=1, 1000=2, 400=3, otherwise it is 0 if
762  * it is not enabled. the build_assert should prevent any invalid values when it is enabled
763  */
764 #define BMI08X_DATA_SYNC_REG_VAL(inst)                                                             \
765 	(BMI08X_GYRO_ODR(inst) == 3 && BMI08X_ACCEL_ODR(inst) == 5)   ? 3                          \
766 	: (BMI08X_GYRO_ODR(inst) == 2 && BMI08X_ACCEL_ODR(inst) == 6) ? 2                          \
767 	: ((BMI08X_GYRO_ODR(inst) == 1 || BMI08X_GYRO_ODR(inst) == 0) &&                           \
768 	   BMI08X_ACCEL_ODR(inst) == 7)                                                            \
769 		? 1                                                                                \
770 		: 0
771 
772 /* define the .data_sync in the driver config */
773 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
774 /* if another bmi08x as the data sync enabled, and one doesn't, it will get the value of 0 and won't
775  * have the config file sent over
776  */
777 #define BMI08X_DATA_SYNC_REG(inst)                                                                 \
778 	.data_sync = COND_CODE_1(BMI08X_ACCEL_DATA_SYNC_EN(inst),                                  \
779 				 (BMI08X_DATA_SYNC_REG_VAL(inst)), (0)),
780 #define BMI08X_ACCEL_TRIGGER_PINS(inst) BMI08X_ACCEL_TRIG(inst)
781 #else
782 #define BMI08X_DATA_SYNC_REG(inst)
783 #define BMI08X_ACCEL_TRIGGER_PINS(inst)                                                            \
784 	IF_ENABLED(CONFIG_BMI08X_ACCEL_TRIGGER, (BMI08X_ACCEL_TRIG(inst)))
785 #endif
786 
787 #define BMI08X_CREATE_INST(inst)                                                                   \
788                                                                                                    \
789 	IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC(inst);))              \
790 	IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC_ODR(inst);))          \
791 	IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_GYRO_DATA_SYNC_EN(inst);))      \
792                                                                                                    \
793 	static struct bmi08x_accel_data bmi08x_drv_##inst;                                         \
794                                                                                                    \
795 	static const struct bmi08x_accel_config bmi08x_config_##inst = {                           \
796 		COND_CODE_1(DT_INST_ON_BUS(inst, spi), (BMI08X_CONFIG_SPI(inst)),                  \
797 			    (BMI08X_CONFIG_I2C(inst)))                                             \
798 			.api = COND_CODE_1(DT_INST_ON_BUS(inst, spi), (&bmi08x_spi_api),           \
799 					   (&bmi08x_i2c_api)),                                     \
800 		IF_ENABLED(CONFIG_BMI08X_ACCEL_TRIGGER,                                            \
801 			   (.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),))                  \
802 			BMI08X_ACCEL_TRIGGER_PINS(inst)                                            \
803 				.accel_hz = DT_INST_ENUM_IDX(inst, accel_hz) + 5,                  \
804 		.accel_fs = DT_INST_PROP(inst, accel_fs), BMI08X_DATA_SYNC_REG(inst)};             \
805                                                                                                    \
806 	PM_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_pm_action);                                    \
807 	SENSOR_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_init, PM_DEVICE_DT_INST_GET(inst),         \
808 				     &bmi08x_drv_##inst, &bmi08x_config_##inst, POST_KERNEL,       \
809 				     CONFIG_SENSOR_INIT_PRIORITY, &bmi08x_api);
810 
811 /* Create the struct device for every status "okay" node in the devicetree. */
812 DT_INST_FOREACH_STATUS_OKAY(BMI08X_CREATE_INST)
813