Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Charging Subsystem #56666

Merged
merged 3 commits into from Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/develop/api/overview.rst
Expand Up @@ -53,6 +53,10 @@ between major releases are available in the :ref:`zephyr_release_notes`.
- Stable
- 1.14

* - :ref:`charger_api`
- Experimental
- 3.5

* - :ref:`counter_api`
- Unstable
- 1.14
Expand Down
29 changes: 29 additions & 0 deletions doc/hardware/peripherals/charger.rst
@@ -0,0 +1,29 @@
.. _charger_api:

Chargers
########

The charger subsystem exposes an API to uniformly access battery charger devices. Currently,
only reading data is supported.

Basic Operation
***************

Properties
==========

Fundamentally, a property is a configurable setting, state, or quantity that a charger device can
measure.

Chargers typically support multiple properties, such as temperature readings of the battery-pack
or present-time current/voltage.

Properties are fetched using a client allocated array of :c:struct:`charger_get_property`. This
array is then populated by values as according to its `property_type` field.

.. _charger_api_reference:

API Reference
*************

.. doxygengroup:: charger_interface
1 change: 1 addition & 0 deletions doc/hardware/peripherals/index.rst
Expand Up @@ -17,6 +17,7 @@ Peripherals
bc12.rst
clock_control.rst
canbus/index.rst
charger.rst
coredump.rst
counter.rst
dac.rst
Expand Down
1 change: 1 addition & 0 deletions drivers/CMakeLists.txt
Expand Up @@ -17,6 +17,7 @@ add_subdirectory_ifdef(CONFIG_BT_DRIVERS bluetooth)
add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache)
add_subdirectory_ifdef(CONFIG_CAN can)
add_subdirectory_ifdef(CONFIG_CLOCK_CONTROL clock_control)
add_subdirectory_ifdef(CONFIG_CHARGER charger)
add_subdirectory_ifdef(CONFIG_CONSOLE console)
add_subdirectory_ifdef(CONFIG_COREDUMP_DEVICE coredump)
add_subdirectory_ifdef(CONFIG_COUNTER counter)
Expand Down
1 change: 1 addition & 0 deletions drivers/Kconfig
Expand Up @@ -12,6 +12,7 @@ source "drivers/bbram/Kconfig"
source "drivers/bluetooth/Kconfig"
source "drivers/cache/Kconfig"
source "drivers/can/Kconfig"
source "drivers/charger/Kconfig"
rriveramcrus marked this conversation as resolved.
Show resolved Hide resolved
source "drivers/clock_control/Kconfig"
source "drivers/console/Kconfig"
source "drivers/coredump/Kconfig"
Expand Down
8 changes: 8 additions & 0 deletions drivers/charger/CMakeLists.txt
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_library()
zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h)

zephyr_library_sources_ifdef(CONFIG_SBS_CHARGER sbs_charger.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE charger_handlers.c)
zephyr_library_sources_ifdef(CONFIG_EMUL_SBS_CHARGER emul_sbs_charger.c)
24 changes: 24 additions & 0 deletions drivers/charger/Kconfig
@@ -0,0 +1,24 @@
# Copyright 2023 Cirrus Logic, Inc.
#
# SPDX-License-Identifier: Apache-2.0

menuconfig CHARGER
bool "Battery charger drivers"
help
Enable battery charger driver configuration.

if CHARGER

module = CHARGER
module-str = charger
source "subsys/logging/Kconfig.template.log_config"

rriveramcrus marked this conversation as resolved.
Show resolved Hide resolved
config CHARGER_INIT_PRIORITY
int "Battery charger init priority"
default 90
help
Battery charger initialization priority.

source "drivers/charger/Kconfig.sbs_charger"

endif # CHARGER
19 changes: 19 additions & 0 deletions drivers/charger/Kconfig.sbs_charger
@@ -0,0 +1,19 @@
# Copyright 2023 Cirrus Logic, Inc.
# SPDX-License-Identifier: Apache-2.0

config SBS_CHARGER
bool "Smart Battery Charger"
default y
depends on DT_HAS_SBS_SBS_CHARGER_ENABLED
select I2C
help
Enable I2C-based/SMBus-based driver for a Smart Battery Charger.

