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 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