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, ®, 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 = ®, .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