Skip to content

Commit e517af4

Browse files
fabiobaltiericarlescufi
authored andcommitted
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 <[email protected]>
1 parent 312e000 commit e517af4

File tree

6 files changed

+267
-0
lines changed

6 files changed

+267
-0
lines changed

drivers/charger/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ zephyr_library()
44
zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/charger.h)
55

66
zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ24190 charger_bq24190.c)
7+
zephyr_library_sources_ifdef(CONFIG_CHARGER_BQ25180 charger_bq25180.c)
78
zephyr_library_sources_ifdef(CONFIG_CHARGER_MAX20335 charger_max20335.c)
89
zephyr_library_sources_ifdef(CONFIG_SBS_CHARGER sbs_charger.c)
910
zephyr_library_sources_ifdef(CONFIG_USERSPACE charger_handlers.c)

drivers/charger/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ config CHARGER_INIT_PRIORITY
2121

2222
source "drivers/charger/Kconfig.sbs_charger"
2323
source "drivers/charger/Kconfig.bq24190"
24+
source "drivers/charger/Kconfig.bq25180"
2425
source "drivers/charger/Kconfig.max20335"
2526

2627
endif # CHARGER

drivers/charger/Kconfig.bq25180

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright 2024 Google LLC
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
config CHARGER_BQ25180
6+
bool "BQ25180 Battery Charger"
7+
default y
8+
depends on DT_HAS_TI_BQ25180_ENABLED
9+
select I2C
10+
help
11+
Enable BQ25180 battery charger driver.

drivers/charger/charger_bq25180.c

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* BQ25180 Datasheet: https://www.ti.com/lit/gpn/bq25180
7+
*/
8+
9+
#define DT_DRV_COMPAT ti_bq25180
10+
11+
#include <zephyr/device.h>
12+
#include <zephyr/drivers/charger.h>
13+
#include <zephyr/drivers/i2c.h>
14+
#include <zephyr/kernel.h>
15+
#include <zephyr/logging/log.h>
16+
#include <zephyr/sys/util.h>
17+
18+
LOG_MODULE_REGISTER(bq25180, CONFIG_CHARGER_LOG_LEVEL);
19+
20+
#define BQ25180_STAT0 0x00
21+
#define BQ25180_STAT1 0x01
22+
#define BQ25180_FLAG0 0x02
23+
#define BQ25180_VBAT_CTRL 0x03
24+
#define BQ25180_ICHG_CTRL 0x04
25+
#define BQ25180_IC_CTRL 0x07
26+
#define BQ25180_SHIP_RST 0x09
27+
#define BQ25180_MASK_ID 0x0c
28+
29+
#define BQ25180_ICHG_CHG_DIS BIT(7)
30+
#define BQ25180_ICHG_MSK GENMASK(6, 0)
31+
#define BQ25180_WATCHDOG_SEL_1_MSK GENMASK(1, 0)
32+
#define BQ25180_WATCHDOG_DISABLE 0x03
33+
#define BQ25180_DEVICE_ID_MSK GENMASK(3, 0)
34+
#define BQ25180_DEVICE_ID 0x00
35+
#define BQ25180_SHIP_RST_EN_RST_SHIP_MSK GENMASK(6, 5)
36+
#define BQ25180_SHIP_RST_EN_RST_SHIP_ADAPTER 0x20
37+
#define BQ25180_SHIP_RST_EN_RST_SHIP_BUTTON 0x40
38+
39+
/* Charging current limits */
40+
#define BQ25180_CURRENT_MIN_MA 5
41+
#define BQ25180_CURRENT_MAX_MA 1000
42+
43+
struct bq25180_config {
44+
struct i2c_dt_spec i2c;
45+
uint32_t initial_current_microamp;
46+
};
47+
48+
/*
49+
* For ICHG <= 35mA = ICHGCODE + 5mA
50+
* For ICHG > 35mA = 40 + ((ICHGCODE-31)*10)mA.
51+
* Maximum programmable current = 1000mA
52+
*
53+
* Return: value between 0 and 127, negative on error.
54+
*/
55+
static int bq25180_ma_to_ichg(uint32_t current_ma, uint8_t *ichg)
56+
{
57+
if (!IN_RANGE(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA)) {
58+
LOG_WRN("charging current out of range: %dmA, "
59+
"clamping to the nearest limit", current_ma);
60+
}
61+
current_ma = CLAMP(current_ma, BQ25180_CURRENT_MIN_MA, BQ25180_CURRENT_MAX_MA);
62+
63+
if (current_ma <= 35) {
64+
*ichg = current_ma - 5;
65+
return 0;
66+
}
67+
68+
*ichg = (current_ma - 40) / 10 + 31;
69+
70+
return 0;
71+
}
72+
73+
static uint32_t bq25180_ichg_to_ma(uint8_t ichg)
74+
{
75+
ichg &= BQ25180_ICHG_MSK;
76+
77+
if (ichg <= 30) {
78+
return (ichg + 5);
79+
}
80+
81+
return (ichg - 31) * 10 + 40;
82+
}
83+
84+
static int bq25183_charge_enable(const struct device *dev, const bool enable)
85+
{
86+
const struct bq25180_config *cfg = dev->config;
87+
uint8_t value = enable ? 0 : BQ25180_ICHG_CHG_DIS;
88+
int ret;
89+
90+
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL,
91+
BQ25180_ICHG_CHG_DIS, value);
92+
if (ret < 0) {
93+
return ret;
94+
}
95+
96+
return 0;
97+
}
98+
99+
static int bq25180_set_charge_current(const struct device *dev,
100+
uint32_t const_charge_current_ua)
101+
{
102+
const struct bq25180_config *cfg = dev->config;
103+
uint8_t val;
104+
int ret;
105+
106+
ret = bq25180_ma_to_ichg(const_charge_current_ua / 1000, &val);
107+
if (ret < 0) {
108+
return ret;
109+
}
110+
111+
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL,
112+
BQ25180_ICHG_MSK, val);
113+
if (ret < 0) {
114+
return ret;
115+
}
116+
117+
return 0;
118+
}
119+
120+
static int bq25180_get_charge_current(const struct device *dev,
121+
uint32_t *const_charge_current_ua)
122+
{
123+
const struct bq25180_config *cfg = dev->config;
124+
uint8_t val;
125+
int ret;
126+
127+
ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL, &val);
128+
if (ret < 0) {
129+
return ret;
130+
}
131+
132+
*const_charge_current_ua = bq25180_ichg_to_ma(val) * 1000;
133+
134+
return 0;
135+
}
136+
137+
static int bq25180_get_prop(const struct device *dev, charger_prop_t prop,
138+
union charger_propval *val)
139+
{
140+
switch (prop) {
141+
case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA:
142+
return bq25180_get_charge_current(dev, &val->const_charge_current_ua);
143+
default:
144+
return -ENOTSUP;
145+
}
146+
}
147+
148+
static int bq25180_set_prop(const struct device *dev, charger_prop_t prop,
149+
const union charger_propval *val)
150+
{
151+
switch (prop) {
152+
case CHARGER_PROP_CONSTANT_CHARGE_CURRENT_UA:
153+
return bq25180_set_charge_current(dev, val->const_charge_current_ua);
154+
default:
155+
return -ENOTSUP;
156+
}
157+
}
158+
159+
static const struct charger_driver_api bq25180_api = {
160+
.get_property = bq25180_get_prop,
161+
.set_property = bq25180_set_prop,
162+
.charge_enable = bq25183_charge_enable,
163+
};
164+
165+
static int bq25180_init(const struct device *dev)
166+
{
167+
const struct bq25180_config *cfg = dev->config;
168+
uint8_t val;
169+
int ret;
170+
171+
ret = i2c_reg_read_byte_dt(&cfg->i2c, BQ25180_MASK_ID, &val);
172+
if (ret < 0) {
173+
return ret;
174+
}
175+
176+
val &= BQ25180_DEVICE_ID_MSK;
177+
if (val != BQ25180_DEVICE_ID) {
178+
LOG_ERR("Invalid device id: %02x", val);
179+
return -EINVAL;
180+
}
181+
182+
/* Disable the watchdog */
183+
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_IC_CTRL,
184+
BQ25180_WATCHDOG_SEL_1_MSK,
185+
BQ25180_WATCHDOG_DISABLE);
186+
if (ret < 0) {
187+
return ret;
188+
}
189+
190+
if (cfg->initial_current_microamp > 0) {
191+
ret = bq25180_ma_to_ichg(cfg->initial_current_microamp / 1000, &val);
192+
if (ret < 0) {
193+
return ret;
194+
}
195+
196+
ret = i2c_reg_update_byte_dt(&cfg->i2c, BQ25180_ICHG_CTRL,
197+
BQ25180_ICHG_MSK, val);
198+
if (ret < 0) {
199+
return ret;
200+
}
201+
}
202+
203+
return 0;
204+
}
205+
206+
#define CHARGER_BQ25180_INIT(inst) \
207+
static const struct bq25180_config bq25180_config_##inst = { \
208+
.i2c = I2C_DT_SPEC_INST_GET(inst), \
209+
.initial_current_microamp = DT_INST_PROP( \
210+
inst, constant_charge_current_max_microamp), \
211+
}; \
212+
\
213+
DEVICE_DT_INST_DEFINE(inst, bq25180_init, NULL, NULL, \
214+
&bq25180_config_##inst, POST_KERNEL, \
215+
CONFIG_CHARGER_INIT_PRIORITY, \
216+
&bq25180_api);
217+
218+
DT_INST_FOREACH_STATUS_OKAY(CHARGER_BQ25180_INIT)

dts/bindings/charger/ti,bq25180.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright 2024 Google LLC
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
BQ25180 I2C Controlled, 1-Cell, 1-A Linear Battery Charger with Power Path
6+
and Ship Mode.
7+
8+
The device has a single child node for the charger. For example:
9+
10+
bq25180@6a {
11+
compatible = "ti,bq25180";
12+
reg = <0x6a>;
13+
14+
constant-charge-current-max-microamp = <500000>;
15+
};
16+
17+
compatible: "ti,bq25180"
18+
19+
include: [battery.yaml, i2c-device.yaml]
20+
21+
22+
properties:
23+
constant-charge-current-max-microamp:
24+
type: int
25+
default: 0
26+
description: |
27+
Charge current set at init time in uA, available range is 5 mA to 800 mA.
28+
The value specified will be rounded down to the closest implemented
29+
value. If set to 0 (default) skip setting the charge current value at
30+
driver initialization.

tests/drivers/build_all/charger/i2c.dtsi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ max20335@1 {
2828
constant-charge-voltage-max-microvolt = <4050000>;
2929
};
3030
};
31+
32+
bq25180@2 {
33+
compatible = "ti,bq25180";
34+
reg = <0x2>;
35+
constant-charge-current-max-microamp = <500000>;
36+
};

0 commit comments

Comments
 (0)