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 	int16_t temp_int11 = 0;
458 	int ret;
459 
460 	ret = bmi08x_accel_word_read(dev, BMI08X_REG_TEMP_MSB, &temp_raw);
461 	if (!ret) {
462 		temp_int11 = (temp_raw & 0xFF) << 3;
463 	} else {
464 		LOG_ERR("Error reading BMI08X_REG_TEMP_MSB. (err %d)", ret);
465 		return ret;
466 	}
467 
468 	if (temp_raw == 0x80) {
469 		/* temperature invalid */
470 		LOG_ERR("BMI08X returned invalid temperature.");
471 		return -ENODATA;
472 	}
473 
474 	ret = bmi08x_accel_word_read(dev, BMI08X_REG_TEMP_LSB, &temp_raw);
475 	if (!ret) {
476 		temp_int11 |= (temp_raw & 0xE0) >> 5;
477 	} else {
478 		LOG_ERR("Error reading BMI08X_REG_TEMP_LSB. (err %d)", ret);
479 		return ret;
480 	}
481 	/*
482 	 * int11 type ranges in [-1024, 1023]
483 	 * the 11st bit declares +/-
484 	 * if larger than 1023, it is negative.
485 	 */
486 	if (temp_int11 > 1023) {
487 		temp_int11 -= 2048;
488 	}
489 	/* the value ranges in [-504, 496] */
490 	/* the scale is 0.125°C/LSB = 125 micro degrees */
491 	temp_micro = temp_int11 * 125 + 23 * 1000000;
492 	val->val1 = temp_micro / 1000000ULL;
493 	val->val2 = temp_micro % 1000000ULL;
494 
495 	return ret;
496 }
497 
bmi08x_channel_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)498 static int bmi08x_channel_get(const struct device *dev, enum sensor_channel chan,
499 			      struct sensor_value *val)
500 {
501 #ifdef CONFIG_PM_DEVICE
502 	enum pm_device_state state;
503 
504 	(void)pm_device_state_get(dev, &state);
505 	if (state != PM_DEVICE_STATE_ACTIVE) {
506 		return -EBUSY;
507 	}
508 #endif
509 
510 	switch ((int16_t)chan) {
511 	case SENSOR_CHAN_ACCEL_X:
512 	case SENSOR_CHAN_ACCEL_Y:
513 	case SENSOR_CHAN_ACCEL_Z:
514 	case SENSOR_CHAN_ACCEL_XYZ:
515 		bmi08x_acc_channel_get(dev, chan, val);
516 		return 0;
517 	case SENSOR_CHAN_DIE_TEMP:
518 		return bmi08x_temp_channel_get(dev, val);
519 	default:
520 		LOG_DBG("Channel not supported.");
521 		return -ENOTSUP;
522 	}
523 
524 	return 0;
525 }
526 
527 #ifdef CONFIG_PM_DEVICE
bmi08x_accel_pm_action(const struct device * dev,enum pm_device_action action)528 static int bmi08x_accel_pm_action(const struct device *dev, enum pm_device_action action)
529 {
530 	uint8_t conf_reg_val;
531 	uint8_t ctrl_reg_val;
532 	int ret;
533 
534 	switch (action) {
535 	case PM_DEVICE_ACTION_RESUME:
536 		conf_reg_val = BMI08X_ACCEL_PM_ACTIVE;
537 		ctrl_reg_val = BMI08X_ACCEL_POWER_ENABLE;
538 		break;
539 	case PM_DEVICE_ACTION_SUSPEND:
540 		conf_reg_val = BMI08X_ACCEL_PM_SUSPEND;
541 		ctrl_reg_val = BMI08X_ACCEL_POWER_DISABLE;
542 		break;
543 	default:
544 		return -ENOTSUP;
545 	}
546 
547 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, conf_reg_val);
548 	if (ret < 0) {
549 		LOG_ERR("Failed to set conf power mode");
550 		return ret;
551 	}
552 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
553 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, ctrl_reg_val);
554 	if (ret < 0) {
555 		LOG_ERR("Failed to set ctrl power mode");
556 		return ret;
557 	}
558 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
559 
560 	return ret;
561 }
562 #endif /* CONFIG_PM_DEVICE */
563 
564 static DEVICE_API(sensor, bmi08x_api) = {
565 	.attr_set = bmi08x_attr_set,
566 #ifdef CONFIG_BMI08X_ACCEL_TRIGGER
567 	.trigger_set = bmi08x_trigger_set_acc,
568 #endif
569 	.sample_fetch = bmi08x_sample_fetch,
570 	.channel_get = bmi08x_channel_get,
571 };
572 
573 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
bmi08x_apply_sync_binary_config(const struct device * dev)574 static int bmi08x_apply_sync_binary_config(const struct device *dev)
575 {
576 	const struct bmi08x_accel_config *config = dev->config;
577 	int ret;
578 
579 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, BMI08X_ACCEL_PM_ACTIVE);
580 	if (ret < 0) {
581 		LOG_ERR("Cannot deactivate advanced power save mode.");
582 		return ret;
583 	}
584 	/* required when switching power modes */
585 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
586 
587 	/* deactivate accel, otherwise post processing can not be enabled safely */
588 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_DISABLE);
589 	if (ret < 0) {
590 		LOG_ERR("Cannot deactivate accel.");
591 		return ret;
592 	}
593 	/* required when switching power modes */
594 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
595 	/* disable config loading */
596 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INIT_CTRL,
597 				      BMI08X_ACCEL_INIT_CTRL_DISABLE);
598 	if (ret < 0) {
599 		LOG_ERR("Cannot disable config loading.");
600 		return ret;
601 	}
602 
603 	if (config->api->write_config_file(dev) != 0) {
604 		LOG_ERR("Cannot write configuration for accelerometer.");
605 		return -EIO;
606 	}
607 	k_msleep(5U);
608 
609 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_INIT_CTRL,
610 				      BMI08X_ACCEL_INIT_CTRL_ENABLE);
611 	if (ret < 0) {
612 		LOG_ERR("Cannot write configuration for accelerometer.");
613 		return ret;
614 	}
615 	k_msleep(BMI08X_ASIC_INIT_TIME_MS);
616 
617 	/* check config initialization status */
618 	uint8_t val;
619 
620 	ret = bmi08x_accel_byte_read(dev, BMI08X_REG_ACCEL_INTERNAL_STAT, &val);
621 	if (ret < 0) {
622 		LOG_ERR("Cannot write configuration for accelerometer.");
623 		return ret;
624 	}
625 	if (val != 1) {
626 		LOG_ERR("Configuration stream error.");
627 		return -EIO;
628 	}
629 
630 	/* write feature configuration */
631 	uint8_t fdata[8];
632 
633 	ret = bmi08x_accel_read(dev, BMI08X_ACCEL_FEATURE_CFG_REG, fdata, 6);
634 	if (ret < 0) {
635 		LOG_ERR("Cannot read configuration for accelerometer.");
636 		return ret;
637 	}
638 	fdata[4] = config->data_sync;
639 	fdata[5] = 0x00;
640 	ret = bmi08x_accel_write(dev, BMI08X_ACCEL_FEATURE_CFG_REG, fdata, 6);
641 	if (ret < 0) {
642 		LOG_ERR("Cannot write configuration for accelerometer.");
643 		return ret;
644 	}
645 	k_msleep(100U);
646 
647 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_ENABLE);
648 	if (ret < 0) {
649 		LOG_ERR("Cannot activate accel.");
650 		return ret;
651 	}
652 	/* required when switching power modes */
653 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
654 
655 	return ret;
656 }
657 #endif
658 
bmi08x_accel_init(const struct device * dev)659 int bmi08x_accel_init(const struct device *dev)
660 {
661 	const struct bmi08x_accel_config *config = dev->config;
662 	struct bmi08x_accel_data *data = dev->data;
663 	uint8_t val = 0U;
664 	int ret;
665 
666 	ret = bmi08x_bus_check(dev);
667 	if (ret < 0) {
668 		LOG_ERR("Bus not ready for '%s'", dev->name);
669 		return ret;
670 	}
671 
672 	/* reboot the chip */
673 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_SOFTRESET, BMI08X_SOFT_RESET_CMD);
674 	if (ret < 0) {
675 		LOG_ERR("Cannot reboot chip.");
676 		return ret;
677 	}
678 
679 	k_msleep(BMI08X_ACCEL_SOFTRESET_DELAY_MS);
680 
681 	ret = bmi08x_bus_init(dev);
682 	if (ret < 0) {
683 		LOG_ERR("Can't initialize bus for %s", dev->name);
684 		return ret;
685 	}
686 
687 	ret = bmi08x_accel_byte_read(dev, BMI08X_REG_ACCEL_CHIP_ID, &val);
688 	if (ret < 0) {
689 		LOG_ERR("Failed to read chip id.");
690 		return ret;
691 	}
692 
693 	if ((val != BMI085_ACCEL_CHIP_ID) && (val != BMI088_ACCEL_CHIP_ID)) {
694 		LOG_ERR("Unsupported chip detected (0x%02x)!", val);
695 		return -ENODEV;
696 	}
697 	data->accel_chip_id = val;
698 
699 	/* enable power */
700 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CONF, BMI08X_ACCEL_PM_ACTIVE);
701 	if (ret < 0) {
702 		LOG_ERR("Failed to set conf power mode");
703 		return ret;
704 	}
705 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
706 	ret = bmi08x_accel_byte_write(dev, BMI08X_REG_ACCEL_PWR_CTRL, BMI08X_ACCEL_POWER_ENABLE);
707 	if (ret < 0) {
708 		LOG_ERR("Failed to set ctrl power mode");
709 		return ret;
710 	}
711 	k_msleep(BMI08X_POWER_CONFIG_DELAY);
712 
713 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
714 	if (config->data_sync != 0) {
715 		ret = bmi08x_apply_sync_binary_config(dev);
716 		if (ret < 0) {
717 			return ret;
718 		}
719 	}
720 #endif
721 
722 	/* set accelerometer default range, divide by two because the dts contains both bmi085 and
723 	 * bmi088 valid values even values in the enum are for the bmi085 and odd values are for the
724 	 * bmi088
725 	 */
726 	ret = bmi08x_acc_range_set(dev, config->accel_fs);
727 	if (ret < 0) {
728 		LOG_ERR("Cannot set default range for accelerometer.");
729 		return ret;
730 	}
731 
732 	/* set accelerometer default odr */
733 	/* add 5 to offset from the dts enum */
734 	ret = bmi08x_accel_reg_field_update(dev, BMI08X_REG_ACCEL_CONF, 0, BMI08X_ACCEL_ODR_MASK,
735 					    config->accel_hz);
736 	if (ret < 0) {
737 		LOG_ERR("Failed to set accel's default ODR.");
738 		return ret;
739 	}
740 
741 #ifdef CONFIG_BMI08X_ACCEL_TRIGGER
742 	ret = bmi08x_acc_trigger_mode_init(dev);
743 	if (ret < 0) {
744 		LOG_ERR("Cannot set up trigger mode.");
745 		return ret;
746 	}
747 #endif
748 
749 	return ret;
750 }
751 
752 #define BMI08X_CONFIG_SPI(inst)                                                                    \
753 	.bus.spi = SPI_DT_SPEC_INST_GET(                                                           \
754 		inst, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 2),
755 
756 #define BMI08X_CONFIG_I2C(inst) .bus.i2c = I2C_DT_SPEC_INST_GET(inst),
757 
758 #define BMI08X_ACCEL_TRIG(inst)                                                                    \
759 	.int1_map = DT_INST_PROP(inst, int1_map_io), .int2_map = DT_INST_PROP(inst, int2_map_io),  \
760 	.int1_conf_io = DT_INST_PROP(inst, int1_conf_io),                                          \
761 	.int2_conf_io = DT_INST_PROP(inst, int2_conf_io),
762 
763 /* verify the bmi08x-accel is paired with a bmi08x-gyro */
764 #define BMI08X_VERIFY_DATA_SYNC(inst)                                                              \
765 	BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_INST_PHANDLE(inst, data_sync), bosch_bmi08x_gyro) != 0, \
766 		     "bmi08x-accel data sync not paired with a bmi08x-gyro")
767 /*
768  * verify data sync odr, the only valid odr combinitions with the gyro are
769  *  (gyro-hz == "400_47" and accel-hz == "400") or (gyro-hz == "1000_116" and accel-hz == "800")
770  *  or ((gyro-hz == "2000_230" or gyro-hz == "2000_532") and accel-hz == "1600")
771  */
772 #define BMI08X_GYRO_ODR(inst)  DT_ENUM_IDX(DT_INST_PHANDLE(inst, data_sync), gyro_hz)
773 #define BMI08X_ACCEL_ODR(inst) DT_INST_ENUM_IDX(inst, accel_hz)
774 /* As the dts uses strings to define the definition, ints must be used for comparision */
775 #define BMI08X_VERIFY_DATA_SYNC_ODR(inst)                                                          \
776 	BUILD_ASSERT((BMI08X_GYRO_ODR(inst) == 3 && BMI08X_ACCEL_ODR(inst) == 5) ||                \
777 			     (BMI08X_GYRO_ODR(inst) == 2 && BMI08X_ACCEL_ODR(inst) == 6) ||        \
778 			     ((BMI08X_GYRO_ODR(inst) == 1 || BMI08X_GYRO_ODR(inst) == 0) &&        \
779 			      BMI08X_ACCEL_ODR(inst) == 7),                                        \
780 		     "Invalid gyro and accel odr for data-sync")
781 /* Assert if the gyro does not have data-sync enabled */
782 #define BMI08X_VERIFY_GYRO_DATA_SYNC_EN(inst)                                                      \
783 	BUILD_ASSERT(DT_PROP(DT_INST_PHANDLE(inst, data_sync), data_sync),                         \
784 		     "paired bmi08x-gyro does not have data-sync enabled")
785 
786 /* infer the data-sync value from the gyro and accel odr 2000=1, 1000=2, 400=3, otherwise it is 0 if
787  * it is not enabled. the build_assert should prevent any invalid values when it is enabled
788  */
789 #define BMI08X_DATA_SYNC_REG_VAL(inst)                                                             \
790 	(BMI08X_GYRO_ODR(inst) == 3 && BMI08X_ACCEL_ODR(inst) == 5)   ? 3                          \
791 	: (BMI08X_GYRO_ODR(inst) == 2 && BMI08X_ACCEL_ODR(inst) == 6) ? 2                          \
792 	: ((BMI08X_GYRO_ODR(inst) == 1 || BMI08X_GYRO_ODR(inst) == 0) &&                           \
793 	   BMI08X_ACCEL_ODR(inst) == 7)                                                            \
794 		? 1                                                                                \
795 		: 0
796 
797 /* define the .data_sync in the driver config */
798 #if BMI08X_ACCEL_ANY_INST_HAS_DATA_SYNC
799 /* if another bmi08x as the data sync enabled, and one doesn't, it will get the value of 0 and won't
800  * have the config file sent over
801  */
802 #define BMI08X_DATA_SYNC_REG(inst)                                                                 \
803 	.data_sync = COND_CODE_1(BMI08X_ACCEL_DATA_SYNC_EN(inst),                                  \
804 				 (BMI08X_DATA_SYNC_REG_VAL(inst)), (0)),
805 #define BMI08X_ACCEL_TRIGGER_PINS(inst) BMI08X_ACCEL_TRIG(inst)
806 #else
807 #define BMI08X_DATA_SYNC_REG(inst)
808 #define BMI08X_ACCEL_TRIGGER_PINS(inst)                                                            \
809 	IF_ENABLED(CONFIG_BMI08X_ACCEL_TRIGGER, (BMI08X_ACCEL_TRIG(inst)))
810 #endif
811 
812 #define BMI08X_CREATE_INST(inst)                                                                   \
813                                                                                                    \
814 	IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC(inst);))              \
815 	IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_DATA_SYNC_ODR(inst);))          \
816 	IF_ENABLED(BMI08X_ACCEL_DATA_SYNC_EN(inst), (BMI08X_VERIFY_GYRO_DATA_SYNC_EN(inst);))      \
817                                                                                                    \
818 	static struct bmi08x_accel_data bmi08x_drv_##inst;                                         \
819                                                                                                    \
820 	static const struct bmi08x_accel_config bmi08x_config_##inst = {                           \
821 		COND_CODE_1(DT_INST_ON_BUS(inst, spi), (BMI08X_CONFIG_SPI(inst)),                  \
822 			    (BMI08X_CONFIG_I2C(inst)))                                             \
823 			.api = COND_CODE_1(DT_INST_ON_BUS(inst, spi), (&bmi08x_spi_api),           \
824 					   (&bmi08x_i2c_api)),                                     \
825 		IF_ENABLED(CONFIG_BMI08X_ACCEL_TRIGGER,                                            \
826 			   (.int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),))                  \
827 			BMI08X_ACCEL_TRIGGER_PINS(inst)                                            \
828 				.accel_hz = DT_INST_ENUM_IDX(inst, accel_hz) + 5,                  \
829 		.accel_fs = DT_INST_PROP(inst, accel_fs), BMI08X_DATA_SYNC_REG(inst)};             \
830                                                                                                    \
831 	PM_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_pm_action);                                    \
832 	SENSOR_DEVICE_DT_INST_DEFINE(inst, bmi08x_accel_init, PM_DEVICE_DT_INST_GET(inst),         \
833 				     &bmi08x_drv_##inst, &bmi08x_config_##inst, POST_KERNEL,       \
834 				     CONFIG_SENSOR_INIT_PRIORITY, &bmi08x_api);
835 
836 /* Create the struct device for every status "okay" node in the devicetree. */
837 DT_INST_FOREACH_STATUS_OKAY(BMI08X_CREATE_INST)
838