From 7a14b6e977ded8840c6c6641ec2236b9dff02cb5 Mon Sep 17 00:00:00 2001 From: Mohammed Billoo Date: Fri, 11 Jul 2025 08:39:46 -0400 Subject: [PATCH] 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 are accounted for in the driver. Functionality was tested using a Thingy 91x. Signed-off-by: Mohammed Billoo --- drivers/fuel_gauge/CMakeLists.txt | 1 + drivers/fuel_gauge/Kconfig | 1 + drivers/fuel_gauge/max17043/Kconfig | 13 ++ drivers/fuel_gauge/max17043/max17043.c | 177 ++++++++++++++++++++ drivers/fuel_gauge/max17043/max17043.h | 24 +++ dts/bindings/fuel-gauge/maxim,max17043.yaml | 10 ++ 6 files changed, 226 insertions(+) create mode 100644 drivers/fuel_gauge/max17043/Kconfig create mode 100644 drivers/fuel_gauge/max17043/max17043.c create mode 100644 drivers/fuel_gauge/max17043/max17043.h create mode 100644 dts/bindings/fuel-gauge/maxim,max17043.yaml diff --git a/drivers/fuel_gauge/CMakeLists.txt b/drivers/fuel_gauge/CMakeLists.txt index 532eb21998c28..3532ba3ed3b2a 100644 --- a/drivers/fuel_gauge/CMakeLists.txt +++ b/drivers/fuel_gauge/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/fuel_gauge.h) add_subdirectory_ifdef(CONFIG_SBS_GAUGE_NEW_API sbs_gauge) add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_COMPOSITE composite) add_subdirectory_ifdef(CONFIG_MAX17048 max17048) +add_subdirectory_ifdef(CONFIG_MAX17043 max17043) add_subdirectory_ifdef(CONFIG_BQ27Z746 bq27z746) add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_AXP2101 axp2101) add_subdirectory_ifdef(CONFIG_LC709203F lc709203f) diff --git a/drivers/fuel_gauge/Kconfig b/drivers/fuel_gauge/Kconfig index 817bd94d0e785..7498d4a603269 100644 --- a/drivers/fuel_gauge/Kconfig +++ b/drivers/fuel_gauge/Kconfig @@ -19,6 +19,7 @@ config FUEL_GAUGE_INIT_PRIORITY help Battery fuel gauge initialization priority. +source "drivers/fuel_gauge/max17043/Kconfig" source "drivers/fuel_gauge/max17048/Kconfig" source "drivers/fuel_gauge/sbs_gauge/Kconfig" source "drivers/fuel_gauge/bq27z746/Kconfig" diff --git a/drivers/fuel_gauge/max17043/Kconfig b/drivers/fuel_gauge/max17043/Kconfig new file mode 100644 index 0000000000000..732db1e5f9a92 --- /dev/null +++ b/drivers/fuel_gauge/max17043/Kconfig @@ -0,0 +1,13 @@ +# MAX17043 Li-Ion battery fuel gauge + +# Copyright (c) 2025, Mohammed Billoo +# SPDX-License-Identifier: Apache-2.0 + + +config MAX17043 + bool "MAX17043 Li-Po fuel gauge" + default y + depends on DT_HAS_MAXIM_MAX17043_ENABLED + select I2C + help + Enable driver for the MAX17043 fuel gauge device. diff --git a/drivers/fuel_gauge/max17043/max17043.c b/drivers/fuel_gauge/max17043/max17043.c new file mode 100644 index 0000000000000..5a57cb223b870 --- /dev/null +++ b/drivers/fuel_gauge/max17043/max17043.c @@ -0,0 +1,177 @@ +/* max17043.c - Driver for max17043 battery fuel gauge */ + +/* + * Copyright (c) 2025 Mohammed Billoo + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT maxim_max17043 + +#include "max17043.h" + +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(MAX17043); + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 +#warning "MAX17043 driver enabled without any devices" +#endif + +/** + * Storage for the fuel gauge basic information + */ +struct max17043_data { + /* Charge as percentage */ + uint8_t charge; + /* Voltage as uV */ + uint32_t voltage; +}; + +/** + * I2C communication + * The way we read a value is first writing the address we want to read and then + * wait for 2 bytes containing the data. + */ +int max17043_read_register(const struct device *dev, uint8_t registerId, uint16_t *response) +{ + uint8_t max17043_buffer[2]; + const struct max17043_config *cfg = dev->config; + int rc = i2c_write_read_dt(&cfg->i2c, ®isterId, sizeof(registerId), max17043_buffer, + sizeof(max17043_buffer)); + if (rc != 0) { + LOG_ERR("Unable to read register, error %d", rc); + return rc; + } + + *response = sys_get_be16(max17043_buffer); + return 0; +} + +/** + * Raw value from the internal ADC + */ +int max17043_adc(const struct device *i2c_dev, uint16_t *response) +{ + return max17043_read_register(i2c_dev, REGISTER_VCELL, response); +} + +/** + * Battery voltage + */ +int max17043_voltage(const struct device *i2c_dev, uint32_t *response) +{ + uint16_t raw_voltage; + int rc = max17043_adc(i2c_dev, &raw_voltage); + + if (rc < 0) { + return rc; + } + /** + * Once the value is read, it has to be converted to volts. The datasheet + * https://www.analog.com/media/en/technical-documentation/data-sheets/ + * MAX17043-MAX17049.pdf + * Page 10, Table 2. Register Summary: 78.125µV/cell + * Max17043 only supports one cell so we just have to multiply the value by 78.125 to + * obtain µV + */ + + *response = (uint32_t)raw_voltage * 78.125; + return 0; +} + +/** + * Battery percentage still available + */ +int max17043_percent(const struct device *i2c_dev, uint8_t *response) +{ + uint16_t data; + int rc = max17043_read_register(i2c_dev, REGISTER_SOC, &data); + + if (rc < 0) { + return rc; + } + /** + * Once the value is read, it has to be converted to percentage. The datasheet + * Page 8, Table 2. Register Summary: 1%/256 + * So to obtain the total percentaje we just divide the read value by 256 + */ + *response = data / 256; + return 0; +} + +static int max17043_init(const struct device *dev) +{ + const struct max17043_config *cfg = dev->config; + uint16_t version; + int rc = max17043_read_register(dev, REGISTER_VERSION, &version); + + if (!device_is_ready(cfg->i2c.bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + if (rc < 0) { + LOG_ERR("Cannot read from I2C"); + return rc; + } + + LOG_INF("MAX17043 version: %x", version); + + return 0; +} + +/** + * Get a single property from the fuel gauge + */ +int max17043_get_single_prop(const struct device *dev, fuel_gauge_prop_t prop, + union fuel_gauge_prop_val *val) +{ + struct max17043_data *data = dev->data; + int rc = 0; + + switch (prop) { + case FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE: + rc = max17043_percent(dev, &data->charge); + + if (rc < 0) { + return rc; + } + + val->relative_state_of_charge = data->charge; + break; + case FUEL_GAUGE_VOLTAGE: + rc = max17043_voltage(dev, &data->voltage); + if (rc < 0) { + return rc; + } + val->voltage = data->voltage; + break; + default: + rc = -ENOTSUP; + } + + return rc; +} + +static const struct fuel_gauge_driver_api max17043_driver_api = { + .get_property = &max17043_get_single_prop, +}; + +#define MAX17043_DEFINE(inst) \ + static struct max17043_data max17043_data_##inst; \ + \ + static const struct max17043_config max17043_config_##inst = { \ + .i2c = I2C_DT_SPEC_INST_GET(inst)}; \ + \ + DEVICE_DT_INST_DEFINE(inst, &max17043_init, NULL, &max17043_data_##inst, \ + &max17043_config_##inst, POST_KERNEL, \ + CONFIG_FUEL_GAUGE_INIT_PRIORITY, &max17043_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(MAX17043_DEFINE) diff --git a/drivers/fuel_gauge/max17043/max17043.h b/drivers/fuel_gauge/max17043/max17043.h new file mode 100644 index 0000000000000..e1121b4b74121 --- /dev/null +++ b/drivers/fuel_gauge/max17043/max17043.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Mohammed Billoo + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#define REGISTER_VCELL 0x02 +#define REGISTER_SOC 0x04 +#define REGISTER_MODE 0x06 +#define REGISTER_VERSION 0x08 +#define REGISTER_HIBRT 0x0A +#define REGISTER_CONFIG 0x0C +#define REGISTER_COMMAND 0xFE + +#define RESET_COMMAND 0x5400 +#define QUICKSTART_MODE 0x4000 + +struct max17043_config { + struct i2c_dt_spec i2c; +}; diff --git a/dts/bindings/fuel-gauge/maxim,max17043.yaml b/dts/bindings/fuel-gauge/maxim,max17043.yaml new file mode 100644 index 0000000000000..a9789cbf58f93 --- /dev/null +++ b/dts/bindings/fuel-gauge/maxim,max17043.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Mohammed Billoo +# SPDX-License-Identifier: Apache-2.0 + +description: | + Maxim MAX17043 Fuel Gauge with ModelGauge. See more info at: + https://www.analog.com/media/en/technical-documentation/data-sheets/max17043-max17044.pdf + +compatible: "maxim,max17043" + +include: [i2c-device.yaml, fuel-gauge.yaml]