drivers: sensors: smart-battery with SBS 1.1 compliant fuel gauge
Implementation of a SBS 1.1 compliant fuel gauge driver Signed-off-by: MORGER Patrick <patrick.morger@leica-geosystems.com>
This commit is contained in:
parent
4a382ae2ce
commit
0e1d16bf03
17 changed files with 620 additions and 4 deletions
3
drivers/sensor/sbs_gauge/CMakeLists.txt
Normal file
3
drivers/sensor/sbs_gauge/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
zephyr_library()
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_SBS_GAUGE sbs_gauge.c)
|
8
drivers/sensor/sbs_gauge/Kconfig
Normal file
8
drivers/sensor/sbs_gauge/Kconfig
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2021 Leica Geosystems AG
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SBS_GAUGE
|
||||
bool "Smart Battery Fuel Gauge"
|
||||
depends on I2C
|
||||
help
|
||||
Enable I2C-based/SMBus-based driver for a Smart Battery Fuel Gauge.
|
272
drivers/sensor/sbs_gauge/sbs_gauge.c
Normal file
272
drivers/sensor/sbs_gauge/sbs_gauge.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Leica Geosystems AG
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT sbs_sbs_gauge
|
||||
|
||||
#include <drivers/i2c.h>
|
||||
#include <drivers/sensor.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
||||
#include "sbs_gauge.h"
|
||||
|
||||
#include <logging/log.h>
|
||||
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 = (struct sbs_gauge_config *)dev->config;
|
||||
status = i2c_burst_read(cfg->i2c_dev, cfg->i2c_addr, 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 = (struct sbs_gauge_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 int sbs_gauge_sample_fetch(const struct device *dev,
|
||||
enum sensor_channel chan)
|
||||
{
|
||||
struct sbs_gauge_data *data;
|
||||
int status = 0;
|
||||
|
||||
data = (struct sbs_gauge_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;
|
||||
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief initialize the fuel gauge
|
||||
*
|
||||
* @return 0 for success
|
||||
*/
|
||||
static int sbs_gauge_init(const struct device *dev)
|
||||
{
|
||||
struct sbs_gauge_config *cfg;
|
||||
|
||||
cfg = (struct sbs_gauge_config *)dev->config;
|
||||
|
||||
if (!device_is_ready(cfg->i2c_dev)) {
|
||||
LOG_ERR("%s device is not ready", cfg->i2c_dev->name);
|
||||
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_dev = DEVICE_DT_GET(DT_INST_BUS(index)), \
|
||||
.i2c_addr = DT_INST_REG_ADDR(index), \
|
||||
}; \
|
||||
\
|
||||
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)
|
80
drivers/sensor/sbs_gauge/sbs_gauge.h
Normal file
80
drivers/sensor/sbs_gauge/sbs_gauge.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Leica Geosystems AG
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_DRIVERS_SENSOR_SBS_GAUGE_H_
|
||||
#define ZEPHYR_DRIVERS_SENSOR_SBS_GAUGE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*** Standard Commands ***/
|
||||
#define SBS_GAUGE_CMD_MANUFACTURER_ACCESS 0x00 /* ManufacturerAccess */
|
||||
#define SBS_GAUGE_CMD_REM_CAPACITY_ALARM 0x01 /* LowCapacityAlarmThreshold */
|
||||
#define SBS_GAUGE_CMD_REM_TIME_ALARM 0x02 /* RemainingTimeToEmptyThreshold */
|
||||
#define SBS_GAUGE_CMD_BATTERY_MODE 0x03 /* BatteryOperatingMode */
|
||||
#define SBS_GAUGE_CMD_AR 0x04 /* AtRate */
|
||||
#define SBS_GAUGE_CMD_ARTTF 0x05 /* AtRateTimeToFull */
|
||||
#define SBS_GAUGE_CMD_ARTTE 0x06 /* AtRateTimeToEmpty */
|
||||
#define SBS_GAUGE_CMD_AROK 0x07 /* AtRateOK */
|
||||
#define SBS_GAUGE_CMD_TEMP 0x08 /* Temperature */
|
||||
#define SBS_GAUGE_CMD_VOLTAGE 0x09 /* Voltage */
|
||||
#define SBS_GAUGE_CMD_CURRENT 0x0A /* Current */
|
||||
#define SBS_GAUGE_CMD_AVG_CURRENT 0x0B /* AverageCurrent */
|
||||
#define SBS_GAUGE_CMD_MAX_ERROR 0x0C /* MaxError */
|
||||
#define SBS_GAUGE_CMD_RSOC 0x0D /* RelativeStateOfCharge */
|
||||
#define SBS_GAUGE_CMD_ASOC 0x0E /* AbsoluteStateOfCharge */
|
||||
#define SBS_GAUGE_CMD_REM_CAPACITY 0x0F /* RemainingCapacity */
|
||||
#define SBS_GAUGE_CMD_FULL_CAPACITY 0x10 /* FullChargeCapacity */
|
||||
#define SBS_GAUGE_CMD_RUNTIME2EMPTY 0x11 /* RunTimeToEmpty */
|
||||
#define SBS_GAUGE_CMD_AVG_TIME2EMPTY 0x12 /* AverageTimeToEmpty */
|
||||
#define SBS_GAUGE_CMD_AVG_TIME2FULL 0x13 /* AverageTimeToFull */
|
||||
#define SBS_GAUGE_CMD_CHG_CURRENT 0x14 /* ChargeCurrent */
|
||||
#define SBS_GAUGE_CMD_CHG_VOLTAGE 0x15 /* ChargeVoltage */
|
||||
#define SBS_GAUGE_CMD_FLAGS 0x16 /* BatteryStatus */
|
||||
#define SBS_GAUGE_CMD_CYCLE_COUNT 0x17 /* CycleCount */
|
||||
#define SBS_GAUGE_CMD_NOM_CAPACITY 0x18 /* DesignCapacity */
|
||||
#define SBS_GAUGE_CMD_DESIGN_VOLTAGE 0x19 /* DesignVoltage */
|
||||
#define SBS_GAUGE_CMD_SPECS_INFO 0x1A /* SpecificationInfo */
|
||||
#define SBS_GAUGE_CMD_MANUFACTURER_DATE 0x1B /* ManufacturerDate */
|
||||
#define SBS_GAUGE_CMD_SN 0x1C /* SerialNumber */
|
||||
#define SBS_GAUGE_CMD_MANUFACTURER_NAME 0x20 /* ManufacturerName */
|
||||
#define SBS_GAUGE_CMD_DEVICE_NAME 0x21 /* DeviceName */
|
||||
#define SBS_GAUGE_CMD_DEVICE_CHEM 0x22 /* DeviceChemistry */
|
||||
#define SBS_GAUGE_CMD_MANUFACTURER_DATA 0x23 /* ManufacturerData */
|
||||
#define SBS_GAUGE_CMD_DESIGN_MAX_POWER 0x24 /* DesignMaxPower */
|
||||
#define SBS_GAUGE_CMD_START_TIME 0x25 /* StartTime */
|
||||
#define SBS_GAUGE_CMD_TOTAL_RUNTIME 0x26 /* TotalRuntime */
|
||||
#define SBS_GAUGE_CMD_FC_TEMP 0x27 /* FCTemp */
|
||||
#define SBS_GAUGE_CMD_FC_STATUS 0x28 /* FCStatus */
|
||||
#define SBS_GAUGE_CMD_FC_MODE 0x29 /* FCMode */
|
||||
#define SBS_GAUGE_CMD_AUTO_SOFT_OFF 0x2A /* AutoSoftOff */
|
||||
#define SBS_GAUGE_CMD_AUTHENTICATE 0x2F /* Authenticate */
|
||||
#define SBS_GAUGE_CMD_CELL_V4 0x3C /* CellVoltage4 */
|
||||
#define SBS_GAUGE_CMD_CELL_V3 0x3D /* CellVoltage3 */
|
||||
#define SBS_GAUGE_CMD_CELL_V2 0x3E /* CellVoltage2 */
|
||||
#define SBS_GAUGE_CMD_CELL_V1 0x3F /* CellVoltage1 */
|
||||
|
||||
#define SBS_GAUGE_DELAY 1000
|
||||
|
||||
struct sbs_gauge_data {
|
||||
uint16_t voltage;
|
||||
int16_t avg_current;
|
||||
uint16_t state_of_charge;
|
||||
uint16_t internal_temperature;
|
||||
uint16_t full_charge_capacity;
|
||||
uint16_t remaining_charge_capacity;
|
||||
uint16_t nom_avail_capacity;
|
||||
uint16_t full_avail_capacity;
|
||||
uint16_t time_to_empty;
|
||||
uint16_t time_to_full;
|
||||
uint16_t cycle_count;
|
||||
};
|
||||
|
||||
struct sbs_gauge_config {
|
||||
const struct device *i2c_dev;
|
||||
uint8_t i2c_addr;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue