/* * Copyright (c) 2023 Trackunit Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include "bmi323.h" #include "bmi323_spi.h" #include #include #include #include #include #include #include LOG_MODULE_REGISTER(bosch_bmi323); #define DT_DRV_COMPAT bosch_bmi323 /* Value taken from BMI323 Datasheet section 5.8.1 */ #define IMU_BOSCH_FEATURE_ENGINE_STARTUP_CONFIG (0x012C) #define IMU_BOSCH_DIE_TEMP_OFFSET_MICRO_DEG_CELCIUS (23000000LL) #define IMU_BOSCH_DIE_TEMP_MICRO_DEG_CELCIUS_LSB (1953L) typedef void (*bosch_bmi323_gpio_callback_ptr)(const struct device *dev, struct gpio_callback *cb, uint32_t pins); struct bosch_bmi323_config { const struct bosch_bmi323_bus *bus; const struct gpio_dt_spec int_gpio; const bosch_bmi323_gpio_callback_ptr int_gpio_callback; }; struct bosch_bmi323_data { struct k_mutex lock; struct sensor_value acc_samples[3]; struct sensor_value gyro_samples[3]; struct sensor_value temperature; bool acc_samples_valid; bool gyro_samples_valid; bool temperature_valid; uint32_t acc_full_scale; uint32_t gyro_full_scale; struct gpio_callback gpio_callback; const struct sensor_trigger *trigger; sensor_trigger_handler_t trigger_handler; struct k_work callback_work; const struct device *dev; }; static int bosch_bmi323_bus_init(const struct device *dev) { const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; const struct bosch_bmi323_bus *bus = config->bus; return bus->api->init(bus->context); } static int bosch_bmi323_bus_read_words(const struct device *dev, uint8_t offset, uint16_t *words, uint16_t words_count) { const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; const struct bosch_bmi323_bus *bus = config->bus; return bus->api->read_words(bus->context, offset, words, words_count); } static int bosch_bmi323_bus_write_words(const struct device *dev, uint8_t offset, uint16_t *words, uint16_t words_count) { const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; const struct bosch_bmi323_bus *bus = config->bus; return bus->api->write_words(bus->context, offset, words, words_count); } static int32_t bosch_bmi323_lsb_from_fullscale(int64_t fullscale) { return (fullscale * 1000) / INT16_MAX; } /* lsb is the value of one 1/1000000 LSB */ static int64_t bosch_bmi323_value_to_micro(int16_t value, int32_t lsb) { return ((int64_t)value) * lsb; } /* lsb is the value of one 1/1000000 LSB */ static void bosch_bmi323_value_to_sensor_value(struct sensor_value *result, int16_t value, int32_t lsb) { int64_t ll_value = (int64_t)value * lsb; int32_t int_part = (int32_t)(ll_value / 1000000); int32_t frac_part = (int32_t)(ll_value % 1000000); result->val1 = int_part; result->val2 = frac_part; } static void bosch_bmi323_sensor_value_from_micro(struct sensor_value *result, int64_t micro) { int32_t int_part = (int32_t)(micro / 1000000); int32_t frac_part = (int32_t)(micro % 1000000); result->val1 = int_part; result->val2 = frac_part; } static bool bosch_bmi323_value_is_valid(int16_t value) { return ((uint16_t)value == 0x8000) ? false : true; } static int bosch_bmi323_validate_chip_id(const struct device *dev) { uint16_t sensor_id; int ret; ret = bosch_bmi323_bus_read_words(dev, 0, &sensor_id, 1); if (ret < 0) { return ret; } if ((sensor_id & 0xFF) != 0x43) { return -ENODEV; } return 0; } static int bosch_bmi323_soft_reset(const struct device *dev) { uint16_t cmd; int ret; cmd = IMU_BOSCH_BMI323_REG_VALUE(CMD, CMD, SOFT_RESET); ret = bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_CMD, &cmd, 1); if (ret < 0) { return ret; } k_usleep(1500); return 0; } static int bosch_bmi323_enable_feature_engine(const struct device *dev) { uint16_t buf; int ret; buf = IMU_BOSCH_FEATURE_ENGINE_STARTUP_CONFIG; ret = bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_FEATURE_IO2, &buf, 1); if (ret < 0) { return ret; } buf = IMU_BOSCH_BMI323_REG_VALUE(FEATURE_IO_STATUS, STATUS, SET); ret = bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_FEATURE_IO_STATUS, &buf, 1); if (ret < 0) { return ret; } buf = IMU_BOSCH_BMI323_REG_VALUE(FEATURE_CTRL, ENABLE, EN); return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_FEATURE_CTRL, &buf, 1); } static int bosch_bmi323_driver_api_set_acc_odr(const struct device *dev, const struct sensor_value *val) { int ret; uint16_t acc_conf; int64_t odr = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); if (ret < 0) { return ret; } acc_conf &= ~IMU_BOSCH_BMI323_REG_MASK(ACC_CONF, ODR); if (odr <= 782) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ0P78125); } else if (odr <= 1563) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ1P5625); } else if (odr <= 3125) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ3P125); } else if (odr <= 6250) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ6P25); } else if (odr <= 12500) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ12P5); } else if (odr <= 25000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ25); } else if (odr <= 50000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ50); } else if (odr <= 100000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ100); } else if (odr <= 200000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ200); } else if (odr <= 400000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ400); } else if (odr <= 800000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ800); } else if (odr <= 1600000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ1600); } else if (odr <= 3200000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ3200); } else { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, ODR, HZ6400); } return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); } static int bosch_bmi323_driver_api_set_acc_full_scale(const struct device *dev, const struct sensor_value *val) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; uint16_t acc_conf; int64_t fullscale = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); if (ret < 0) { return ret; } acc_conf &= ~IMU_BOSCH_BMI323_REG_MASK(ACC_CONF, RANGE); if (fullscale <= 2000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, RANGE, G2); } else if (fullscale <= 4000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, RANGE, G4); } else if (fullscale <= 8000) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, RANGE, G8); } else { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, RANGE, G16); } data->acc_full_scale = 0; return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); } static int bosch_bmi323_driver_api_set_acc_feature_mask(const struct device *dev, const struct sensor_value *val) { int ret; uint16_t acc_conf; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); if (ret < 0) { return ret; } acc_conf &= ~IMU_BOSCH_BMI323_REG_MASK(ACC_CONF, MODE); if (val->val1) { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, MODE, HPWR); } else { acc_conf |= IMU_BOSCH_BMI323_REG_VALUE(ACC_CONF, MODE, DIS); } return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); } static int bosch_bmi323_driver_api_set_gyro_odr(const struct device *dev, const struct sensor_value *val) { int ret; uint16_t gyro_conf; int64_t odr = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); if (ret < 0) { return ret; } gyro_conf &= ~IMU_BOSCH_BMI323_REG_MASK(GYRO_CONF, ODR); if (odr <= 782) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ0P78125); } else if (odr <= 1563) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ1P5625); } else if (odr <= 3125) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ3P125); } else if (odr <= 6250) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ6P25); } else if (odr <= 12500) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ12P5); } else if (odr <= 25000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ25); } else if (odr <= 50000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ50); } else if (odr <= 100000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ100); } else if (odr <= 200000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ200); } else if (odr <= 400000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ400); } else if (odr <= 800000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ800); } else if (odr <= 1600000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ1600); } else if (odr <= 3200000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ3200); } else { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, ODR, HZ6400); } return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); } static int bosch_bmi323_driver_api_set_gyro_full_scale(const struct device *dev, const struct sensor_value *val) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; uint16_t gyro_conf; int32_t fullscale = sensor_value_to_milli(val); ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); if (ret < 0) { return ret; } gyro_conf &= ~IMU_BOSCH_BMI323_REG_MASK(GYRO_CONF, RANGE); if (fullscale <= 125000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, RANGE, DPS125); } else if (fullscale <= 250000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, RANGE, DPS250); } else if (fullscale <= 500000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, RANGE, DPS500); } else if (fullscale <= 1000000) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, RANGE, DPS1000); } else { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, RANGE, DPS2000); } data->gyro_full_scale = 0; return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); } static int bosch_bmi323_driver_api_set_gyro_feature_mask(const struct device *dev, const struct sensor_value *val) { int ret; uint16_t gyro_conf; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); if (ret < 0) { return ret; } gyro_conf &= ~IMU_BOSCH_BMI323_REG_MASK(GYRO_CONF, MODE); if (val->val1) { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, MODE, HPWR); } else { gyro_conf |= IMU_BOSCH_BMI323_REG_VALUE(GYRO_CONF, MODE, DIS); } return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); } static int bosch_bmi323_driver_api_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; k_mutex_lock(&data->lock, K_FOREVER); switch (chan) { case SENSOR_CHAN_ACCEL_XYZ: switch (attr) { case SENSOR_ATTR_SAMPLING_FREQUENCY: ret = bosch_bmi323_driver_api_set_acc_odr(dev, val); break; case SENSOR_ATTR_FULL_SCALE: ret = bosch_bmi323_driver_api_set_acc_full_scale(dev, val); break; case SENSOR_ATTR_FEATURE_MASK: ret = bosch_bmi323_driver_api_set_acc_feature_mask(dev, val); break; default: ret = -ENODEV; break; } break; case SENSOR_CHAN_GYRO_XYZ: switch (attr) { case SENSOR_ATTR_SAMPLING_FREQUENCY: ret = bosch_bmi323_driver_api_set_gyro_odr(dev, val); break; case SENSOR_ATTR_FULL_SCALE: ret = bosch_bmi323_driver_api_set_gyro_full_scale(dev, val); break; case SENSOR_ATTR_FEATURE_MASK: ret = bosch_bmi323_driver_api_set_gyro_feature_mask(dev, val); break; default: ret = -ENODEV; break; } break; default: ret = -ENODEV; break; } k_mutex_unlock(&data->lock); return ret; } static int bosch_bmi323_driver_api_get_acc_odr(const struct device *dev, struct sensor_value *val) { uint16_t acc_conf; int ret; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); if (ret < 0) { return ret; } switch (IMU_BOSCH_BMI323_REG_VALUE_GET_FIELD(acc_conf, ACC_CONF, ODR)) { case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ0P78125: val->val1 = 0; val->val2 = 781250; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ1P5625: val->val1 = 1; val->val2 = 562500; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ3P125: val->val1 = 3; val->val2 = 125000; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ6P25: val->val1 = 6; val->val2 = 250000; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ12P5: val->val1 = 12; val->val2 = 500000; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ25: val->val1 = 25; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ50: val->val1 = 50; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ100: val->val1 = 100; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ200: val->val1 = 200; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ400: val->val1 = 400; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ800: val->val1 = 800; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ1600: val->val1 = 1600; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ3200: val->val1 = 3200; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_ODR_VAL_HZ6400: val->val1 = 6400; val->val2 = 0; break; default: return -EINVAL; } return 0; } static int bosch_bmi323_driver_api_get_acc_full_scale(const struct device *dev, struct sensor_value *val) { uint16_t acc_conf; int ret; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); if (ret < 0) { return ret; } switch (IMU_BOSCH_BMI323_REG_VALUE_GET_FIELD(acc_conf, ACC_CONF, RANGE)) { case IMU_BOSCH_BMI323_REG_ACC_CONF_RANGE_VAL_G2: val->val1 = 2; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_RANGE_VAL_G4: val->val1 = 4; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_RANGE_VAL_G8: val->val1 = 8; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_ACC_CONF_RANGE_VAL_G16: val->val1 = 16; val->val2 = 0; break; default: return -EINVAL; } return 0; } static int bosch_bmi323_driver_api_get_acc_feature_mask(const struct device *dev, struct sensor_value *val) { uint16_t acc_conf; int ret; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_CONF, &acc_conf, 1); if (ret < 0) { return ret; } if (IMU_BOSCH_BMI323_REG_VALUE_GET_FIELD(acc_conf, ACC_CONF, MODE)) { val->val1 = 1; val->val2 = 0; } else { val->val1 = 0; val->val2 = 0; } return 0; } static int bosch_bmi323_driver_api_get_gyro_odr(const struct device *dev, struct sensor_value *val) { uint16_t gyro_conf; int ret; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); if (ret < 0) { return ret; } switch (IMU_BOSCH_BMI323_REG_VALUE_GET_FIELD(gyro_conf, GYRO_CONF, ODR)) { case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ0P78125: val->val1 = 0; val->val2 = 781250; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ1P5625: val->val1 = 1; val->val2 = 562500; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ3P125: val->val1 = 3; val->val2 = 125000; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ6P25: val->val1 = 6; val->val2 = 250000; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ12P5: val->val1 = 12; val->val2 = 500000; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ25: val->val1 = 25; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ50: val->val1 = 50; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ100: val->val1 = 100; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ200: val->val1 = 200; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ400: val->val1 = 400; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ800: val->val1 = 800; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ1600: val->val1 = 1600; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ3200: val->val1 = 3200; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_ODR_VAL_HZ6400: val->val1 = 6400; val->val2 = 0; break; default: return -EINVAL; } return 0; } static int bosch_bmi323_driver_api_get_gyro_full_scale(const struct device *dev, struct sensor_value *val) { uint16_t gyro_conf; int ret; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); if (ret < 0) { return ret; } switch (IMU_BOSCH_BMI323_REG_VALUE_GET_FIELD(gyro_conf, GYRO_CONF, RANGE)) { case IMU_BOSCH_BMI323_REG_GYRO_CONF_RANGE_VAL_DPS125: val->val1 = 125; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_RANGE_VAL_DPS250: val->val1 = 250; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_RANGE_VAL_DPS500: val->val1 = 500; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_RANGE_VAL_DPS1000: val->val1 = 1000; val->val2 = 0; break; case IMU_BOSCH_BMI323_REG_GYRO_CONF_RANGE_VAL_DPS2000: val->val1 = 2000; val->val2 = 0; break; default: return -EINVAL; } return 0; } static int bosch_bmi323_driver_api_get_gyro_feature_mask(const struct device *dev, struct sensor_value *val) { uint16_t gyro_conf; int ret; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_CONF, &gyro_conf, 1); if (ret < 0) { return ret; } if (IMU_BOSCH_BMI323_REG_VALUE_GET_FIELD(gyro_conf, GYRO_CONF, MODE)) { val->val1 = 1; val->val2 = 0; } else { val->val1 = 0; val->val2 = 0; } return 0; } static int bosch_bmi323_driver_api_attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, struct sensor_value *val) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; k_mutex_lock(&data->lock, K_FOREVER); switch (chan) { case SENSOR_CHAN_ACCEL_XYZ: switch (attr) { case SENSOR_ATTR_SAMPLING_FREQUENCY: ret = bosch_bmi323_driver_api_get_acc_odr(dev, val); break; case SENSOR_ATTR_FULL_SCALE: ret = bosch_bmi323_driver_api_get_acc_full_scale(dev, val); break; case SENSOR_ATTR_FEATURE_MASK: ret = bosch_bmi323_driver_api_get_acc_feature_mask(dev, val); break; default: ret = -ENODEV; break; } break; case SENSOR_CHAN_GYRO_XYZ: switch (attr) { case SENSOR_ATTR_SAMPLING_FREQUENCY: ret = bosch_bmi323_driver_api_get_gyro_odr(dev, val); break; case SENSOR_ATTR_FULL_SCALE: ret = bosch_bmi323_driver_api_get_gyro_full_scale(dev, val); break; case SENSOR_ATTR_FEATURE_MASK: ret = bosch_bmi323_driver_api_get_gyro_feature_mask(dev, val); break; default: ret = -ENODEV; break; } break; default: ret = -ENODEV; break; } k_mutex_unlock(&data->lock); return ret; } static int bosch_bmi323_driver_api_trigger_set_acc_drdy(const struct device *dev) { uint16_t buf[2]; buf[0] = 0; buf[1] = IMU_BOSCH_BMI323_REG_VALUE(INT_MAP2, ACC_DRDY_INT, INT1); return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_INT_MAP1, buf, 2); } static int bosch_bmi323_driver_api_trigger_set_acc_motion(const struct device *dev) { uint16_t buf[2]; int ret; buf[0] = IMU_BOSCH_BMI323_REG_VALUE(INT_MAP1, MOTION_OUT, INT1); buf[1] = 0; ret = bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_INT_MAP1, buf, 2); if (ret < 0) { return ret; } buf[0] = 0; ret = bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_FEATURE_IO0, buf, 1); if (ret < 0) { return ret; } buf[0] = IMU_BOSCH_BMI323_REG_VALUE(FEATURE_IO0, MOTION_X_EN, EN) | IMU_BOSCH_BMI323_REG_VALUE(FEATURE_IO0, MOTION_Y_EN, EN) | IMU_BOSCH_BMI323_REG_VALUE(FEATURE_IO0, MOTION_Z_EN, EN); ret = bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_FEATURE_IO0, buf, 1); if (ret < 0) { return ret; } buf[0] = 1; return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_FEATURE_IO_STATUS, buf, 1); } static int bosch_bmi323_driver_api_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret = -ENODEV; k_mutex_lock(&data->lock, K_FOREVER); data->trigger = trig; data->trigger_handler = handler; switch (trig->chan) { case SENSOR_CHAN_ACCEL_XYZ: switch (trig->type) { case SENSOR_TRIG_DATA_READY: ret = bosch_bmi323_driver_api_trigger_set_acc_drdy(dev); break; case SENSOR_TRIG_MOTION: ret = bosch_bmi323_driver_api_trigger_set_acc_motion(dev); break; default: break; } break; default: break; } k_mutex_unlock(&data->lock); return ret; } static int bosch_bmi323_driver_api_fetch_acc_samples(const struct device *dev) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; struct sensor_value full_scale; int16_t *buf = (int16_t *)data->acc_samples; int ret; int32_t lsb; if (data->acc_full_scale == 0) { ret = bosch_bmi323_driver_api_get_acc_full_scale(dev, &full_scale); if (ret < 0) { return ret; } data->acc_full_scale = sensor_value_to_milli(&full_scale); } ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_ACC_DATA_X, (uint16_t *)buf, 3); if (ret < 0) { return ret; } if ((bosch_bmi323_value_is_valid(buf[0]) == false) || (bosch_bmi323_value_is_valid(buf[1]) == false) || (bosch_bmi323_value_is_valid(buf[2]) == false)) { return -ENODATA; } lsb = bosch_bmi323_lsb_from_fullscale(data->acc_full_scale); /* Reuse vector backwards to avoid overwriting the raw values */ bosch_bmi323_value_to_sensor_value(&data->acc_samples[2], buf[2], lsb); bosch_bmi323_value_to_sensor_value(&data->acc_samples[1], buf[1], lsb); bosch_bmi323_value_to_sensor_value(&data->acc_samples[0], buf[0], lsb); data->acc_samples_valid = true; return 0; } static int bosch_bmi323_driver_api_fetch_gyro_samples(const struct device *dev) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; struct sensor_value full_scale; int16_t *buf = (int16_t *)data->gyro_samples; int ret; int32_t lsb; if (data->gyro_full_scale == 0) { ret = bosch_bmi323_driver_api_get_gyro_full_scale(dev, &full_scale); if (ret < 0) { return ret; } data->gyro_full_scale = sensor_value_to_milli(&full_scale); } ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_GYRO_DATA_X, (uint16_t *)buf, 3); if (ret < 0) { return ret; } if ((bosch_bmi323_value_is_valid(buf[0]) == false) || (bosch_bmi323_value_is_valid(buf[1]) == false) || (bosch_bmi323_value_is_valid(buf[2]) == false)) { return -ENODATA; } lsb = bosch_bmi323_lsb_from_fullscale(data->gyro_full_scale); /* Reuse vector backwards to avoid overwriting the raw values */ bosch_bmi323_value_to_sensor_value(&data->gyro_samples[2], buf[2], lsb); bosch_bmi323_value_to_sensor_value(&data->gyro_samples[1], buf[1], lsb); bosch_bmi323_value_to_sensor_value(&data->gyro_samples[0], buf[0], lsb); data->gyro_samples_valid = true; return 0; } static int bosch_bmi323_driver_api_fetch_temperature(const struct device *dev) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int16_t buf; int64_t micro; int ret; ret = bosch_bmi323_bus_read_words(dev, IMU_BOSCH_BMI323_REG_TEMP_DATA, &buf, 1); if (ret < 0) { return ret; } if (bosch_bmi323_value_is_valid(buf) == false) { return -ENODATA; } micro = bosch_bmi323_value_to_micro(buf, IMU_BOSCH_DIE_TEMP_MICRO_DEG_CELCIUS_LSB); micro += IMU_BOSCH_DIE_TEMP_OFFSET_MICRO_DEG_CELCIUS; bosch_bmi323_sensor_value_from_micro(&data->temperature, micro); data->temperature_valid = true; return 0; } static int bosch_bmi323_driver_api_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; k_mutex_lock(&data->lock, K_FOREVER); switch (chan) { case SENSOR_CHAN_ACCEL_XYZ: ret = bosch_bmi323_driver_api_fetch_acc_samples(dev); break; case SENSOR_CHAN_GYRO_XYZ: ret = bosch_bmi323_driver_api_fetch_gyro_samples(dev); break; case SENSOR_CHAN_DIE_TEMP: ret = bosch_bmi323_driver_api_fetch_temperature(dev); break; case SENSOR_CHAN_ALL: ret = bosch_bmi323_driver_api_fetch_acc_samples(dev); if (ret < 0) { break; } ret = bosch_bmi323_driver_api_fetch_gyro_samples(dev); if (ret < 0) { break; } ret = bosch_bmi323_driver_api_fetch_temperature(dev); break; default: ret = -ENODEV; break; } k_mutex_unlock(&data->lock); return ret; } static int bosch_bmi323_driver_api_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret = 0; k_mutex_lock(&data->lock, K_FOREVER); switch (chan) { case SENSOR_CHAN_ACCEL_XYZ: if (data->acc_samples_valid == false) { ret = -ENODATA; break; } memcpy(val, data->acc_samples, sizeof(data->acc_samples)); break; case SENSOR_CHAN_GYRO_XYZ: if (data->gyro_samples_valid == false) { ret = -ENODATA; break; } memcpy(val, data->gyro_samples, sizeof(data->gyro_samples)); break; case SENSOR_CHAN_DIE_TEMP: if (data->temperature_valid == false) { ret = -ENODATA; break; } (*val) = data->temperature; break; default: ret = -ENOTSUP; break; } k_mutex_unlock(&data->lock); return ret; } static DEVICE_API(sensor, bosch_bmi323_api) = { .attr_set = bosch_bmi323_driver_api_attr_set, .attr_get = bosch_bmi323_driver_api_attr_get, .trigger_set = bosch_bmi323_driver_api_trigger_set, .sample_fetch = bosch_bmi323_driver_api_sample_fetch, .channel_get = bosch_bmi323_driver_api_channel_get, }; static void bosch_bmi323_irq_callback(const struct device *dev) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; k_work_submit(&data->callback_work); } static int bosch_bmi323_init_irq(const struct device *dev) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; struct bosch_bmi323_config *config = (struct bosch_bmi323_config *)dev->config; int ret; ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); if (ret < 0) { return ret; } gpio_init_callback(&data->gpio_callback, config->int_gpio_callback, BIT(config->int_gpio.pin)); ret = gpio_add_callback(config->int_gpio.port, &data->gpio_callback); if (ret < 0) { return ret; } return gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE); } static int bosch_bmi323_init_int1(const struct device *dev) { uint16_t buf; buf = IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_LVL, ACT_HIGH) | IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_OD, PUSH_PULL) | IMU_BOSCH_BMI323_REG_VALUE(IO_INT_CTRL, INT1_OUTPUT_EN, EN); return bosch_bmi323_bus_write_words(dev, IMU_BOSCH_BMI323_REG_IO_INT_CTRL, &buf, 1); } static void bosch_bmi323_irq_callback_handler(struct k_work *item) { struct bosch_bmi323_data *data = CONTAINER_OF(item, struct bosch_bmi323_data, callback_work); k_mutex_lock(&data->lock, K_FOREVER); if (data->trigger_handler != NULL) { data->trigger_handler(data->dev, data->trigger); } k_mutex_unlock(&data->lock); } static int bosch_bmi323_pm_resume(const struct device *dev) { const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; int ret; ret = bosch_bmi323_bus_init(dev); if (ret < 0) { LOG_WRN("Failed to init bus"); return ret; } ret = bosch_bmi323_validate_chip_id(dev); if (ret < 0) { LOG_WRN("Failed to validate chip id"); return ret; } ret = bosch_bmi323_soft_reset(dev); if (ret < 0) { LOG_WRN("Failed to soft reset chip"); return ret; } ret = bosch_bmi323_bus_init(dev); if (ret < 0) { LOG_WRN("Failed to re-init bus"); return ret; } ret = bosch_bmi323_enable_feature_engine(dev); if (ret < 0) { LOG_WRN("Failed to enable feature engine"); return ret; } ret = bosch_bmi323_init_int1(dev); if (ret < 0) { LOG_WRN("Failed to enable INT1"); return ret; } ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE); if (ret < 0) { LOG_WRN("Failed to configure int"); } return ret; } #ifdef CONFIG_PM_DEVICE static int bosch_bmi323_pm_suspend(const struct device *dev) { const struct bosch_bmi323_config *config = (const struct bosch_bmi323_config *)dev->config; int ret; ret = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_DISABLE); if (ret < 0) { LOG_WRN("Failed to disable int"); } /* Soft reset device to put it into suspend */ return bosch_bmi323_soft_reset(dev); } #endif /* CONFIG_PM_DEVICE */ #ifdef CONFIG_PM_DEVICE static int bosch_bmi323_pm_action(const struct device *dev, enum pm_device_action action) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; k_mutex_lock(&data->lock, K_FOREVER); switch (action) { case PM_DEVICE_ACTION_RESUME: ret = bosch_bmi323_pm_resume(dev); break; case PM_DEVICE_ACTION_SUSPEND: ret = bosch_bmi323_pm_suspend(dev); break; default: ret = -ENOTSUP; break; } k_mutex_unlock(&data->lock); return ret; } #endif /* CONFIG_PM_DEVICE */ static int bosch_bmi323_init(const struct device *dev) { struct bosch_bmi323_data *data = (struct bosch_bmi323_data *)dev->data; int ret; k_mutex_init(&data->lock); k_work_init(&data->callback_work, bosch_bmi323_irq_callback_handler); data->dev = dev; ret = bosch_bmi323_init_irq(dev); if (ret < 0) { LOG_WRN("Failed to init irq"); return ret; } #ifndef CONFIG_PM_DEVICE_RUNTIME ret = bosch_bmi323_pm_resume(dev); if (ret < 0) { LOG_WRN("Failed to initialize device"); } #else pm_device_init_suspended(dev); ret = pm_device_runtime_enable(dev); if (ret < 0) { LOG_WRN("Failed to enable device pm runtime"); } #endif /* CONFIG_PM_DEVICE_RUNTIME */ return ret; } /* * Currently only support for the SPI bus is implemented. This shall be updated to * select the appropriate bus once I2C is implemented. */ #define BMI323_DEVICE_BUS(inst) \ BUILD_ASSERT(DT_INST_ON_BUS(inst, spi), "Unimplemented bus"); \ BMI323_DEVICE_SPI_BUS(inst) #define BMI323_DEVICE(inst) \ static struct bosch_bmi323_data bosch_bmi323_data_##inst; \ \ BMI323_DEVICE_BUS(inst); \ \ static void bosch_bmi323_irq_callback##inst(const struct device *dev, \ struct gpio_callback *cb, uint32_t pins) \ { \ bosch_bmi323_irq_callback(DEVICE_DT_INST_GET(inst)); \ } \ \ static const struct bosch_bmi323_config bosch_bmi323_config_##inst = { \ .bus = &bosch_bmi323_bus_api##inst, \ .int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \ .int_gpio_callback = bosch_bmi323_irq_callback##inst, \ }; \ \ PM_DEVICE_DT_INST_DEFINE(inst, bosch_bmi323_pm_action); \ \ SENSOR_DEVICE_DT_INST_DEFINE(inst, bosch_bmi323_init, PM_DEVICE_DT_INST_GET(inst), \ &bosch_bmi323_data_##inst, &bosch_bmi323_config_##inst, \ POST_KERNEL, 99, &bosch_bmi323_api); DT_INST_FOREACH_STATUS_OKAY(BMI323_DEVICE)