Repository: zephyrproject-rtos/zephyr
Pull request #89225: fuel_gauge: add basic support for AXP2101 chip
Author: login: fmoessbauer
Labels: name: area: Samples
description: Samples
name: area: Fuel Gauge
Created: 2025-04-28T17:48:32Z | Merged: 2025-05-22T02:51:27Z

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.

cc @valeriosetti @aaronemassey @teburd @soburi @rriveramcrus


Diff:
diff --git a/boards/lilygo/ttgo_tbeam/ttgo_tbeam_esp32_procpu.dts b/boards/lilygo/ttgo_tbeam/ttgo_tbeam_esp32_procpu.dts
index 7b7c1831e1291..88deaae04d21a 100644
--- a/boards/lilygo/ttgo_tbeam/ttgo_tbeam_esp32_procpu.dts
+++ b/boards/lilygo/ttgo_tbeam/ttgo_tbeam_esp32_procpu.dts
@@ -125,6 +125,10 @@
 			constant-charge-current-max-microamp = <1000000>;
 			constant-charge-voltage-max-microvolt = <4200000>;
 		};
+
+		fuel_gauge: fuel_gauge {
+			compatible = "x-powers,axp2101-fuel-gauge";
+		};
 	};
 };
 
diff --git a/drivers/fuel_gauge/CMakeLists.txt b/drivers/fuel_gauge/CMakeLists.txt
index 93ad388eacc38..d8fa11f6a3398 100644
--- a/drivers/fuel_gauge/CMakeLists.txt
+++ b/drivers/fuel_gauge/CMakeLists.txt
@@ -6,6 +6,7 @@ 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_BQ27Z746		bq27z746)
+add_subdirectory_ifdef(CONFIG_FUEL_GAUGE_AXP2101	axp2101)
 
 zephyr_library_sources_ifdef(CONFIG_USERSPACE fuel_gauge_syscall_handlers.c)
 
diff --git a/drivers/fuel_gauge/Kconfig b/drivers/fuel_gauge/Kconfig
index 660c1e6125b23..c0eab696880c0 100644
--- a/drivers/fuel_gauge/Kconfig
+++ b/drivers/fuel_gauge/Kconfig
@@ -23,5 +23,6 @@ source "drivers/fuel_gauge/max17048/Kconfig"
 source "drivers/fuel_gauge/sbs_gauge/Kconfig"
 source "drivers/fuel_gauge/bq27z746/Kconfig"
 source "drivers/fuel_gauge/composite/Kconfig"
+source "drivers/fuel_gauge/axp2101/Kconfig"
 
 endif # FUEL_GAUGE
