This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 910e6cbb9e6dfb0cf4563bb587a457332cd26be3 Author: Daniel P. Carvalho <[email protected]> AuthorDate: Wed Oct 21 08:58:57 2026 -0300 drivers/power: add an Analog Devices LTC4013 battery charger driver Add a lower-half driver for the Analog Devices LTC4013 multi-chemistry battery charger controller, on top of the battery charger interface (nuttx/power/battery_charger.h). The chip has no digital interface. The board provides callbacks to drive ENAB, to set the three-state MODE1 and MODE2 pins and to read STAT0 and STAT1, and describes the optional limits of the charge voltage in ltc4013_config_s. The application chooses the charge profile. BATIOC_OPERATE selects one of the nine algorithms of the MODE pin table of the datasheet (LTC4013_OPRTN_ALGO) and enables or disables the charger (BATIO_OPRTN_CHARGE). BATIOC_VOLTAGE sets the voltage of the last stage of the algorithm (the VFLOAT column of the table); the absorption and equalization voltages follow from the same feedback divider. BATIOC_STATE and BATIOC_HEALTH decode the status pins as in the datasheet. How the feedback network is programmed is left to the board, since it can be a digital potentiometer, a DAC or a fixed divider. The board provides an optional callback that receives the battery voltage and the regulation voltage of the FB pin of the selected algorithm and programs its network; it may refuse a voltage that it cannot reach. The driver refuses a voltage outside of the limits of the board instead of saturating it. Without the callback the divider is fixed by the hardware: BATIOC_VOLTAGE is not supported and, if the board gives the two resistors of the divider, BATIOC_GET_VOLTAGE reports the voltage that it programs with the algorithm. The charger is left disabled when it is registered, and when the voltage is set by the board it cannot be enabled until a voltage has been set. Changing the algorithm programs the same voltage again with the new regulation voltage of the FB pin and is refused with -EBUSY while the charger is enabled. The charge current and the input current are set by the hardware, so BATIOC_CURRENT and BATIOC_INPUT_CURRENT return -ENOSYS. Tested by compiling the driver (-Wall -Wextra), with nxstyle and checkpatch, and with a host program that stubs the battery charger upper half and the callbacks: voltage limits and refusal by the board, the new regulation voltage when the algorithm changes (including the restore when the mode pins fail), the decoding of the status pins for each kind of algorithm, a fixed divider with and without resistors and the validation of the configuration. Run on a custom STM32G474 board whose feedback divider is a MCP4561, with a bidirectional bench supply in place of the battery (no battery connected). Li-Ion wide spread at 13.8 V: constant current at 2.45 A, then constant voltage with the current falling to 0.13 A at 13.86 V. 3-stage normal with 13.2 V requested: absorption at 13.76 V (13.78 V expected, the float voltage times 2.367/2.267). Not tested on the board: the float stage and the BATTERY_FULL state, the time termination and the recharge. Assisted-by: Claude Code:claude-sonnet-5-5 Signed-off-by: Daniel P. Carvalho <[email protected]> --- drivers/power/battery/CMakeLists.txt | 6 + drivers/power/battery/Kconfig | 11 + drivers/power/battery/Make.defs | 6 + drivers/power/battery/ltc4013.c | 544 +++++++++++++++++++++++++++++++++++ include/nuttx/power/ltc4013.h | 213 ++++++++++++++ 5 files changed, 780 insertions(+) diff --git a/drivers/power/battery/CMakeLists.txt b/drivers/power/battery/CMakeLists.txt index 41d8bee7382..ce8d9a0e50b 100644 --- a/drivers/power/battery/CMakeLists.txt +++ b/drivers/power/battery/CMakeLists.txt @@ -36,6 +36,12 @@ if(CONFIG_BATTERY_CHARGER) list(APPEND SRCS mcp73871.c) endif() + # Add the LTC4013 battery charger driver + + if(CONFIG_LTC4013) + list(APPEND SRCS ltc4013.c) + endif() + # Add the BQ2425x I2C-based battery charger driver if(CONFIG_I2C_BQ2425X) diff --git a/drivers/power/battery/Kconfig b/drivers/power/battery/Kconfig index fd1a47a1f04..a77b3c0cad9 100644 --- a/drivers/power/battery/Kconfig +++ b/drivers/power/battery/Kconfig @@ -124,6 +124,17 @@ config MCP73871 ---help--- A simple driver to report MCP73871 status. +config LTC4013 + bool "Analog Devices LTC4013 Battery charger support" + default n + depends on BATTERY_CHARGER + ---help--- + Lower half driver for the LTC4013 multi-chemistry battery charger + controller. The chip has no digital interface: the driver enables + it, sets its charge algorithm and reads its status through board + callbacks. The charge voltage is set by a board callback that + programs the feedback network, or it is fixed by the hardware. + config BATTERY_GAUGE bool "Battery Fuel Gauge support" default n diff --git a/drivers/power/battery/Make.defs b/drivers/power/battery/Make.defs index 8cc0b6f2d7e..7be635c8448 100644 --- a/drivers/power/battery/Make.defs +++ b/drivers/power/battery/Make.defs @@ -32,6 +32,12 @@ ifeq ($(CONFIG_MCP73871),y) CSRCS += mcp73871.c endif +# Add the LTC4013 battery charger driver + +ifeq ($(CONFIG_LTC4013),y) +CSRCS += ltc4013.c +endif + # Add the BQ2425x I2C-based battery charger driver ifeq ($(CONFIG_I2C_BQ2425X),y) diff --git a/drivers/power/battery/ltc4013.c b/drivers/power/battery/ltc4013.c new file mode 100644 index 00000000000..e32d135b72c --- /dev/null +++ b/drivers/power/battery/ltc4013.c @@ -0,0 +1,544 @@ +/**************************************************************************** + * drivers/power/battery/ltc4013.c + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Lower half driver for the Analog Devices LTC4013 battery charger + * controller. The chip is controlled through pins that the board + * provides and the charge voltage is set by the feedback network of the + * board, see include/nuttx/power/ltc4013.h. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> + +#include <stdbool.h> +#include <stdint.h> +#include <errno.h> + +#include <nuttx/debug.h> +#include <nuttx/kmalloc.h> +#include <nuttx/power/battery_charger.h> +#include <nuttx/power/battery_ioctl.h> +#include <nuttx/power/ltc4013.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Highest Vfb of Table 1 of the datasheet, in mV */ + +#define LTC4013_VFB_MAX_MV 2400 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* A charge algorithm of Table 1 of the datasheet */ + +struct ltc4013_algo_s +{ + enum ltc4013_level_e mode1; + enum ltc4013_level_e mode2; + bool staged; /* 3 or 4 stages, STAT1 on means float */ + uint16_t vfb_mv; /* Vfb of the VFLOAT column, mV */ +}; + +struct ltc4013_dev_s +{ + /* The common part of the battery driver visible to the upper half, + * it must be the first field. + */ + + struct battery_charger_dev_s dev; + + struct ltc4013_config_s config; /* Board configuration */ + int mv; /* Voltage requested, 0 if none */ + bool enabled; /* The charger is enabled */ + enum ltc4013_algo_e algo; /* Selected algorithm */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int ltc4013_state(FAR struct battery_charger_dev_s *dev, + FAR int *status); +static int ltc4013_health(FAR struct battery_charger_dev_s *dev, + FAR int *health); +static int ltc4013_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status); +static int ltc4013_voltage(FAR struct battery_charger_dev_s *dev, + int value); +static int ltc4013_current(FAR struct battery_charger_dev_s *dev, + int value); +static int ltc4013_input_current(FAR struct battery_charger_dev_s *dev, + int value); +static int ltc4013_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param); +static int ltc4013_chipid(FAR struct battery_charger_dev_s *dev, + FAR unsigned int *value); +static int ltc4013_get_voltage(FAR struct battery_charger_dev_s *dev, + FAR int *value); +static int ltc4013_voltage_info(FAR struct battery_charger_dev_s *dev, + FAR int *value); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct battery_charger_operations_s g_ltc4013ops = +{ + ltc4013_state, + ltc4013_health, + ltc4013_online, + ltc4013_voltage, + ltc4013_current, + ltc4013_input_current, + ltc4013_operate, + ltc4013_chipid, + ltc4013_get_voltage, + ltc4013_voltage_info, + NULL +}; + +/* Table 1 of the datasheet, in the order of enum ltc4013_algo_e */ + +static const struct ltc4013_algo_s g_algos[LTC4013_ALGO_NALGOS] = +{ + { LTC4013_LEVEL_HIGH, LTC4013_LEVEL_FLOAT, false, 2367 }, + { LTC4013_LEVEL_FLOAT, LTC4013_LEVEL_FLOAT, false, LTC4013_VFB_MAX_MV }, + { LTC4013_LEVEL_LOW, LTC4013_LEVEL_LOW, false, 2267 }, + { LTC4013_LEVEL_LOW, LTC4013_LEVEL_FLOAT, false, 2333 }, + { LTC4013_LEVEL_HIGH, LTC4013_LEVEL_LOW, true, 2267 }, + { LTC4013_LEVEL_FLOAT, LTC4013_LEVEL_LOW, true, 2200 }, + { LTC4013_LEVEL_LOW, LTC4013_LEVEL_HIGH, true, 2267 }, + { LTC4013_LEVEL_HIGH, LTC4013_LEVEL_HIGH, true, 2267 }, + { LTC4013_LEVEL_FLOAT, LTC4013_LEVEL_HIGH, true, 2200 } +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ltc4013_apply_mode + * + * Description: + * Set the MODE pins for an algorithm. + * + ****************************************************************************/ + +static int ltc4013_apply_mode(FAR struct ltc4013_dev_s *priv, + enum ltc4013_algo_e algo) +{ + return priv->config.mode(priv->config.arg, g_algos[algo].mode1, + g_algos[algo].mode2); +} + +/**************************************************************************** + * Name: ltc4013_state + * + * Description: + * Return the current battery state from Table 2 of the datasheet. + * + ****************************************************************************/ + +static int ltc4013_state(FAR struct battery_charger_dev_s *dev, + FAR int *status) +{ + FAR struct ltc4013_dev_s *priv = (FAR struct ltc4013_dev_s *)dev; + bool stat0; + bool stat1; + int ret; + + ret = priv->config.stat(priv->config.arg, &stat0, &stat1); + if (ret < 0) + { + return ret; + } + + if (stat0 && stat1) + { + /* Constant voltage for the Li-Ion and 2-stage algorithms, float + * charging for the 3 and 4-stage ones. + */ + + *status = g_algos[priv->algo].staged ? BATTERY_FULL : + BATTERY_CHARGING; + } + else if (stat0) + { + *status = BATTERY_CHARGING; + } + else if (stat1) + { + *status = BATTERY_FAULT; + } + else + { + *status = BATTERY_IDLE; + } + + return OK; +} + +/**************************************************************************** + * Name: ltc4013_health + * + * Description: + * Return the current battery health. The chip signals a low battery + * or a thermal shutdown with the same pattern, so it is not possible to + * tell them apart. + * + ****************************************************************************/ + +static int ltc4013_health(FAR struct battery_charger_dev_s *dev, + FAR int *health) +{ + int status; + int ret; + + ret = ltc4013_state(dev, &status); + if (ret < 0) + { + return ret; + } + + *health = status == BATTERY_FAULT ? BATTERY_HEALTH_UNSPEC_FAIL : + BATTERY_HEALTH_GOOD; + return OK; +} + +/**************************************************************************** + * Name: ltc4013_online + * + * Description: + * The chip cannot tell if a battery is connected: report whether the + * charger is enabled. + * + ****************************************************************************/ + +static int ltc4013_online(FAR struct battery_charger_dev_s *dev, + FAR bool *status) +{ + FAR struct ltc4013_dev_s *priv = (FAR struct ltc4013_dev_s *)dev; + + *status = priv->enabled; + return OK; +} + +/**************************************************************************** + * Name: ltc4013_voltage + * + * Description: + * Set the charge voltage, in mV, of the selected algorithm. The board + * programs its feedback network. + * + ****************************************************************************/ + +static int ltc4013_voltage(FAR struct battery_charger_dev_s *dev, + int value) +{ + FAR struct ltc4013_dev_s *priv = (FAR struct ltc4013_dev_s *)dev; + FAR const struct ltc4013_config_s *cfg = &priv->config; + int ret; + + if (cfg->voltage == NULL) + { + return -ENOSYS; + } + + if (value <= 0 || (cfg->v_min > 0 && value < cfg->v_min) || + (cfg->v_max > 0 && value > cfg->v_max)) + { + return -EINVAL; + } + + ret = cfg->voltage(cfg->arg, value, g_algos[priv->algo].vfb_mv); + if (ret < 0) + { + return ret; + } + + priv->mv = value; + return OK; +} + +/**************************************************************************** + * Name: ltc4013_current + * + * Description: + * The charge current is set by the sense resistor. + * + ****************************************************************************/ + +static int ltc4013_current(FAR struct battery_charger_dev_s *dev, + int value) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: ltc4013_input_current + ****************************************************************************/ + +static int ltc4013_input_current(FAR struct battery_charger_dev_s *dev, + int value) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: ltc4013_enable + * + * Description: + * Enable or disable the charger. When the voltage is set by software, + * enabling is refused until a voltage has been programmed. + * + ****************************************************************************/ + +static int ltc4013_enable(FAR struct ltc4013_dev_s *priv, bool enable) +{ + int ret; + + if (enable && priv->config.voltage != NULL && priv->mv == 0) + { + return -EINVAL; + } + + ret = priv->config.enable(priv->config.arg, enable); + if (ret < 0) + { + return ret; + } + + priv->enabled = enable; + return OK; +} + +/**************************************************************************** + * Name: ltc4013_set_algo + * + * Description: + * Select an algorithm. If a voltage has been requested the board + * programs it again with the new regulation voltage of the FB pin, so the + * voltage stays the same. + * + ****************************************************************************/ + +static int ltc4013_set_algo(FAR struct ltc4013_dev_s *priv, + enum ltc4013_algo_e algo) +{ + FAR const struct ltc4013_config_s *cfg = &priv->config; + int ret; + + if ((unsigned int)algo >= LTC4013_ALGO_NALGOS) + { + return -EINVAL; + } + + if (priv->enabled) + { + return -EBUSY; + } + + if (priv->mv > 0) + { + ret = cfg->voltage(cfg->arg, priv->mv, g_algos[algo].vfb_mv); + if (ret < 0) + { + return ret; + } + } + + ret = ltc4013_apply_mode(priv, algo); + if (ret < 0) + { + if (priv->mv > 0) + { + cfg->voltage(cfg->arg, priv->mv, g_algos[priv->algo].vfb_mv); + } + + return ret; + } + + priv->algo = algo; + return OK; +} + +/**************************************************************************** + * Name: ltc4013_operate + ****************************************************************************/ + +static int ltc4013_operate(FAR struct battery_charger_dev_s *dev, + uintptr_t param) +{ + FAR struct ltc4013_dev_s *priv = (FAR struct ltc4013_dev_s *)dev; + FAR struct batio_operate_msg_s *msg = + (FAR struct batio_operate_msg_s *)param; + + switch (msg->operate_type) + { + case BATIO_OPRTN_CHARGE: + return ltc4013_enable(priv, msg->u8[0] != 0); + + case LTC4013_OPRTN_ALGO: + return ltc4013_set_algo(priv, (enum ltc4013_algo_e)msg->u8[0]); + + default: + return -ENOSYS; + } +} + +/**************************************************************************** + * Name: ltc4013_chipid + * + * Description: + * The chip has no digital interface to read an id from. + * + ****************************************************************************/ + +static int ltc4013_chipid(FAR struct battery_charger_dev_s *dev, + FAR unsigned int *value) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Name: ltc4013_get_voltage + * + * Description: + * Return the charge voltage, in mV: the one last requested when the + * board sets it, or the one that a fixed divider programs with the + * selected algorithm. This is the setpoint of the algorithm, not a + * measurement of the battery. + * + ****************************************************************************/ + +static int ltc4013_get_voltage(FAR struct battery_charger_dev_s *dev, + FAR int *value) +{ + FAR struct ltc4013_dev_s *priv = (FAR struct ltc4013_dev_s *)dev; + FAR const struct ltc4013_config_s *cfg = &priv->config; + + if (cfg->voltage != NULL) + { + if (priv->mv == 0) + { + return -ENODATA; + } + + *value = priv->mv; + return OK; + } + + if (cfg->r_bottom == 0) + { + return -ENODATA; + } + + *value = ((cfg->r_top + cfg->r_bottom) * g_algos[priv->algo].vfb_mv + + cfg->r_bottom / 2) / cfg->r_bottom; + return OK; +} + +/**************************************************************************** + * Name: ltc4013_voltage_info + ****************************************************************************/ + +static int ltc4013_voltage_info(FAR struct battery_charger_dev_s *dev, + FAR int *value) +{ + return -ENOSYS; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ltc4013_register + ****************************************************************************/ + +int ltc4013_register(FAR const char *devpath, + FAR const struct ltc4013_config_s *config) +{ + FAR struct ltc4013_dev_s *priv; + int ret; + + if (devpath == NULL || config == NULL || config->enable == NULL || + config->mode == NULL || config->stat == NULL || + (unsigned int)config->algo >= LTC4013_ALGO_NALGOS) + { + return -EINVAL; + } + + /* The report of the fixed divider is computed in 32 bits: the divider + * must stay below 1.7 Mohm. + */ + + if (config->voltage == NULL && config->r_bottom > 0 && + (uint64_t)config->r_top + config->r_bottom > + UINT32_MAX / LTC4013_VFB_MAX_MV) + { + return -EINVAL; + } + + priv = kmm_zalloc(sizeof(struct ltc4013_dev_s)); + if (priv == NULL) + { + return -ENOMEM; + } + + priv->dev.ops = &g_ltc4013ops; + priv->config = *config; + priv->algo = config->algo; + + /* Start with the charger disabled and the mode pins set */ + + ret = config->enable(config->arg, false); + if (ret < 0) + { + goto errout_free; + } + + ret = ltc4013_apply_mode(priv, priv->algo); + if (ret < 0) + { + goto errout_free; + } + + ret = battery_charger_register(devpath, &priv->dev); + if (ret < 0) + { + goto errout_free; + } + + return OK; + +errout_free: + kmm_free(priv); + return ret; +} diff --git a/include/nuttx/power/ltc4013.h b/include/nuttx/power/ltc4013.h new file mode 100644 index 00000000000..b2d4879f0c5 --- /dev/null +++ b/include/nuttx/power/ltc4013.h @@ -0,0 +1,213 @@ +/**************************************************************************** + * include/nuttx/power/ltc4013.h + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_POWER_LTC4013_H +#define __INCLUDE_NUTTX_POWER_LTC4013_H + +/* Lower half driver for the Analog Devices LTC4013 multi-chemistry battery + * charger controller, on top of the battery charger upper half + * (include/nuttx/power/battery_charger.h). + * + * The LTC4013 has no digital interface. The board wires its pins as + * follows and provides the access to them through the callbacks of + * struct ltc4013_config_s: + * + * ENAB Enable (also usable as an input UVLO). + * MODE1, MODE2 Three-state pins that select the charge algorithm + * (Table 1 of the datasheet): low, high or floating. + * STAT0, STAT1 Open drain status outputs (Table 2 of the datasheet). + * FB Feedback of the battery voltage. The divider from the + * battery to FB sets the charge voltage. + * + * The application chooses the charge profile: it selects the algorithm + * with BATIOC_OPERATE (LTC4013_OPRTN_ALGO) and the voltage with + * BATIOC_VOLTAGE. The voltage is the one of the VFLOAT column of Table 1, + * the voltage of the last stage of the algorithm (for the Li-Ion + * algorithms it is the charge voltage). The absorption and the + * equalization voltages follow from the same divider, in the proportions + * of the datasheet. The charge current is set by the sense resistor of the + * board and the input current by its input stage, so BATIOC_CURRENT and + * BATIOC_INPUT_CURRENT are not supported. + * + * How the voltage is programmed depends on the board. If the board + * provides the voltage callback, it programs its own feedback network (a + * digital potentiometer, a DAC, ...) for a battery voltage and the + * regulation voltage of the FB pin that the driver passes, and the voltage + * is set by software. Without it the divider is fixed by the hardware: + * BATIOC_VOLTAGE is not supported, and if the board gives the two + * resistors of the divider (r_top from the battery to FB and r_bottom from + * FB to ground) BATIOC_GET_VOLTAGE reports the voltage that it programs + * with the selected algorithm. + * + * The driver drives ENAB low when it registers. When the voltage is set by + * software the charger cannot be enabled until a voltage has been set. + * Changing the algorithm is refused while the charger is enabled, since + * the regulation voltage of the FB pin changes with it; the driver then + * programs the same battery voltage again, with the new regulation voltage. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +#include <stdbool.h> +#include <stdint.h> + +#ifdef CONFIG_LTC4013 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Device specific operation of BATIOC_OPERATE. The values from 0x80 on + * are reserved for the lower half drivers. + * + * LTC4013_OPRTN_ALGO - Select the charge algorithm. + * batio_operate_msg_s.u8[0] holds an enum ltc4013_algo_e. + * + * The common BATIO_OPRTN_CHARGE is supported too: u8[0] is nonzero to + * enable the charger and zero to disable it. + */ + +#define LTC4013_OPRTN_ALGO 0x80 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Charge algorithms, the rows of Table 1 of the datasheet. The Li-Ion + * and the 2-stage algorithms have no absorption stage. "Wide" is the + * wide voltage spread: the absorption (and the equalization) voltage + * is further above the float voltage. + */ + +enum ltc4013_algo_e +{ + LTC4013_ALGO_LIION_NORMAL = 0, /* MODE1 H, MODE2 M: Vfb 2.367 V */ + LTC4013_ALGO_LIION_WIDE, /* MODE1 M, MODE2 M: Vfb 2.400 V */ + LTC4013_ALGO_2STAGE, /* MODE1 L, MODE2 L: Vfb 2.267 V */ + LTC4013_ALGO_2STAGE_HIGH, /* MODE1 L, MODE2 M: Vfb 2.333 V */ + LTC4013_ALGO_3STAGE_NORMAL, /* MODE1 H, MODE2 L: float 2.267 V */ + LTC4013_ALGO_3STAGE_WIDE, /* MODE1 M, MODE2 L: float 2.200 V */ + LTC4013_ALGO_4STAGE_NORMAL_T4, /* MODE1 L, MODE2 H: tEQ = tEOC / 4 */ + LTC4013_ALGO_4STAGE_NORMAL, /* MODE1 H, MODE2 H: tEQ = tEOC / 8 */ + LTC4013_ALGO_4STAGE_WIDE, /* MODE1 M, MODE2 H: float 2.200 V */ + LTC4013_ALGO_NALGOS +}; + +/* Level of a MODE pin */ + +enum ltc4013_level_e +{ + LTC4013_LEVEL_LOW = 0, /* Driven low */ + LTC4013_LEVEL_HIGH, /* Driven high, at least 2.5 V */ + LTC4013_LEVEL_FLOAT /* High impedance, the chip biases it */ +}; + +/* Board configuration */ + +struct ltc4013_config_s +{ + /* Programs the feedback network for a battery voltage of mv millivolts, + * when the regulation voltage of the FB pin is vfb_mv millivolts. It + * returns a negated errno value, for example -EINVAL if the network + * cannot reach the voltage, and then it must leave the hardware as it + * was. It is called again with the same voltage and the new Vfb when + * the algorithm changes. Optional: without it the voltage is fixed by + * the hardware. + */ + + CODE int (*voltage)(FAR void *arg, int mv, int vfb_mv); + + /* Fixed divider, in ohms: r_top between the battery and FB and r_bottom + * between FB and ground. Optional, only used without the voltage + * callback to report the voltage in BATIOC_GET_VOLTAGE; 0 for r_bottom + * if it is not known. The sum of the two must stay below 1.7 Mohm. + */ + + uint32_t r_top; + uint32_t r_bottom; + + /* Limits of the voltage that the application may request, in mV, 0 for + * none. They apply to the voltage callback; set them from the battery of + * the board (cells and chemistry). + */ + + int v_min; + int v_max; + + /* Algorithm selected when the charger is registered */ + + enum ltc4013_algo_e algo; + + /* Pin access, all required. They are called from the context of the + * caller of the upper half, never from an interrupt. + * + * enable - Drive ENAB: true enables the charger. + * mode - Set MODE1 and MODE2. + * stat - Read STAT0 and STAT1: true when the pin is pulled low (ON in + * Table 2 of the datasheet). + */ + + CODE int (*enable)(FAR void *arg, bool enable); + CODE int (*mode)(FAR void *arg, enum ltc4013_level_e mode1, + enum ltc4013_level_e mode2); + CODE int (*stat)(FAR void *arg, FAR bool *stat0, FAR bool *stat1); + FAR void *arg; /* Argument of the callbacks */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Name: ltc4013_register + * + * Description: + * Register a LTC4013 as a battery charger. The charger is left + * disabled with the algorithm of the configuration; the application sets + * the voltage and enables it. + * + * Input Parameters: + * devpath - Device path, for example "/dev/bat0". + * config - Board configuration. The structure is copied. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int ltc4013_register(FAR const char *devpath, + FAR const struct ltc4013_config_s *config); + +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_LTC4013 */ +#endif /* __INCLUDE_NUTTX_POWER_LTC4013_H */
