charger: add a driver for bq25180
Add a driver for the TI BQ25180. Implement enable/disable and current set/get. Signed-off-by: Fabio Baltieri <fabiobaltieri@google.com>
This commit is contained in:
parent
312e000a5f
commit
e517af4cff
|
@ -4,6 +4,7 @@ zephyr_library()
|
|||
zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ24190 charger_bq24190.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ25180 charger_bq25180.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_CHARGER_MAX20335 charger_max20335.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_SBS_CHARGER sbs_charger.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE charger_handlers.c)
|
||||
|
|
|
@ -21,6 +21,7 @@ config CHARGER_INIT_PRIORITY
|
|||
|
||||
source "drivers/charger/Kconfig.sbs_charger"
|
||||
source "drivers/charger/Kconfig.bq24190"
|
||||
source "drivers/charger/Kconfig.bq25180"
|
||||
source "drivers/charger/Kconfig.max20335"
|
||||
|
||||
endif # CHARGER
|
||||
|
|
11
drivers/charger/Kconfig.bq25180
Normal file
11
drivers/charger/Kconfig.bq25180
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Copyright 2024 Google LLC
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config CHARGER_BQ25180
|
||||
bool "BQ25180 Battery Charger"
|
||||
default y
|
||||
depends on DT_HAS_TI_BQ25180_ENABLED
|
||||
select I2C
|
||||
help
|
||||
Enable BQ25180 battery charger driver.
|
218
drivers/charger/charger_bq25180.c
Normal file
218
drivers/charger/charger_bq25180.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* BQ25180 Datasheet: https://www.ti.com/lit/gpn/bq25180
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT ti_bq25180
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/charger.h>
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
LOG_MODULE_REGISTER(bq25180, CONFIG_CHARGER_LOG_LEVEL);
|
||||
|
||||
#define BQ25180_STAT0 0x00
|
||||
#define BQ25180_STAT1 0x01
|
||||
#define BQ25180_FLAG0 0x02
|
||||
#define BQ25180_VBAT_CTRL 0x03
|
||||
#define BQ25180_ICHG_CTRL 0x04
|
||||
#define BQ25180_IC_CTRL 0x07
|
||||
#define BQ25180_SHIP_RST 0x09
|
||||
#define BQ25180_MASK_ID 0x0c
|
||||
|
||||
#define BQ25180_ICHG_CHG_DIS BIT(7)
|
||||
#define BQ25180_ICHG_MSK GENMASK(6, 0)
|
||||
#define BQ25180_WATCHDOG_SEL_1_MSK GENMASK(1, 0)
|
||||
#define BQ25180_WATCHDOG_DISABLE 0x03
|
||||
#define BQ25180_DEVICE_ID_MSK GENMASK(3, 0)
|
||||
#define BQ25180_DEVICE_ID 0x00
|
||||
#define BQ25180_SHIP_RST_EN_RST_SHIP_MSK GENMASK(6, 5)
|
||||
#define BQ25180_SHIP_RST_EN_RST_SHIP_ADAPTER 0x20
|
||||
#define BQ25180_SHIP_RST_EN_RST_SHIP_BUTTON 0x40
|
||||
|
||||
/* Charging current limits */
|
||||
#define BQ25180_CURRENT_MIN_MA 5
|
||||
#define BQ25180_CURRENT_MAX_MA 1000
|
||||
|
||||
struct bq25180_config {
|
||||
struct i2c_dt_spec i2c;
|
||||
uint32_t initial_current_microamp;
|
||||
};
|
||||
|
||||
/*
|
||||
* For ICHG <= 35mA = ICHGCODE + 5mA
|
||||
* For ICHG > 35mA = 40 + ((ICHGCODE-31)*10)mA.
|
||||
* Maximum programmable current = 1000mA
|
||||
*
|
||||
* Return: value between 0 and 127, negative on error.
|
||||
*/
|
||||
static int bq25180_ma_to_ichg(uint32_t current_ma, uint8_t *ichg)
|
||||
{
|
||||
if (!IN_RANGE(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA)) {
|
||||
LOG_WRN("charging current out of range: %dmA, "
|
||||
"clamping to the nearest limit", current_ma);
|
||||
}
|
||||
current_ma = CLAMP(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA);
|
||||
|
||||
if (current_ma <= 35) {
|
||||
*ichg = current_ma - 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ichg = (current_ma - 40) / 10 + 31;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t bq25180_ichg_to_ma(uint8_t ichg)
|
||||
{
|
||||
ichg &= BQ25180_ICHG_MSK;
|
||||
|
||||
if (ichg <= 30) {
|
||||
return (ichg + 5);
|
||||
}
|
||||
|
||||
return (ichg - 31) * 10 + 40;
|
||||
}
|
||||
|
||||
static int bq25183_charge_enable(const struct device *dev, const bool enable)
|
||||
{
|
||||
const struct bq25180_config *cfg = dev->config;
|
||||
uint8_t value = enable ? 0 : BQ25180_ICHG_CHG_DIS;
|
||||
int ret;
|
||||
|
||||
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL,
|
||||
BQ25180_ICHG_CHG_DIS, value);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq25180_set_charge_current(const struct device *dev,
|
||||
uint32_t const_charge_current_ua)
|
||||
{
|
||||
const struct bq25180_config *cfg = dev->config;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
ret = bq25180_ma_to_ichg(const_charge_current_ua / 1000, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL,
|
||||
BQ25180_ICHG_MSK, val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq25180_get_charge_current(const struct device *dev,
|
||||
uint32_t *const_charge_current_ua)
|
||||
{
|
||||
const struct bq25180_config *cfg = dev->config;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
*const_charge_current_ua = bq25180_ichg_to_ma(val) * 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq25180_get_prop(const struct device *dev, charger_prop_t prop,
|
||||
union charger_propval *val)
|
||||
{
|
||||
switch (prop) {
|
||||
case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA:
|
||||
return bq25180_get_charge_current(dev, &val->const_charge_current_ua);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static int bq25180_set_prop(const struct device *dev, charger_prop_t prop,
|
||||
const union charger_propval *val)
|
||||
{
|
||||
switch (prop) {
|
||||
case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA:
|
||||
return bq25180_set_charge_current(dev, val->const_charge_current_ua);
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct charger_driver_api bq25180_api = {
|
||||
.get_property = bq25180_get_prop,
|
||||
.set_property = bq25180_set_prop,
|
||||
.charge_enable = bq25183_charge_enable,
|
||||
};
|
||||
|
||||
static int bq25180_init(const struct device *dev)
|
||||
{
|
||||
const struct bq25180_config *cfg = dev->config;
|
||||
uint8_t val;
|
||||
int ret;
|
||||
|
||||
ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_MASK_ID, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
val &= BQ25180_DEVICE_ID_MSK;
|
||||
if (val != BQ25180_DEVICE_ID) {
|
||||
LOG_ERR("Invalid device id: %02x", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Disable the watchdog */
|
||||
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_IC_CTRL,
|
||||
BQ25180_WATCHDOG_SEL_1_MSK,
|
||||
BQ25180_WATCHDOG_DISABLE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cfg->initial_current_microamp > 0) {
|
||||
ret = bq25180_ma_to_ichg(cfg->initial_current_microamp / 1000, &val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL,
|
||||
BQ25180_ICHG_MSK, val);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CHARGER_BQ25180_INIT(inst) \
|
||||
static const struct bq25180_config bq25180_config_##inst = { \
|
||||
.i2c = I2C_DT_SPEC_INST_GET(inst), \
|
||||
.initial_current_microamp = DT_INST_PROP( \
|
||||
inst, constant_charge_current_max_microamp), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(inst, bq25180_init, NULL, NULL, \
|
||||
&bq25180_config_##inst, POST_KERNEL, \
|
||||
CONFIG_CHARGER_INIT_PRIORITY, \
|
||||
&bq25180_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(CHARGER_BQ25180_INIT)
|
30
dts/bindings/charger/ti,bq25180.yaml
Normal file
30
dts/bindings/charger/ti,bq25180.yaml
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Copyright 2024 Google LLC
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: |
|
||||
BQ25180 I2C Controlled, 1-Cell, 1-A Linear Battery Charger with Power Path
|
||||
and Ship Mode.
|
||||
|
||||
The device has a single child node for the charger. For example:
|
||||
|
||||
bq25180@6a {
|
||||
compatible = "ti,bq25180";
|
||||
reg = <0x6a>;
|
||||
|
||||
constant-charge-current-max-microamp = <500000>;
|
||||
};
|
||||
|
||||
compatible: "ti,bq25180"
|
||||
|
||||
include: [battery.yaml, i2c-device.yaml]
|
||||
|
||||
|
||||
properties:
|
||||
constant-charge-current-max-microamp:
|
||||
type: int
|
||||
default: 0
|
||||
description: |
|
||||
Charge current set at init time in uA, available range is 5 mA to 800 mA.
|
||||
The value specified will be rounded down to the closest implemented
|
||||
value. If set to 0 (default) skip setting the charge current value at
|
||||
driver initialization.
|
|
@ -28,3 +28,9 @@ max20335@1 {
|
|||
constant-charge-voltage-max-microvolt = <4050000>;
|
||||
};
|
||||
};
|
||||
|
||||
bq25180@2 {
|
||||
compatible = "ti,bq25180";
|
||||
reg = <0x2>;
|
||||
constant-charge-current-max-microamp = <500000>;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue