Skip to content

Commit 16d3d93

Browse files
committed
drivers: Add fuel gauge max17043
Add support for fuel gauge max17043. This device is similar to the max17048 and so it was used as the basis. There are slight differences in the registers which is accounted for in the driver.
1 parent e22ca6b commit 16d3d93

File tree

6 files changed

+223
-0
lines changed

6 files changed

+223
-0
lines changed

drivers/fuel_gauge/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/fuel_gauge.h)
55
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)
8+
add_subdirectory_ifdef(CONFIG_MAX17043 max17043)
89
add_subdirectory_ifdef(CONFIG_BQ27Z746 bq27z746)
910
add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_AXP2101 axp2101)
1011
add_subdirectory_ifdef(CONFIG_LC709203F lc709203f)

drivers/fuel_gauge/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ config FUEL_GAUGE_INIT_PRIORITY
1919
help
2020
Battery fuel gauge initialization priority.
2121

22+
source "drivers/fuel_gauge/max17043/Kconfig"
2223
source "drivers/fuel_gauge/max17048/Kconfig"
2324
source "drivers/fuel_gauge/sbs_gauge/Kconfig"
2425
source "drivers/fuel_gauge/bq27z746/Kconfig"

drivers/fuel_gauge/max17043/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# MAX17043 Li-Ion battery fuel gauge
2+
3+
# Copyright (c) 2025, Mohammed Billoo <mab@mab-labs.com>
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
7+
config MAX17043
8+
bool "MAX17043 Li-Po fuel gauge"
9+
default y
10+
depends on DT_HAS_MAXIM_MAX17043_ENABLED
11+
select I2C
12+
help
13+
Enable driver for the MAX17043 fuel gauge device.
14+
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/* max17043.c - Driver for max17043 battery fuel gauge */
2+
3+
/*
4+
* Copyright (c) 2025 Mohammed Billoo <mab@mab-labs.com>
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#define DT_DRV_COMPAT maxim_max17043
10+
11+
#include "max17043.h"
12+
13+
#include <zephyr/logging/log.h>
14+
#include <zephyr/drivers/fuel_gauge.h>
15+
#include <zephyr/kernel.h>
16+
#include <zephyr/init.h>
17+
#include <zephyr/pm/device.h>
18+
#include <zephyr/sys/byteorder.h>
19+
#include <zephyr/sys/__assert.h>
20+
21+
LOG_MODULE_REGISTER(MAX17043);
22+
23+
#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0
24+
#warning "MAX17043 driver enabled without any devices"
25+
#endif
26+
27+
/**
28+
* Storage for the fuel gauge basic information
29+
*/
30+
struct max17043_data {
31+
/* Charge as percentage */
32+
uint8_t charge;
33+
/* Voltage as uV */
34+
uint32_t voltage;
35+
};
36+
37+
/**
38+
* I2C communication
39+
* The way we read a value is first writing the address we want to read and then
40+
* wait for 2 bytes containing the data.
41+
*/
42+
int max17043_read_register(const struct device *dev, uint8_t registerId, uint16_t *response)
43+
{
44+
uint8_t max17043_buffer[2];
45+
const struct max17043_config *cfg = dev->config;
46+
int rc = i2c_write_read_dt(&cfg->i2c, &registerId, sizeof(registerId), max17043_buffer,
47+
sizeof(max17043_buffer));
48+
if (rc != 0) {
49+
LOG_ERR("Unable to read register, error %d", rc);
50+
return rc;
51+
}
52+
53+
*response = sys_get_be16(max17043_buffer);
54+
return 0;
55+
}
56+
57+
/**
58+
* Raw value from the internal ADC
59+
*/
60+
int max17043_adc(const struct device *i2c_dev, uint16_t *response)
61+
{
62+
return max17043_read_register(i2c_dev, REGISTER_VCELL, response);
63+
}
64+
65+
/**
66+
* Battery voltage
67+
*/
68+
int max17043_voltage(const struct device *i2c_dev, uint32_t *response)
69+
{
70+
uint16_t raw_voltage;
71+
int rc = max17043_adc(i2c_dev, &raw_voltage);
72+
73+
if (rc < 0) {
74+
return rc;
75+
}
76+
/**
77+
* Once the value is read, it has to be converted to volts. The datasheet
78+
* https://www.analog.com/media/en/technical-documentation/data-sheets/
79+
* MAX17043-MAX17049.pdf
80+
* Page 10, Table 2. Register Summary: 78.125µV/cell
81+
* Max17043 only supports one cell so we just have to multiply the value by 78.125 to
82+
* obtain µV
83+
*/
84+
85+
*response = (uint32_t)raw_voltage * 78.125;
86+
return 0;
87+
}
88+
89+
/**
90+
* Battery percentage still available
91+
*/
92+
int max17043_percent(const struct device *i2c_dev, uint8_t *response)
93+
{
94+
uint16_t data;
95+
int rc = max17043_read_register(i2c_dev, REGISTER_SOC, &data);
96+
97+
if (rc < 0) {
98+
return rc;
99+
}
100+
/**
101+
* Once the value is read, it has to be converted to percentage. The datasheet
102+
* Page 8, Table 2. Register Summary: 1%/256
103+
* So to obtain the total percentaje we just divide the read value by 256
104+
*/
105+
*response = data / 256;
106+
return 0;
107+
}
108+
109+
static int max17043_init(const struct device *dev)
110+
{
111+
const struct max17043_config *cfg = dev->config;
112+
uint16_t version;
113+
int rc = max17043_read_register(dev, REGISTER_VERSION, &version);
114+
115+
if (!device_is_ready(cfg->i2c.bus)) {
116+
LOG_ERR("Bus device is not ready");
117+
return -ENODEV;
118+
}
119+
120+
if (rc < 0) {
121+
LOG_ERR("Cannot read from I2C");
122+
return rc;
123+
}
124+
125+
LOG_INF("MAX17043 version: %x", version);
126+
127+
return 0;
128+
}
129+
130+
/**
131+
* Get a single property from the fuel gauge
132+
*/
133+
int max17043_get_single_prop(const struct device *dev, fuel_gauge_prop_t prop,
134+
union fuel_gauge_prop_val *val)
135+
{
136+
struct max17043_data *data = dev->data;
137+
int rc = 0;
138+
139+
switch (prop) {
140+
case FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE:
141+
rc = max17043_percent(dev, &data->charge);
142+
if (rc < 0)
143+
return rc;
144+
val->relative_state_of_charge = data->charge;
145+
break;
146+
case FUEL_GAUGE_VOLTAGE:
147+
rc = max17043_voltage(dev, &data->voltage);
148+
if (rc < 0)
149+
return rc;
150+
val->voltage = data->voltage;
151+
break;
152+
default:
153+
rc = -ENOTSUP;
154+
}
155+
156+
return rc;
157+
}
158+
159+
static const struct fuel_gauge_driver_api max17043_driver_api = {
160+
.get_property = &max17043_get_single_prop,
161+
};
162+
163+
#define MAX17043_DEFINE(inst) \
164+
static struct max17043_data max17043_data_##inst; \
165+
\
166+
static const struct max17043_config max17043_config_##inst = { \
167+
.i2c = I2C_DT_SPEC_INST_GET(inst)}; \
168+
\
169+
DEVICE_DT_INST_DEFINE(inst, &max17043_init, NULL, &max17043_data_##inst, \
170+
&max17043_config_##inst, POST_KERNEL, \
171+
CONFIG_FUEL_GAUGE_INIT_PRIORITY, &max17043_driver_api);
172+
173+
DT_INST_FOREACH_STATUS_OKAY(MAX17043_DEFINE)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (c) 2025 Mohammed Billoo <mab@mab-labs.com>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include <zephyr/drivers/i2c.h>
10+
11+
#define REGISTER_VCELL 0x02
12+
#define REGISTER_SOC 0x04
13+
#define REGISTER_MODE 0x06
14+
#define REGISTER_VERSION 0x08
15+
#define REGISTER_HIBRT 0x0A
16+
#define REGISTER_CONFIG 0x0C
17+
#define REGISTER_COMMAND 0xFE
18+
19+
#define RESET_COMMAND 0x5400
20+
#define QUICKSTART_MODE 0x4000
21+
22+
struct max17043_config {
23+
struct i2c_dt_spec i2c;
24+
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 Mohammed Billoo <mab@mab-labs.com>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
Maxim MAX17043 Fuel Gauge with ModelGauge. See more info at:
6+
https://www.analog.com/media/en/technical-documentation/data-sheets/max17043-max17044.pdf
7+
8+
compatible: "maxim,max17043"
9+
10+
include: [i2c-device.yaml, fuel-gauge.yaml]

0 commit comments

Comments
 (0)