Skip to content

Commit 84ebbdc

Browse files
fmoessbauerkartben
authored andcommitted
fuel_gauge: add basic support for AXP2101 chip
The AXP2101 chip is a multi functional power chip offering a regulator, charge controller and a fuel gauge (battery percentage and voltage). Hereby, the fuel gauge provides much more reliable data compared to using an ADC. We implement minimal support for this chip (connected state, voltage and gauge) and bind it to the fuel gauge subsystem. Closes: #89158 Signed-off-by: Felix Moessbauer <felix.moessbauer@gmail.com>
1 parent 9a8e466 commit 84ebbdc

File tree

6 files changed

+232
-0
lines changed

6 files changed

+232
-0
lines changed

drivers/fuel_gauge/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_subdirectory_ifdef(CONFIG_SBS_GAUGE_NEW_API sbs_gauge)
66
add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_COMPOSITE composite)
77
add_subdirectory_ifdef(CONFIG_MAX17048 max17048)
88
add_subdirectory_ifdef(CONFIG_BQ27Z746 bq27z746)
9+
add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_AXP2101 axp2101)
910

1011
zephyr_library_sources_ifdef(CONFIG_USERSPACE fuel_gauge_syscall_handlers.c)
1112

drivers/fuel_gauge/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ source "drivers/fuel_gauge/max17048/Kconfig"
2323
source "drivers/fuel_gauge/sbs_gauge/Kconfig"
2424
source "drivers/fuel_gauge/bq27z746/Kconfig"
2525
source "drivers/fuel_gauge/composite/Kconfig"
26+
source "drivers/fuel_gauge/axp2101/Kconfig"
2627

2728
endif # FUEL_GAUGE
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
zephyr_library_sources(fuel_gauge_axp2101.c)

drivers/fuel_gauge/axp2101/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Zephyr axp2101 fuel-gauge device
2+
3+
# Copyright (c) 2025 Felix Moessbauer
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config FUEL_GAUGE_AXP2101
7+
bool "X-Powers AXP2101 fuel gauge"
8+
default y
9+
depends on DT_HAS_X_POWERS_AXP2101_FUEL_GAUGE_ENABLED
10+
depends on DT_HAS_X_POWERS_AXP2101_ENABLED
11+
select I2C
12+
select MFD
13+
help
14+
Enable driver for the x-powers axp2101 fuel gauge device.
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Copyright (c) 2025, Felix Moessbauer
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Note: The functions that query the raw values via i2c are named similar
7+
* to the ones in the reference implementation in the XPowersLib. This also
8+
* applies to the register names (defines).
9+
*
10+
* Datasheet:
11+
* https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
12+
*/
13+
14+
#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
15+
16+
#include <zephyr/device.h>
17+
#include <zephyr/drivers/fuel_gauge.h>
18+
#include <zephyr/drivers/i2c.h>
19+
#include <zephyr/kernel.h>
20+
#include <zephyr/logging/log.h>
21+
22+
LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
23+
24+
/* clang-format off */
25+
/* registers */
26+
#define AXP2101_STATUS1 0x00
27+
#define BAT_PRESENT_MASK BIT(3)
28+
#define AXP2101_CHARGE_GAUGE_WDT_CTRL 0x18
29+
#define GAUGE_ENABLE_MASK BIT(3)
30+
#define AXP2101_ADC_DATA_VBAT_H 0x34
31+
#define GAUGE_VBAT_H_MASK 0x1F
32+
#define AXP2101_ADC_DATA_VBAT_L 0x35
33+
#define AXP2101_BAT_DET_CTRL 0x68
34+
#define BAT_TYPE_DET_MASK BIT(0)
35+
#define AXP2101_BAT_PERCENT_DATA 0xA4
36+
37+
/* internal feature flags */
38+
#define GAUGE_FEATURE_BAT_DET BIT(0)
39+
#define GAUGE_FEATURE_GAUGE BIT(1)
40+
#define GAUGE_FEATURE_ALL (GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
41+
/* clang-format on */
42+
43+
struct axp2101_config {
44+
struct i2c_dt_spec i2c;
45+
};
46+
47+
struct axp2101_data {
48+
uint8_t features;
49+
};
50+
51+
static int enable_fuel_gauge(const struct device *dev)
52+
{
53+
const struct axp2101_config *cfg = dev->config;
54+
struct axp2101_data *data = dev->data;
55+
int ret = 0;
56+
57+
ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
58+
GAUGE_ENABLE_MASK);
59+
if (ret < 0) {
60+
data->features &= ~GAUGE_FEATURE_GAUGE;
61+
}
62+
return ret;
63+
}
64+
65+
static int enable_batt_detection(const struct device *dev)
66+
{
67+
const struct axp2101_config *cfg = dev->config;
68+
struct axp2101_data *data = dev->data;
69+
int ret = 0;
70+
71+
ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
72+
BAT_TYPE_DET_MASK);
73+
if (ret < 0) {
74+
data->features &= ~GAUGE_FEATURE_BAT_DET;
75+
}
76+
return ret;
77+
}
78+
79+
static int is_battery_connect(const struct device *dev, union fuel_gauge_prop_val *val)
80+
{
81+
const struct axp2101_config *cfg = dev->config;
82+
struct axp2101_data *data = dev->data;
83+
uint8_t tmp;
84+
int ret;
85+
86+
if ((data->features & GAUGE_FEATURE_BAT_DET) == 0) {
87+
return -ENOTSUP;
88+
}
89+
90+
ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_STATUS1, &tmp);
91+
if (ret < 0) {
92+
return ret;
93+
}
94+
95+
val->present_state = tmp & BAT_PRESENT_MASK;
96+
return 0;
97+
}
98+
99+
static int get_battery_percent(const struct device *dev, union fuel_gauge_prop_val *val)
100+
{
101+
const struct axp2101_config *cfg = dev->config;
102+
struct axp2101_data *data = dev->data;
103+
uint8_t tmp;
104+
int ret;
105+
106+
if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
107+
return -ENOTSUP;
108+
}
109+
110+
ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_BAT_PERCENT_DATA, &tmp);
111+
if (ret < 0) {
112+
return ret;
113+
}
114+
115+
val->relative_state_of_charge = tmp;
116+
return 0;
117+
}
118+
119+
static int get_bat_voltage(const struct device *dev, union fuel_gauge_prop_val *val)
120+
{
121+
const struct axp2101_config *cfg = dev->config;
122+
struct axp2101_data *data = dev->data;
123+
uint8_t h5, l8;
124+
int ret;
125+
126+
if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
127+
return -ENOTSUP;
128+
}
129+
130+
ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_VBAT_H, &h5);
131+
if (ret < 0) {
132+
return ret;
133+
}
134+
135+
ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_VBAT_L, &l8);
136+
if (ret < 0) {
137+
return ret;
138+
}
139+
140+
val->voltage = (((h5 & GAUGE_VBAT_H_MASK) << 8) | l8) * 1000;
141+
return 0;
142+
}
143+
144+
static int axp2101_get_prop(const struct device *dev, fuel_gauge_prop_t prop,
145+
union fuel_gauge_prop_val *val)
146+
{
147+
switch (prop) {
148+
case FUEL_GAUGE_PRESENT_STATE:
149+
case FUEL_GAUGE_CONNECT_STATE:
150+
return is_battery_connect(dev, val);
151+
case FUEL_GAUGE_VOLTAGE:
152+
return get_bat_voltage(dev, val);
153+
case FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE:
154+
case FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE:
155+
return get_battery_percent(dev, val);
156+
default:
157+
return -ENOTSUP;
158+
}
159+
}
160+
161+
static int axp2101_init(const struct device *dev)
162+
{
163+
struct axp2101_data *data = dev->data;
164+
const struct axp2101_config *cfg;
165+
int ret = 0;
166+
167+
cfg = dev->config;
168+
169+
if (!device_is_ready(cfg->i2c.bus)) {
170+
LOG_ERR("Bus device is not ready");
171+
return -ENODEV;
172+
}
173+
174+
ret = enable_fuel_gauge(dev);
175+
if (ret < 0) {
176+
LOG_WRN("Failed to enable fuel gauge");
177+
data->features &= ~GAUGE_FEATURE_GAUGE;
178+
}
179+
180+
ret = enable_batt_detection(dev);
181+
if (ret < 0) {
182+
LOG_WRN("Failed to enable battery detection");
183+
data->features &= ~GAUGE_FEATURE_BAT_DET;
184+
}
185+
return 0;
186+
}
187+
188+
static DEVICE_API(fuel_gauge, axp2101_api) = {
189+
.get_property = axp2101_get_prop,
190+
};
191+
192+
#define AXP2101_INIT(inst) \
193+
static const struct axp2101_config axp2101_config_##inst = { \
194+
.i2c = I2C_DT_SPEC_GET(DT_PARENT(DT_INST(inst, DT_DRV_COMPAT))), \
195+
}; \
196+
static struct axp2101_data axp2101_data_##inst = { \
197+
.features = GAUGE_FEATURE_ALL, \
198+
}; \
199+
DEVICE_DT_INST_DEFINE(inst, &axp2101_init, NULL, &axp2101_data_##inst, \
200+
&axp2101_config_##inst, POST_KERNEL, \
201+
CONFIG_FUEL_GAUGE_INIT_PRIORITY, &axp2101_api);
202+
203+
DT_INST_FOREACH_STATUS_OKAY(AXP2101_INIT)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2025 Felix Moessbauer <felix.moessbauer@gmail.com>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
X-Powers AXP2101 Fuel Gauge
6+
7+
compatible: "x-powers,axp2101-fuel-gauge"
8+
9+
include: [fuel-gauge.yaml]

0 commit comments

Comments
 (0)