diff --git a/drivers/fuel_gauge/axp2101/CMakeLists.txt b/drivers/fuel_gauge/axp2101/CMakeLists.txt
new file mode 100644
index 0000000000000..e4085647c3b18
--- /dev/null
+++ b/drivers/fuel_gauge/axp2101/CMakeLists.txt
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: Apache-2.0
+
+zephyr_library()
+zephyr_library_sources(fuel_gauge_axp2101.c)
diff --git a/drivers/fuel_gauge/axp2101/Kconfig b/drivers/fuel_gauge/axp2101/Kconfig
new file mode 100644
index 0000000000000..85dd84e9ef2bf
--- /dev/null
+++ b/drivers/fuel_gauge/axp2101/Kconfig
@@ -0,0 +1,14 @@
+# Zephyr axp2101 fuel-gauge device
+
+# Copyright (c) 2025 Felix Moessbauer
+# SPDX-License-Identifier: Apache-2.0
+
+config FUEL_GAUGE_AXP2101
+	bool "X-Powers AXP2101 fuel gauge"
+	default y
+	depends on DT_HAS_X_POWERS_AXP2101_FUEL_GAUGE_ENABLED
+	depends on DT_HAS_X_POWERS_AXP2101_ENABLED
+	select I2C
+	select MFD
+	help
+	  Enable driver for the x-powers axp2101 fuel gauge device.
diff --git a/drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c b/drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
new file mode 100644
index 0000000000000..5f863e3f797ef
--- /dev/null
+++ b/drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+/* registers */
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_ADC_DATA_VBAT_H		0x34
+	#define GAUGE_VBAT_H_MASK	0x1F
+#define AXP2101_ADC_DATA_VBAT_L		0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+
+/* internal feature flags */
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
+				     BAT_TYPE_DET_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return ret;
+}
+
+static int is_battery_connect(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	uint8_t tmp;
+	int ret;
+
+	if ((data->features & GAUGE_FEATURE_BAT_DET) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_STATUS1, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->present_state = tmp & BAT_PRESENT_MASK;
+	return 0;
+}
+
+static int get_battery_percent(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	uint8_t tmp;
+	int ret;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_BAT_PERCENT_DATA, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->relative_state_of_charge = tmp;
+	return 0;
+}
+
+static int get_bat_voltage(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	uint8_t h5, l8;
+	int ret;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_VBAT_H, &h5);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_VBAT_L, &l8);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->voltage = (((h5 & GAUGE_VBAT_H_MASK) << 8) | l8) * 1000;
+	return 0;
+}
+
+static int axp2101_get_prop(const struct device *dev, fuel_gauge_prop_t prop,
+			    union fuel_gauge_prop_val *val)
+{
+	switch (prop) {
+	case FUEL_GAUGE_PRESENT_STATE:
+	case FUEL_GAUGE_CONNECT_STATE:
+		return is_battery_connect(dev, val);
+	case FUEL_GAUGE_VOLTAGE:
+		return get_bat_voltage(dev, val);
+	case FUEL_GAUGE_ABSOLUTE_STATE_OF_CHARGE:
+	case FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE:
+		return get_battery_percent(dev, val);
+	default:
+		return -ENOTSUP;
+	}
+}
+
+static int axp2101_init(const struct device *dev)
+{
+	struct axp2101_data *data = dev->data;
+	const struct axp2101_config *cfg;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static DEVICE_API(fuel_gauge, axp2101_api) = {
+	.get_property = axp2101_get_prop,
+};
+
+#define AXP2101_INIT(inst)                                                                         \
+	static const struct axp2101_config axp2101_config_##inst = {                               \
+		.i2c = I2C_DT_SPEC_GET(DT_PARENT(DT_INST(inst, DT_DRV_COMPAT))),                   \
+	};                                                                                         \
+	static struct axp2101_data axp2101_data_##inst = {                                         \
+		.features = GAUGE_FEATURE_ALL,                                                     \
+	};                                                                                         \
+	DEVICE_DT_INST_DEFINE(inst, &axp2101_init, NULL, &axp2101_data_##inst,                     \
+			      &axp2101_config_##inst, POST_KERNEL,                                 \
+			      CONFIG_FUEL_GAUGE_INIT_PRIORITY, &axp2101_api);
+
+DT_INST_FOREACH_STATUS_OKAY(AXP2101_INIT)
diff --git a/dts/bindings/fuel-gauge/x-powers,axp2101-fuel-gauge.yaml b/dts/bindings/fuel-gauge/x-powers,axp2101-fuel-gauge.yaml
new file mode 100644
index 0000000000000..3cfcc4d3d6808
--- /dev/null
+++ b/dts/bindings/fuel-gauge/x-powers,axp2101-fuel-gauge.yaml
@@ -0,0 +1,9 @@
+# Copyright (c) 2025 Felix Moessbauer <felix.moessbauer@gmail.com>
+# SPDX-License-Identifier: Apache-2.0
+
+description: |
+  X-Powers AXP2101 Fuel Gauge
+
+compatible: "x-powers,axp2101-fuel-gauge"
+
+include: [fuel-gauge.yaml]
diff --git a/include/zephyr/drivers/fuel_gauge.h b/include/zephyr/drivers/fuel_gauge.h
index 2e48b01e44511..387b3fb436756 100644
--- a/include/zephyr/drivers/fuel_gauge.h
+++ b/include/zephyr/drivers/fuel_gauge.h
@@ -130,10 +130,14 @@ union fuel_gauge_prop_val {
 	int current;
 	/** FUEL_GAUGE_CYCLE_COUNT */
 	uint32_t cycle_count;
+	/** FUEL_GAUGE_CONNECT_STATE */
+	uint32_t connect_state;
 	/** FUEL_GAUGE_FLAGS */
 	uint32_t flags;
 	/** FUEL_GAUGE_FULL_CHARGE_CAPACITY */
 	uint32_t full_charge_capacity;
+	/** FUEL_GAUGE_PRESENT_STATE */
+	bool present_state;
 	/** FUEL_GAUGE_REMAINING_CAPACITY */
 	uint32_t remaining_capacity;
 	/** FUEL_GAUGE_RUNTIME_TO_EMPTY */


Reviews:
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T17:54:10Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T17:54:50Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR adds initial support for the AXP2101 fuel gauge chip by implementing its driver, updating DTS bindings, and modifying sample code to use the new property access functions.
- Refactors sample code to poll fuel gauge properties using fuel_gauge_get_prop.
- Adds a new header member for battery presence state and a new DTS binding for the AXP2101.
- Implements the AXP2101 fuel gauge driver with basic functionalities for voltage, state of charge, and battery connection.

### Reviewed Changes

Copilot reviewed 4 out of 14 changed files in this pull request and generated 3 comments.

| File | Description |
| ---- | ----------- |
| samples/fuel_gauge/max17048/src/main.c | Updates fuel gauge polling logic to retrieve properties individually. |
| include/zephyr/drivers/fuel_gauge.h | Introduces a new present_state field in the fuel gauge property union. |
| dts/bindings/fuel-gauge/x-powers,axp2101-fuel-gauge.yaml | Provides new DTS binding for the AXP2101 fuel gauge. |
| drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c | Implements the basic AXP2101 fuel gauge driver with support for charge, voltage, and battery detection. |

<details>
<summary>Files not reviewed (10)</summary>

* **boards/lilygo/ttgo_tbeam/ttgo_tbeam_esp32_procpu.dts**: Language not supported
* **drivers/fuel_gauge/CMakeLists.txt**: Language not supported
* **drivers/fuel_gauge/Kconfig**: Language not supported
* **drivers/fuel_gauge/axp2101/CMakeLists.txt**: Language not supported
* **drivers/fuel_gauge/axp2101/Kconfig**: Language not supported
* **samples/fuel_gauge/max17048/README.rst**: Language not supported
* **samples/fuel_gauge/max17048/boards/adafruit_feather_esp32s2_C.overlay**: Language not supported
* **samples/fuel_gauge/max17048/boards/adafruit_feather_esp32s2_tft.overlay**: Language not supported
* **samples/fuel_gauge/max17048/boards/adafruit_feather_esp32s2_tft_reverse.overlay**: Language not supported
* **samples/fuel_gauge/max17048/boards/nrf52840dk_nrf52840.overlay**: Language not supported
</details>



state: COMMENTED
author_association: NONE
submitted_at: 2025-04-28T18:13:44Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T19:01:46Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T19:02:01Z
user: login: rriveramcrus
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T19:23:58Z
user: login: soburi
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-08T20:46:44Z
user: login: soburi
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-08T21:02:30Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T19:17:59Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T19:18:15Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T19:18:35Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T19:19:26Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T19:19:34Z
user: login: fmoessbauer
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-21T19:22:37Z
user: login: soburi
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-21T22:46:46Z
user: login: teburd
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-22T02:06:08Z

Review comments:
diff_hunk: @@ -40,12 +42,10 @@ Sample output
 ```
 *** Booting Zephyr OS build 16043f62a40a ***
 Found device "max17048@36", getting fuel gauge data
-Time to empty 1911
-Time to full 0
+Polling for fuel gauge data...
+----------------------------------------
 Charge 72%
-Voltage 3968
+Voltage 3968 uV
 Time to empty 1911
 Time to full 0
-Charge 72%
-Voltage 3968
path: samples/fuel_gauge/max17048/README.rst
user: login: fmoessbauer
body: Either the API is wrong, or this value makes no sense. The measurement should be in microvolts (according to the Doxygen comment of the property), but both mine and the old one are in mV.
created_at: 2025-04-28T17:54:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK			BIT(3)
+#define AXP2101_STATUS1					0x00
+	#define BAT_PRESENT_MASK			BIT(3)
+#define AXP2101_BAT_PERCENT_DATA		0xA4
+#define AXP2101_ADC_DATA_RELUST0		0x34
+#define AXP2101_ADC_DATA_RELUST1		0x35
+#define AXP2101_BAT_DET_CTRL			0x68
+	#define BAT_TYPE_DET_MASK			BIT(0)
+#define GAUGE_FEATURE_BAT_DET			BIT(0)
+#define GAUGE_FEATURE_GAUGE				BIT(1)
+#define GAUGE_FEATURE_ALL				(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: tabsize=8, right? Will fix on next iteration.
created_at: 2025-04-28T17:54:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK			BIT(3)
+#define AXP2101_STATUS1					0x00
+	#define BAT_PRESENT_MASK			BIT(3)
+#define AXP2101_BAT_PERCENT_DATA		0xA4
+#define AXP2101_ADC_DATA_RELUST0		0x34
+#define AXP2101_ADC_DATA_RELUST1		0x35
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: Copilot
body: [nitpick] The macro name 'AXP2101_ADC_DATA_RELUST0' appears to contain a typo. Consider renaming it to 'AXP2101_ADC_DATA_RESULT0' if this is not intended from the datasheet.
```suggestion
#define AXP2101_ADC_DATA_RESULT0		0x34
#define AXP2101_ADC_DATA_RESULT1		0x35
```
created_at: 2025-04-28T18:13:42Z
author_association: NONE
diff_hunk: @@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK			BIT(3)
+#define AXP2101_STATUS1					0x00
+	#define BAT_PRESENT_MASK			BIT(3)
+#define AXP2101_BAT_PERCENT_DATA		0xA4
+#define AXP2101_ADC_DATA_RELUST0		0x34
+#define AXP2101_ADC_DATA_RELUST1		0x35
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: Copilot
body: [nitpick] The macro name 'AXP2101_ADC_DATA_RELUST1' may be misspelled. Consider renaming it to 'AXP2101_ADC_DATA_RESULT1' for clarity.
```suggestion
#define AXP2101_ADC_DATA_RESULT0		0x34
#define AXP2101_ADC_DATA_RESULT1		0x35
```
created_at: 2025-04-28T18:13:43Z
author_association: NONE
diff_hunk: @@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK			BIT(3)
+#define AXP2101_STATUS1					0x00
+	#define BAT_PRESENT_MASK			BIT(3)
+#define AXP2101_BAT_PERCENT_DATA		0xA4
+#define AXP2101_ADC_DATA_RELUST0		0x34
+#define AXP2101_ADC_DATA_RELUST1		0x35
+#define AXP2101_BAT_DET_CTRL			0x68
+	#define BAT_TYPE_DET_MASK			BIT(0)
+#define GAUGE_FEATURE_BAT_DET			BIT(0)
+#define GAUGE_FEATURE_GAUGE				BIT(1)
+#define GAUGE_FEATURE_ALL				(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
+{
+	const struct axp2101_config *cfg;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
+				     BAT_TYPE_DET_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return ret;
+}
+
+static int is_battery_connect(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_BAT_DET) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_STATUS1, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->present_state = tmp & BAT_PRESENT_MASK;
+	return 0;
+}
+
+static int get_battery_percent(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_BAT_PERCENT_DATA, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->relative_state_of_charge = tmp;
+	return 0;
+}
+
+static int get_bat_voltage(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t h5, l8;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST0, &h5);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST1, &l8);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (h5 == -1 || l8 == -1) {
+		return -EINVAL;
+	}
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: Copilot
body: The condition is comparing unsigned values 'h5' and 'l8' with -1, which may not work as intended. It is recommended to handle error checking via the return values from the i2c_reg_read_byte_dt calls instead.
```suggestion
	/* Removed invalid comparison of unsigned values to -1 */
```
created_at: 2025-04-28T18:13:43Z
author_association: NONE
diff_hunk: @@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK			BIT(3)
+#define AXP2101_STATUS1					0x00
+	#define BAT_PRESENT_MASK			BIT(3)
+#define AXP2101_BAT_PERCENT_DATA		0xA4
+#define AXP2101_ADC_DATA_RELUST0		0x34
+#define AXP2101_ADC_DATA_RELUST1		0x35
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: These names are taken 1:1 from the reference implementation. By that, I do not recommend to change them.
created_at: 2025-04-28T19:01:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK			BIT(3)
+#define AXP2101_STATUS1					0x00
+	#define BAT_PRESENT_MASK			BIT(3)
+#define AXP2101_BAT_PERCENT_DATA		0xA4
+#define AXP2101_ADC_DATA_RELUST0		0x34
+#define AXP2101_ADC_DATA_RELUST1		0x35
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: Same here. From reference implementation.
created_at: 2025-04-28T19:02:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK			BIT(3)
+#define AXP2101_STATUS1					0x00
+	#define BAT_PRESENT_MASK			BIT(3)
+#define AXP2101_BAT_PERCENT_DATA		0xA4
+#define AXP2101_ADC_DATA_RELUST0		0x34
+#define AXP2101_ADC_DATA_RELUST1		0x35
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: rriveramcrus
body: The datasheet has quite a few typographical errors. We did deviate from and correct those errors on the charger driver, but I'll defer to @aaronemassey on what he would like to do here in the fuel gauge.
created_at: 2025-04-28T19:23:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: It's a matter of preference, but in Zephyr, a lot of the code has init placed at the bottom.
I think it's good if doing so eliminates prototype declarations.
created_at: 2025-05-08T20:43:15Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
+{
+	const struct axp2101_config *cfg;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: This is a matter of personal preference, but a format known as a reverse Christmas tree, in which long declarations are listed first, is also popular.
created_at: 2025-05-08T20:45:30Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: If it is not related to registers, it is better to create a separate group.
created_at: 2025-05-08T20:55:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: If you create groups of registers, sort them by address.
created_at: 2025-05-08T20:55:38Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: Rather than calling it "result", it is better to follow the explanation in the datasheet as vbat_h and vbat_l.
created_at: 2025-05-08T20:57:22Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
+{
+	const struct axp2101_config *cfg;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
+				     BAT_TYPE_DET_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return ret;
+}
+
+static int is_battery_connect(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_BAT_DET) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_STATUS1, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->present_state = tmp & BAT_PRESENT_MASK;
+	return 0;
+}
+
+static int get_battery_percent(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_BAT_PERCENT_DATA, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->relative_state_of_charge = tmp;
+	return 0;
+}
+
+static int get_bat_voltage(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t h5, l8;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST0, &h5);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST1, &l8);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (h5 == -1 || l8 == -1) {
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: First of all, you shouldn't compare int to uint32_t.
Also, isn't 255 an acceptable value for either?
created_at: 2025-05-08T21:01:57Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
+{
+	const struct axp2101_config *cfg;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
+				     BAT_TYPE_DET_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return ret;
+}
+
+static int is_battery_connect(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_BAT_DET) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_STATUS1, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->present_state = tmp & BAT_PRESENT_MASK;
+	return 0;
+}
+
+static int get_battery_percent(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_BAT_PERCENT_DATA, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->relative_state_of_charge = tmp;
+	return 0;
+}
+
+static int get_bat_voltage(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t h5, l8;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST0, &h5);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST1, &l8);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (h5 == -1 || l8 == -1) {
+		return -EINVAL;
+	}
+
+	val->voltage = (((h5 & 0x1F) << 8) | l8) * 1000;
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: The mask value must be defined as a macro.
created_at: 2025-05-08T21:02:23Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: In the latest version I moved it to the bottom (in front of the macro paradise).
created_at: 2025-05-21T19:17:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: Sure. Done and marked with a comment.
created_at: 2025-05-21T19:18:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: Renamed accordingly and sorted by address.
created_at: 2025-05-21T19:18:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
+{
+	const struct axp2101_config *cfg;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
+				     BAT_TYPE_DET_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return ret;
+}
+
+static int is_battery_connect(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_BAT_DET) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_STATUS1, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->present_state = tmp & BAT_PRESENT_MASK;
+	return 0;
+}
+
+static int get_battery_percent(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_BAT_PERCENT_DATA, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->relative_state_of_charge = tmp;
+	return 0;
+}
+
+static int get_bat_voltage(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t h5, l8;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST0, &h5);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST1, &l8);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (h5 == -1 || l8 == -1) {
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: Oh yes... I took that part from the reference implementation, but the datasheet does not mention anything about it. Now I dropped it, so we just rely on the bus read status.
created_at: 2025-05-21T19:19:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
+{
+	const struct axp2101_config *cfg;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
+				     BAT_TYPE_DET_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return ret;
+}
+
+static int is_battery_connect(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_BAT_DET) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_STATUS1, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->present_state = tmp & BAT_PRESENT_MASK;
+	return 0;
+}
+
+static int get_battery_percent(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t tmp;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_BAT_PERCENT_DATA, &tmp);
+	if (ret < 0) {
+		return ret;
+	}
+
+	val->relative_state_of_charge = tmp;
+	return 0;
+}
+
+static int get_bat_voltage(const struct device *dev, union fuel_gauge_prop_val *val)
+{
+	uint8_t h5, l8;
+	int ret;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+
+	if ((data->features & GAUGE_FEATURE_GAUGE) == 0) {
+		return -ENOTSUP;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST0, &h5);
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = i2c_reg_read_byte_dt(&cfg->i2c, AXP2101_ADC_DATA_RELUST1, &l8);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (h5 == -1 || l8 == -1) {
+		return -EINVAL;
+	}
+
+	val->voltage = (((h5 & 0x1F) << 8) | l8) * 1000;
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: Done.
created_at: 2025-05-21T19:19:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+#define AXP2101_ADC_DATA_RELUST0	0x34
+#define AXP2101_ADC_DATA_RELUST1	0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev);
+static int enable_batt_detection(const struct device *dev);
+
+static int axp2101_init(const struct device *dev)
+{
+	const struct axp2101_config *cfg;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	cfg = dev->config;
+
+	if (!device_is_ready(cfg->i2c.bus)) {
+		LOG_ERR("Bus device is not ready");
+		return -ENODEV;
+	}
+
+	ret = enable_fuel_gauge(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable fuel gauge");
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+
+	ret = enable_batt_detection(dev);
+	if (ret < 0) {
+		LOG_WRN("Failed to enable battery detection");
+		data->features &= ~GAUGE_FEATURE_BAT_DET;
+	}
+	return 0;
+}
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
+}
+
+static int enable_batt_detection(const struct device *dev)
+{
+	int ret = 0;
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_BAT_DET_CTRL, BAT_TYPE_DET_MASK,
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: fmoessbauer
body: That indeed looks cleaner. I changed it and unified it across the driver.
created_at: 2025-05-21T19:22:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2025, Felix Moessbauer
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Note: The functions that query the raw values via i2c are named similar
+ * to the ones in the reference implementation in the XPowersLib. This also
+ * applies to the register names (defines).
+ *
+ * Datasheet:
+ * https://github.com/lewisxhe/XPowersLib/blob/a7d06b98c1136c8fee7854b1d29a9f012b2aba83/datasheet/AXP2101_Datasheet_V1.0_en.pdf
+ */
+
+#define DT_DRV_COMPAT x_powers_axp2101_fuel_gauge
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/fuel_gauge.h>
+#include <zephyr/drivers/i2c.h>
+#include <zephyr/kernel.h>
+#include <zephyr/logging/log.h>
+
+LOG_MODULE_REGISTER(fuel_gauge_axp2101, CONFIG_FUEL_GAUGE_LOG_LEVEL);
+
+/* clang-format off */
+/* registers */
+#define AXP2101_STATUS1			0x00
+	#define BAT_PRESENT_MASK	BIT(3)
+#define AXP2101_CHARGE_GAUGE_WDT_CTRL	0x18
+	#define GAUGE_ENABLE_MASK	BIT(3)
+#define AXP2101_ADC_DATA_VBAT_H		0x34
+	#define GAUGE_VBAT_H_MASK	0x1F
+#define AXP2101_ADC_DATA_VBAT_L		0x35
+#define AXP2101_BAT_DET_CTRL		0x68
+	#define BAT_TYPE_DET_MASK	BIT(0)
+#define AXP2101_BAT_PERCENT_DATA	0xA4
+
+/* internal feature flags */
+#define GAUGE_FEATURE_BAT_DET		BIT(0)
+#define GAUGE_FEATURE_GAUGE		BIT(1)
+#define GAUGE_FEATURE_ALL		(GAUGE_FEATURE_BAT_DET | GAUGE_FEATURE_GAUGE)
+/* clang-format on */
+
+struct axp2101_config {
+	struct i2c_dt_spec i2c;
+};
+
+struct axp2101_data {
+	uint8_t features;
+};
+
+static int enable_fuel_gauge(const struct device *dev)
+{
+	const struct axp2101_config *cfg = dev->config;
+	struct axp2101_data *data = dev->data;
+	int ret = 0;
+
+	ret = i2c_reg_update_byte_dt(&cfg->i2c, AXP2101_CHARGE_GAUGE_WDT_CTRL, GAUGE_ENABLE_MASK,
+				     GAUGE_ENABLE_MASK);
+	if (ret < 0) {
+		data->features &= ~GAUGE_FEATURE_GAUGE;
+	}
+	return ret;
path: drivers/fuel_gauge/axp2101/fuel_gauge_axp2101.c
user: login: soburi
body: Although it is not blocking, I think Zephyr has many codes in that put a blank line before return. Please consider it if you like it.
created_at: 2025-05-21T22:46:17Z
author_association: MEMBER

PR comments:
user: login: fmoessbauer
created_at: 2025-05-21T19:23:25Z
body: @soburi Many thanks for the detailed review and apologies for the delay. Please review again.
author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-05-21T19:51:02Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=zephyrproject-rtos_zephyr&pullRequest=89225) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&pullRequest=89225&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&pullRequest=89225&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=zephyrproject-rtos_zephyr&pullRequest=89225&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=zephyrproject-rtos_zephyr&pullRequest=89225&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=zephyrproject-rtos_zephyr&pullRequest=89225&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=zephyrproject-rtos_zephyr&pullRequest=89225)


author_association: NONE
user: login: soburi
created_at: 2025-05-21T22:48:12Z
body: @aaronemassey @teburd 

Could you take a look, please?
author_association: MEMBER