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]