From e517af4cff25c27deedfbd40f472b209f2f8621b Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Sun, 6 Aug 2023 23:33:37 +0100 Subject: [PATCH] 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 --- drivers/charger/CMakeLists.txt | 1 + drivers/charger/Kconfig | 1 + drivers/charger/Kconfig.bq25180 | 11 ++ drivers/charger/charger_bq25180.c | 218 +++++++++++++++++++++++ dts/bindings/charger/ti,bq25180.yaml | 30 ++++ tests/drivers/build_all/charger/i2c.dtsi | 6 + 6 files changed, 267 insertions(+) create mode 100644 drivers/charger/Kconfig.bq25180 create mode 100644 drivers/charger/charger_bq25180.c create mode 100644 dts/bindings/charger/ti,bq25180.yaml diff --git a/drivers/charger/CMakeLists.txt b/drivers/charger/CMakeLists.txt index ce70f0590c6..60b80b0ed25 100644 --- a/drivers/charger/CMakeLists.txt +++ b/drivers/charger/CMakeLists.txt @@ -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) diff --git a/drivers/charger/Kconfig b/drivers/charger/Kconfig index 9c7873168a5..ce2c3d8b8d3 100644 --- a/drivers/charger/Kconfig +++ b/drivers/charger/Kconfig @@ -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 diff --git a/drivers/charger/Kconfig.bq25180 b/drivers/charger/Kconfig.bq25180 new file mode 100644 index 00000000000..44bdc9b32ee --- /dev/null +++ b/drivers/charger/Kconfig.bq25180 @@ -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. diff --git a/drivers/charger/charger_bq25180.c b/drivers/charger/charger_bq25180.c new file mode 100644 index 00000000000..7063377c589 --- /dev/null +++ b/drivers/charger/charger_bq25180.c @@ -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 +#include +#include +#include +#include +#include + +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) diff --git a/dts/bindings/charger/ti,bq25180.yaml b/dts/bindings/charger/ti,bq25180.yaml new file mode 100644 index 00000000000..be3b336aa50 --- /dev/null +++ b/dts/bindings/charger/ti,bq25180.yaml @@ -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. diff --git a/tests/drivers/build_all/charger/i2c.dtsi b/tests/drivers/build_all/charger/i2c.dtsi index c30efdcfcb8..b6365e97470 100644 --- a/tests/drivers/build_all/charger/i2c.dtsi +++ b/tests/drivers/build_all/charger/i2c.dtsi @@ -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>; +};