/* * Copyright (c) 2021 Leica Geosystems AG * * SPDX-License-Identifier: Apache-2.0 */ #define DT_DRV_COMPAT sbs_sbs_gauge #include #include #include #include "sbs_gauge.h" #include LOG_MODULE_REGISTER(sbs_gauge, CONFIG_SENSOR_LOG_LEVEL); static int sbs_cmd_reg_read(const struct device *dev, uint8_t reg_addr, uint16_t *val) { const struct sbs_gauge_config *cfg; uint8_t i2c_data[2]; int status; cfg = dev->config; status = i2c_burst_read_dt(&cfg->i2c, reg_addr, i2c_data, ARRAY_SIZE(i2c_data)); if (status < 0) { LOG_ERR("Unable to read register"); return status; } *val = sys_get_le16(i2c_data); return 0; } /** * @brief sensor value get * * @return -ENOTSUP for unsupported channels */ static int sbs_gauge_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val) { struct sbs_gauge_data *data; int32_t int_temp; data = dev->data; val->val2 = 0; switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: val->val1 = data->voltage / 1000; val->val2 = (data->voltage % 1000) * 1000; break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: val->val1 = data->avg_current / 1000; val->val2 = (data->avg_current % 1000) * 1000; break; case SENSOR_CHAN_GAUGE_TEMP: int_temp = (data->internal_temperature * 10); int_temp = int_temp - 27315; val->val1 = int_temp / 100; val->val2 = (int_temp % 100) * 1000000; break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: val->val1 = data->state_of_charge; break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: val->val1 = data->full_charge_capacity; break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: val->val1 = data->remaining_charge_capacity; break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: val->val1 = data->nom_avail_capacity; break; case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: val->val1 = data->full_avail_capacity; break; case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY: val->val1 = data->time_to_empty; break; case SENSOR_CHAN_GAUGE_TIME_TO_FULL: val->val1 = data->time_to_full; break; case SENSOR_CHAN_GAUGE_CYCLE_COUNT: val->val1 = data->cycle_count; break; default: return -ENOTSUP; } return 0; } static const uint16_t all_channels[] = { SENSOR_CHAN_GAUGE_VOLTAGE, SENSOR_CHAN_GAUGE_AVG_CURRENT, SENSOR_CHAN_GAUGE_TEMP, SENSOR_CHAN_GAUGE_STATE_OF_CHARGE, SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY, SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY, SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY, SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY, SENSOR_CHAN_GAUGE_TIME_TO_EMPTY, SENSOR_CHAN_GAUGE_TIME_TO_FULL, SENSOR_CHAN_GAUGE_CYCLE_COUNT }; static int sbs_gauge_sample_fetch(const struct device *dev, enum sensor_channel chan) { struct sbs_gauge_data *data; int status = 0; data = dev->data; switch (chan) { case SENSOR_CHAN_GAUGE_VOLTAGE: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_VOLTAGE, &data->voltage); if (status < 0) { LOG_ERR("Failed to read voltage"); } break; case SENSOR_CHAN_GAUGE_AVG_CURRENT: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_AVG_CURRENT, &data->avg_current); if (status < 0) { LOG_ERR("Failed to read average current "); } break; case SENSOR_CHAN_GAUGE_TEMP: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_TEMP, &data->internal_temperature); if (status < 0) { LOG_ERR("Failed to read internal temperature"); } break; case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_ASOC, &data->state_of_charge); if (status < 0) { LOG_ERR("Failed to read state of charge"); } break; case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_FULL_CAPACITY, &data->full_charge_capacity); if (status < 0) { LOG_ERR("Failed to read full charge capacity"); } break; case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_REM_CAPACITY, &data->remaining_charge_capacity); if (status < 0) { LOG_ERR("Failed to read remaining charge capacity"); } break; case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_NOM_CAPACITY, &data->nom_avail_capacity); if (status < 0) { LOG_ERR("Failed to read nominal available capacity"); } break; case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_FULL_CAPACITY, &data->full_avail_capacity); if (status < 0) { LOG_ERR("Failed to read full available capacity"); } break; case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_AVG_TIME2EMPTY, &data->time_to_empty); data->time_to_empty = (data->time_to_empty) & 0x00FF; if (status < 0) { LOG_ERR("Failed to read time to empty"); } break; case SENSOR_CHAN_GAUGE_TIME_TO_FULL: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_AVG_TIME2FULL, &data->time_to_full); data->time_to_full = (data->time_to_full) & 0x00FF; if (status < 0) { LOG_ERR("Failed to read time to full"); } break; case SENSOR_CHAN_GAUGE_CYCLE_COUNT: status = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_CYCLE_COUNT, &data->cycle_count); data->cycle_count = (data->cycle_count) & 0x00FF; if (status < 0) { LOG_ERR("Failed to read cycle count"); } break; case SENSOR_CHAN_ALL: for (int i = 0; i < ARRAY_SIZE(all_channels); i++) { status = sbs_gauge_sample_fetch(dev, all_channels[i]); if (status != 0) { break; } } break; default: return -ENOTSUP; } return status; } /** * @brief initialize the fuel gauge * * @return 0 for success */ static int sbs_gauge_init(const struct device *dev) { const struct sbs_gauge_config *cfg; cfg = dev->config; if (!device_is_ready(cfg->i2c.bus)) { LOG_ERR("Bus device is not ready"); return -ENODEV; } return 0; } static const struct sensor_driver_api sbs_gauge_driver_api = { .sample_fetch = sbs_gauge_sample_fetch, .channel_get = sbs_gauge_channel_get, }; #define SBS_GAUGE_INIT(index) \ static struct sbs_gauge_data sbs_gauge_driver_##index; \ \ static const struct sbs_gauge_config sbs_gauge_config_##index = { \ .i2c = I2C_DT_SPEC_INST_GET(index), \ }; \ \ SENSOR_DEVICE_DT_INST_DEFINE(index, \ &sbs_gauge_init, \ NULL, \ &sbs_gauge_driver_##index, \ &sbs_gauge_config_##index, POST_KERNEL, \ CONFIG_SENSOR_INIT_PRIORITY, \ &sbs_gauge_driver_api); DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_INIT)