config EMUL_SBS_CHARGER
bool "Emulate an SBS 1.1 compliant smart battery charger"
default y
depends on EMUL
depends on SBS_CHARGER
help
It provides reading which follow a simple sequence, thus allowing
test code to check that things are working as expected.
38 changes: 38 additions & 0 deletions drivers/charger/charger_handlers.c
@@ -0,0 +1,38 @@
/*
* Copyright 2023 Cirrus Logic, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/syscall_handler.h>
#include <zephyr/drivers/charger.h>

static inline int z_vrfy_charger_get_prop(const struct device *dev, const charger_prop_t prop,
union charger_propval *val)
{
union charger_propval k_val;

Z_OOPS(Z_SYSCALL_DRIVER_CHARGER(dev, get_property));

int ret = z_impl_charger_get_prop(dev, prop, &k_val);

Z_OOPS(z_user_to_copy(val, &k_val, sizeof(union charger_propval)));

return ret;
}

#include <syscalls/charger_get_prop_mrsh.c>

static inline int z_vrfy_charger_set_prop(const struct device *dev, const charger_prop_t prop,
const union charger_propval *val)
{
union charger_propval k_val;

Z_OOPS(Z_SYSCALL_DRIVER_CHARGER(dev, set_property));

Z_OOPS(z_user_from_copy(&k_val, val, sizeof(union charger_propval)));

return z_impl_charger_set_prop(dev, prop, &k_val);
}

#include <syscalls/charger_set_prop_mrsh.c>
141 changes: 141 additions & 0 deletions drivers/charger/emul_sbs_charger.c
@@ -0,0 +1,141 @@
/*
* Copyright 2023 Cirrus Logic, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
* Emulator for SBS 1.1 compliant smart battery charger.
*/

#define DT_DRV_COMPAT sbs_sbs_charger

#include <zephyr/device.h>
#include <zephyr/drivers/emul.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/i2c_emul.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/byteorder.h>

#include "sbs_charger.h"

LOG_MODULE_REGISTER(sbs_sbs_charger);

/** Static configuration for the emulator */
struct sbs_charger_emul_cfg {
/** I2C address of emulator */
uint16_t addr;
};

static int emul_sbs_charger_reg_write(const struct emul *target, int reg, int val)
{
LOG_INF("write %x = %x", reg, val);
switch (reg) {
default:
LOG_ERR("Unknown write %x", reg);
return -EIO;
}

return 0;
}

static int emul_sbs_charger_reg_read(const struct emul *target, int reg, int *val)
{
switch (reg) {
case SBS_CHARGER_REG_SPEC_INFO:
case SBS_CHARGER_REG_CHARGER_MODE:
case SBS_CHARGER_REG_STATUS:
case SBS_CHARGER_REG_ALARM_WARNING:
/* Arbitrary stub value. */
*val = 1;
break;
default:
LOG_ERR("Unknown register 0x%x read", reg);
return -EIO;
}
LOG_INF("read 0x%x = 0x%x", reg, *val);

return 0;
}

static int sbs_charger_emul_transfer_i2c(const struct emul *target, struct i2c_msg *msgs,
int num_msgs, int addr)
{
/* Largely copied from emul_sbs_gauge.c */
struct sbs_charger_emul_data *data;
unsigned int val;
int reg;
int rc;

data = target->data;

i2c_dump_msgs_rw("emul", msgs, num_msgs, addr, false);
switch (num_msgs) {
case 2:
if (msgs->flags & I2C_MSG_READ) {
LOG_ERR("Unexpected read");
return -EIO;
}
if (msgs->len != 1) {
LOG_ERR("Unexpected msg0 length %d", msgs->len);
return -EIO;
}
reg = msgs->buf[0];

/* Now process the 'read' part of the message */
msgs++;
if (msgs->flags & I2C_MSG_READ) {
switch (msgs->len - 1) {
case 1:
rc = emul_sbs_charger_reg_read(target, reg, &val);
if (rc) {
/* Return before writing bad value to message buffer */
return rc;
}

/* SBS uses SMBus, which sends data in little-endian format. */
sys_put_le16(val, msgs->buf);
henrikbrixandersen marked this conversation as resolved.
Show resolved Hide resolved
break;
default:
LOG_ERR("Unexpected msg1 length %d", msgs->len);
return -EIO;
}
} else {
/* We write a word (2 bytes by the SBS spec) */
if (msgs->len != 2) {
LOG_ERR("Unexpected msg1 length %d", msgs->len);
}
uint16_t value = sys_get_le16(msgs->buf);

rc = emul_sbs_charger_reg_write(target, reg, value);
}
break;
default:
LOG_ERR("Invalid number of messages: %d", num_msgs);
return -EIO;
}

return rc;
}

static const struct i2c_emul_api sbs_charger_emul_api_i2c = {
.transfer = sbs_charger_emul_transfer_i2c,
};

static int emul_sbs_sbs_charger_init(const struct emul *target, const struct device *parent)
{
ARG_UNUSED(target);
ARG_UNUSED(parent);

return 0;
}

/*
* Main instantiation macro. SBS Charger Emulator only implemented for I2C
*/
#define SBS_CHARGER_EMUL(n) \
static const struct sbs_charger_emul_cfg sbs_charger_emul_cfg_##n = { \
.addr = DT_INST_REG_ADDR(n), \
}; \
EMUL_DT_INST_DEFINE(n, emul_sbs_sbs_charger_init, NULL, &sbs_charger_emul_cfg_##n, \
&sbs_charger_emul_api_i2c, NULL)

DT_INST_FOREACH_STATUS_OKAY(SBS_CHARGER_EMUL)