fuel_gauge: Sample sbs gauge driver with tests
Add a sample sbs gauge driver with feature parity and basic tests comparison to its sensor counter-part. Includes a simple stub test that is extended upon. Signed-off-by: Aaron Massey <aaronmassey@google.com>
This commit is contained in:
parent
ee6e85ca83
commit
28b8123887
18 changed files with 370 additions and 1 deletions
|
@ -73,3 +73,4 @@ add_subdirectory_ifdef(CONFIG_BOARD_XENVM xen)
|
|||
add_subdirectory_ifdef(CONFIG_MM_DRV mm)
|
||||
add_subdirectory_ifdef(CONFIG_RESET reset)
|
||||
add_subdirectory_ifdef(CONFIG_COREDUMP_DEVICE coredump)
|
||||
add_subdirectory_ifdef(CONFIG_FUEL_GAUGE fuel_gauge)
|
||||
|
|
|
@ -149,4 +149,6 @@ source "drivers/coredump/Kconfig"
|
|||
|
||||
source "drivers/xen/Kconfig"
|
||||
|
||||
source "drivers/fuel_gauge/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
3
drivers/fuel_gauge/CMakeLists.txt
Normal file
3
drivers/fuel_gauge/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_SBS_GAUGE_NEW_API sbs_gauge)
|
18
drivers/fuel_gauge/Kconfig
Normal file
18
drivers/fuel_gauge/Kconfig
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Copyright 2022 Google LLC
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig FUEL_GAUGE
|
||||
bool "Battery fuel gauge drivers"
|
||||
help
|
||||
Enable battery fuel gauge driver configuration.
|
||||
|
||||
if FUEL_GAUGE
|
||||
|
||||
module = FUEL_GAUGE
|
||||
module-str = fuel_gauge
|
||||
source "subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
source "drivers/fuel_gauge/sbs_gauge/Kconfig"
|
||||
|
||||
endif # FUEL_GAUGE
|
3
drivers/fuel_gauge/sbs_gauge/CMakeLists.txt
Normal file
3
drivers/fuel_gauge/sbs_gauge/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
zephyr_library()
|
||||
|
||||
zephyr_library_sources(sbs_gauge.c)
|
10
drivers/fuel_gauge/sbs_gauge/Kconfig
Normal file
10
drivers/fuel_gauge/sbs_gauge/Kconfig
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Copyright (c) 2021 Leica Geosystems AG
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config SBS_GAUGE_NEW_API
|
||||
bool "Smart Battery Fuel Gauge"
|
||||
default y
|
||||
depends on DT_HAS_SBS_SBS_GAUGE_NEW_API_ENABLED
|
||||
select I2C
|
||||
help
|
||||
Enable I2C-based/SMBus-based driver for a Smart Battery Fuel Gauge.
|
138
drivers/fuel_gauge/sbs_gauge/sbs_gauge.c
Normal file
138
drivers/fuel_gauge/sbs_gauge/sbs_gauge.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Leica Geosystems AG
|
||||
*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT sbs_sbs_gauge_new_api
|
||||
|
||||
#include "sbs_gauge.h"
|
||||
|
||||
#include <zephyr/drivers/fuel_gauge.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
LOG_MODULE_REGISTER(sbs_gauge);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int sbs_gauge_get_prop(const struct device *dev, struct fuel_gauge_get_property *prop)
|
||||
{
|
||||
int rc = 0;
|
||||
uint16_t val = 0;
|
||||
|
||||
switch (prop->property_type) {
|
||||
case FUEL_GAUGE_AVG_CURRENT:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_AVG_CURRENT, &val);
|
||||
prop->value.avg_current = val * 1000;
|
||||
break;
|
||||
case FUEL_GAUGE_CYCLE_COUNT:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_CYCLE_COUNT, &val);
|
||||
prop->value.cycle_count = val;
|
||||
break;
|
||||
case FUEL_GAUGE_CURRENT:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_CURRENT, &val);
|
||||
prop->value.current = val * 1000;
|
||||
break;
|
||||
case FUEL_GAUGE_FULL_CHARGE_CAPACITY:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_FULL_CAPACITY, &val);
|
||||
prop->value.full_charge_capacity = val * 1000;
|
||||
break;
|
||||
case FUEL_GAUGE_REMAINING_CAPACITY:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_REM_CAPACITY, &val);
|
||||
prop->value.remaining_capacity = val * 1000;
|
||||
break;
|
||||
case FUEL_GAUGE_RUNTIME_TO_EMPTY:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_RUNTIME2EMPTY, &val);
|
||||
prop->value.runtime_to_empty = val;
|
||||
break;
|
||||
case FUEL_GAUGE_RUNTIME_TO_FULL:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_AVG_TIME2FULL, &val);
|
||||
prop->value.runtime_to_empty = val;
|
||||
break;
|
||||
case FUEL_GAUGE_STATE_OF_CHARGE:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_ASOC, &val);
|
||||
prop->value.state_of_charge = val;
|
||||
break;
|
||||
case FUEL_GAUGE_TEMPERATURE:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_TEMP, &val);
|
||||
prop->value.temperature = val;
|
||||
break;
|
||||
case FUEL_GAUGE_VOLTAGE:
|
||||
rc = sbs_cmd_reg_read(dev, SBS_GAUGE_CMD_VOLTAGE, &val);
|
||||
prop->value.voltage = val * 1000;
|
||||
break;
|
||||
default:
|
||||
rc = -ENOTSUP;
|
||||
}
|
||||
|
||||
prop->status = rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sbs_gauge_get_props(const struct device *dev, struct fuel_gauge_get_property *props,
|
||||
size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
ret |= sbs_gauge_get_prop(dev, props + i);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 battery_driver_api sbs_gauge_driver_api = {
|
||||
.get_property = &sbs_gauge_get_props,
|
||||
};
|
||||
|
||||
/* FIXME: fix init priority */
|
||||
#define SBS_GAUGE_INIT(index) \
|
||||
\
|
||||
static const struct sbs_gauge_config sbs_gauge_config_##index = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(index), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(index, &sbs_gauge_init, NULL, NULL, &sbs_gauge_config_##index, \
|
||||
POST_KERNEL, 90, &sbs_gauge_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(SBS_GAUGE_INIT)
|
54
drivers/fuel_gauge/sbs_gauge/sbs_gauge.h
Normal file
54
drivers/fuel_gauge/sbs_gauge/sbs_gauge.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <zephyr/drivers/i2c.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_DELAY 1000
|
||||
|
||||
struct sbs_gauge_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
};
|
||||
|
||||
#endif
|
5
dts/bindings/fuel-gauge/sbs,sbs-gauge-new-api.yaml
Normal file
5
dts/bindings/fuel-gauge/sbs,sbs-gauge-new-api.yaml
Normal file
|
@ -0,0 +1,5 @@
|
|||
description: SBS 1.1 compliant fuel gauge (http://www.sbs-forum.org/specs)
|
||||
|
||||
compatible: "sbs,sbs-gauge-new-api"
|
||||
|
||||
include: [i2c-device.yaml, fuel-gauge.yaml]
|
|
@ -6,9 +6,12 @@
|
|||
* Emulator for SBS 1.1 compliant smart battery fuel gauge.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FUEL_GAUGE
|
||||
#define DT_DRV_COMPAT sbs_sbs_gauge_new_api
|
||||
#else
|
||||
#define DT_DRV_COMPAT sbs_sbs_gauge
|
||||
#endif /* CONFIG_FUEL_GAUGE */
|
||||
|
||||
#define LOG_LEVEL CONFIG_SENSOR_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(sbs_sbs_gauge);
|
||||
|
||||
|
|
8
tests/drivers/fuel_gauge/sbs_gauge/CMakeLists.txt
Normal file
8
tests/drivers/fuel_gauge/sbs_gauge/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(device)
|
||||
|
||||
FILE(GLOB app_sources src/test_sbs_gauge.c)
|
||||
target_sources(app PRIVATE ${app_sources})
|
|
@ -0,0 +1,7 @@
|
|||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_EMUL=y
|
||||
CONFIG_EMUL_SBS_GAUGE=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_EMUL=y
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Leica Geosystems AG
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
&i2c0 {
|
||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
||||
smartbattery: sbs_gauge@b {
|
||||
compatible = "sbs,sbs-gauge-new-api";
|
||||
reg = <0x0B>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
CONFIG_EMUL=y
|
||||
CONFIG_EMUL_SBS_GAUGE=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_I2C_EMUL=y
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/dt-bindings/i2c/i2c.h>
|
||||
|
||||
/ {
|
||||
/* qemu_cortex_a9 board isn't configured with an I2C node */
|
||||
fake_i2c_bus: i2c@100 {
|
||||
status = "okay";
|
||||
compatible = "zephyr,i2c-emul-controller";
|
||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0x100 4>;
|
||||
};
|
||||
};
|
||||
|
||||
&fake_i2c_bus {
|
||||
clock-frequency = <I2C_BITRATE_STANDARD>;
|
||||
compatible = "zephyr,i2c-emul-controller";
|
||||
smartbattery0: smartbattery@b {
|
||||
compatible = "sbs,sbs-gauge-new-api";
|
||||
reg = <0x0B>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
7
tests/drivers/fuel_gauge/sbs_gauge/prj.conf
Normal file
7
tests/drivers/fuel_gauge/sbs_gauge/prj.conf
Normal file
|
@ -0,0 +1,7 @@
|
|||
CONFIG_ZTEST=y
|
||||
CONFIG_ZTEST_NEW_API=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_TEST_USERSPACE=y
|
||||
CONFIG_LOG=y
|
||||
|
||||
CONFIG_FUEL_GAUGE=y
|
49
tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c
Normal file
49
tests/drivers/fuel_gauge/sbs_gauge/src/test_sbs_gauge.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/fuel_gauge.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/ztest.h>
|
||||
#include <zephyr/ztest_assert.h>
|
||||
|
||||
struct sbs_gauge_new_api_fixture {
|
||||
const struct device *dev;
|
||||
const struct battery_driver_api *api;
|
||||
};
|
||||
|
||||
static void *sbs_gauge_new_api_setup(void)
|
||||
{
|
||||
|
||||
static struct sbs_gauge_new_api_fixture fixture;
|
||||
const struct device *dev = DEVICE_DT_GET_ANY(sbs_sbs_gauge_new_api);
|
||||
const struct battery_driver_api *api = dev->api;
|
||||
|
||||
fixture.dev = dev;
|
||||
fixture.api = api;
|
||||
|
||||
zassert_true(device_is_ready(fixture.dev), "Fuel Gauge not found");
|
||||
zassert_not_null(api);
|
||||
|
||||
return &fixture;
|
||||
}
|
||||
|
||||
ZTEST_F(sbs_gauge_new_api, test_implemented_apis)
|
||||
{
|
||||
zassert_not_equal(NULL, fixture->api->get_property);
|
||||
}
|
||||
|
||||
ZTEST_F(sbs_gauge_new_api, test_voltage_read)
|
||||
{
|
||||
struct fuel_gauge_get_property prop = {
|
||||
.property_type = FUEL_GAUGE_VOLTAGE,
|
||||
};
|
||||
zassert_ok(fixture->api->get_property(fixture->dev, &prop, 1));
|
||||
}
|
||||
|
||||
ZTEST_SUITE(sbs_gauge_new_api, NULL, sbs_gauge_new_api_setup, NULL, NULL, NULL);
|
11
tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml
Normal file
11
tests/drivers/fuel_gauge/sbs_gauge/testcase.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
tests:
|
||||
# section.subsection
|
||||
drivers.sbs_gauge_new_api:
|
||||
tags: test_framework
|
||||
filter: dt_compat_enabled("sbs,sbs-gauge-new-api")
|
||||
platform_allow:
|
||||
native_posix
|
||||
qemu_cortex_a9
|
||||
nucleo_f070rb
|
||||
integration_platforms:
|
||||
- nucleo_f070rb
|
Loading…
Add table
Add a link
Reference in a new issue