sensor: add MAX17262 fuel gauge driver and sample application

The MAX17262 is an ultra-low power fuel-gauge IC which implements the
Maxim ModelGauge m5 algorithm. The IC monitors a single-cell battery
pack and supports internal current sensing for up to 3.1A pulse
current. The IC provides best performance for batteries with 100mAhr
to 6Ahr capacity.

Signed-off-by: Matija Tudan <mtudan@mobilisis.hr>
diff --git a/drivers/sensor/CMakeLists.txt b/drivers/sensor/CMakeLists.txt
index c944095..4765f0f 100644
--- a/drivers/sensor/CMakeLists.txt
+++ b/drivers/sensor/CMakeLists.txt
@@ -53,6 +53,7 @@
 add_subdirectory_ifdef(CONFIG_LSM9DS0_GYRO	lsm9ds0_gyro)
 add_subdirectory_ifdef(CONFIG_LSM9DS0_MFD	lsm9ds0_mfd)
 add_subdirectory_ifdef(CONFIG_MAX17055		max17055)
+add_subdirectory_ifdef(CONFIG_MAX17262		max17262)
 add_subdirectory_ifdef(CONFIG_MAX30101		max30101)
 add_subdirectory_ifdef(CONFIG_MAX44009		max44009)
 add_subdirectory_ifdef(CONFIG_MAX6675		max6675)
diff --git a/drivers/sensor/Kconfig b/drivers/sensor/Kconfig
index 0282403..0ac2a57 100644
--- a/drivers/sensor/Kconfig
+++ b/drivers/sensor/Kconfig
@@ -144,6 +144,8 @@
 
 source "drivers/sensor/max17055/Kconfig"
 
+source "drivers/sensor/max17262/Kconfig"
+
 source "drivers/sensor/max30101/Kconfig"
 
 source "drivers/sensor/max44009/Kconfig"
diff --git a/drivers/sensor/max17262/CMakeLists.txt b/drivers/sensor/max17262/CMakeLists.txt
new file mode 100644
index 0000000..386aea8
--- /dev/null
+++ b/drivers/sensor/max17262/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright 2020 Matija Tudan
+#
+# SPDX-License-Identifier: Apache-2.0
+
+zephyr_library()
+
+zephyr_library_sources_ifdef(CONFIG_MAX17262 max17262.c)
diff --git a/drivers/sensor/max17262/Kconfig b/drivers/sensor/max17262/Kconfig
new file mode 100644
index 0000000..4bb9a10
--- /dev/null
+++ b/drivers/sensor/max17262/Kconfig
@@ -0,0 +1,11 @@
+# Copyright 2020 Matija Tudan
+#
+# SPDX-License-Identifier: Apache-2.0
+
+config MAX17262
+	bool "MAX17262 Fuel Gauge"
+	depends on I2C
+	help
+	  Enable I2C-based driver for MAX17262 Fuel Gauge. This driver supports
+	  reading various sensor settings including voltage, current, temperature,
+	  time to full/empty and remaining capacity in mAh.
diff --git a/drivers/sensor/max17262/max17262.c b/drivers/sensor/max17262/max17262.c
new file mode 100644
index 0000000..2ff12b4
--- /dev/null
+++ b/drivers/sensor/max17262/max17262.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2021 Matija Tudan
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <drivers/i2c.h>
+#include <drivers/sensor.h>
+
+#include <logging/log.h>
+LOG_MODULE_REGISTER(max17262, CONFIG_SENSOR_LOG_LEVEL);
+
+#include "max17262.h"
+
+#define DT_DRV_COMPAT maxim_max17262
+
+/**
+ * @brief Read a register value
+ *
+ * Registers have an address and a 16-bit value
+ *
+ * @param dev MAX17262 device to access
+ * @param reg_addr Register address to read
+ * @param valp Place to put the value on success
+ * @return 0 if successful, or negative error code from I2C API
+ */
+static int max17262_reg_read(const struct device *dev, uint8_t reg_addr,
+			     int16_t *valp)
+{
+	const struct max17262_config *cfg = dev->config;
+	uint8_t i2c_data[2];
+	int rc;
+
+	rc = i2c_burst_read(cfg->i2c, cfg->i2c_addr, reg_addr,
+			    i2c_data, 2);
+	if (rc < 0) {
+		LOG_ERR("Unable to read register");
+		return rc;
+	}
+	*valp = ((int16_t)i2c_data[1] << 8) | i2c_data[0];
+
+	return 0;
+}
+
+/**
+ * @brief Write a register value
+ *
+ * Registers have an address and a 16-bit value
+ *
+ * @param dev MAX17262 device to access
+ * @param reg_addr Register address to write to
+ * @param val Register value to write
+ * @return 0 if successful, or negative error code from I2C API
+ */
+static int max17262_reg_write(const struct device *dev, uint8_t reg_addr,
+			     int16_t val)
+{
+	const struct max17262_config *cfg = dev->config;
+	uint8_t i2c_data[3] = {reg_addr, val & 0xFF, (uint16_t)val >> 8};
+
+	return i2c_write(cfg->i2c, i2c_data, sizeof(i2c_data),
+		     cfg->i2c_addr);
+}
+
+/**
+ * @brief Convert sensor value from millis
+ *
+ * @param val Where to store converted value in sensor_value format
+ * @param val_millis Value in millis
+ */
+static void convert_millis(struct sensor_value *val, int32_t val_millis)
+{
+	val->val1 = val_millis / 1000;
+	val->val2 = (val_millis % 1000) * 1000;
+}
+
+/**
+ * @brief Convert raw register values for specific channel
+ *
+ * @param dev MAX17262 device to access
+ * @param chan Channel number to read
+ * @param valp Returns the sensor value read on success
+ * @return 0 if successful
+ * @return -ENOTSUP for unsupported channels
+ */
+static int max17262_channel_get(const struct device *dev,
+				enum sensor_channel chan,
+				struct sensor_value *valp)
+{
+	const struct max17262_config *const config = dev->config;
+	struct max17262_data *const data = dev->data;
+	int32_t tmp;
+
+	switch (chan) {
+	case SENSOR_CHAN_GAUGE_VOLTAGE:
+		/* Get voltage in uV */
+		tmp = data->voltage * VOLTAGE_MULTIPLIER_UV;
+		/* Convert to V */
+		valp->val1 = tmp / 1000000;
+		valp->val2 = tmp % 1000000;
+		break;
+	case SENSOR_CHAN_GAUGE_AVG_CURRENT: {
+		int current;
+		/* Get avg current in nA */
+		current = data->avg_current * CURRENT_MULTIPLIER_NA;
+		/* Convert to mA */
+		valp->val1 = current / 1000000;
+		valp->val2 = current % 1000000;
+		break;
+	}
+	case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
+		valp->val1 = data->state_of_charge / 256;
+		valp->val2 = data->state_of_charge % 256 * 1000000 / 256;
+		break;
+	case SENSOR_CHAN_GAUGE_TEMP:
+		valp->val1 = data->internal_temp / 256;
+		valp->val2 = data->internal_temp % 256 * 1000000 / 256;
+		break;
+	case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY:
+		convert_millis(valp, data->full_cap);
+		break;
+	case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY:
+		convert_millis(valp, data->remaining_cap);
+		break;
+	case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY:
+		/* Get time in ms */
+		if (data->time_to_empty == 0xffff) {
+			valp->val1 = 0;
+			valp->val2 = 0;
+		} else {
+			tmp = data->time_to_empty * TIME_MULTIPLIER_MS;
+			convert_millis(valp, tmp);
+		}
+		break;
+	case SENSOR_CHAN_GAUGE_TIME_TO_FULL:
+		/* Get time in ms */
+		if (data->time_to_full == 0xffff) {
+			valp->val1 = 0;
+			valp->val2 = 0;
+		} else {
+			tmp = data->time_to_full * TIME_MULTIPLIER_MS;
+			convert_millis(valp, tmp);
+		}
+		break;
+	case SENSOR_CHAN_GAUGE_CYCLE_COUNT:
+		valp->val1 = data->cycle_count / 100;
+		valp->val2 = data->cycle_count % 100 * 10000;
+		break;
+	case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY:
+		convert_millis(valp, data->design_cap);
+		break;
+	case SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE:
+		convert_millis(valp, config->design_voltage);
+		break;
+	case SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE:
+		convert_millis(valp, config->desired_voltage);
+		break;
+	case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT:
+		valp->val1 = data->ichg_term;
+		valp->val2 = 0;
+		break;
+	case MAX17262_COULOMB_COUNTER:
+		/* Get spent capacity in mAh */
+		data->coulomb_counter = 0xffff - data->coulomb_counter;
+		valp->val1 = data->coulomb_counter / 2;
+		valp->val2 = data->coulomb_counter % 2 * 10 / 2;
+		break;
+	default:
+		LOG_ERR("Unsupported channel!");
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Read register values for supported channels
+ *
+ * @param dev MAX17262 device to access
+ * @return 0 if successful, or negative error code from I2C API
+ */
+static int max17262_sample_fetch(const struct device *dev,
+				 enum sensor_channel chan)
+{
+	struct max17262_data *data = dev->data;
+	struct {
+		int reg_addr;
+		int16_t *dest;
+	} regs[] = {
+		{ VCELL, &data->voltage },
+		{ AVG_CURRENT, &data->avg_current },
+		{ ICHG_TERM, &data->ichg_term },
+		{ REP_SOC, &data->state_of_charge },
+		{ INT_TEMP, &data->internal_temp },
+		{ REP_CAP, &data->remaining_cap },
+		{ FULL_CAP_REP, &data->full_cap },
+		{ TTE, &data->time_to_empty },
+		{ TTF, &data->time_to_full },
+		{ CYCLES, &data->cycle_count },
+		{ DESIGN_CAP, &data->design_cap },
+		{ COULOMB_COUNTER, &data->coulomb_counter },
+	};
+
+	__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
+	for (size_t i = 0; i < ARRAY_SIZE(regs); i++) {
+		int rc;
+
+		rc = max17262_reg_read(dev, regs[i].reg_addr, regs[i].dest);
+		if (rc != 0) {
+			LOG_ERR("Failed to read channel %d", chan);
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * @brief Initialise the fuel gauge
+ *
+ * @param dev MAX17262 device to access
+ * @return 0 for success
+ * @return -EINVAL if the I2C controller could not be found
+ */
+static int max17262_gauge_init(const struct device *dev)
+{
+	const struct max17262_config *const config = dev->config;
+	int16_t tmp, hibcfg;
+
+	if (!device_is_ready(config->i2c)) {
+		LOG_ERR("Could not get pointer to %s device", config->i2c->name);
+		return -EINVAL;
+	}
+
+	/* Read Status register */
+	max17262_reg_read(dev, STATUS, &tmp);
+
+	if (!(tmp & STATUS_POR)) {
+		/*
+		 * Status.POR bit is set to 1 when MAX17262 detects that
+		 * a software or hardware POR event has occurred and
+		 * therefore a custom configuration needs to be set...
+		 * If POR event did not happen (Status.POR == 0), skip
+		 * init and continue with measurements.
+		 */
+		LOG_DBG("No POR event detected - skip device configuration");
+		return 0;
+	}
+	LOG_DBG("POR detected, setting custom device configuration...");
+
+	/** STEP 1 */
+	max17262_reg_read(dev, FSTAT, &tmp);
+
+	/* Do not continue until FSTAT.DNR bit is cleared */
+	while (tmp & FSTAT_DNR) {
+		k_sleep(K_MSEC(10));
+		max17262_reg_read(dev, FSTAT, &tmp);
+	}
+
+	/** STEP 2 */
+	/* Store original HibCFG value */
+	max17262_reg_read(dev, HIBCFG, &hibcfg);
+
+	/* Exit Hibernate Mode step 1 */
+	max17262_reg_write(dev, SOFT_WAKEUP, 0x0090);
+	/* Exit Hibernate Mode step 2 */
+	max17262_reg_write(dev, HIBCFG, 0x0000);
+	/* Exit Hibernate Mode step 3 */
+	max17262_reg_write(dev, SOFT_WAKEUP, 0x0000);
+
+	/** STEP 2.1 --> OPTION 1 EZ Config (No INI file is needed) */
+	/* Write DesignCap */
+	max17262_reg_write(dev, DESIGN_CAP, config->design_cap);
+
+	/* Write IChgTerm */
+	max17262_reg_write(dev, ICHG_TERM, config->desired_charging_current);
+
+	/* Write VEmpty */
+	max17262_reg_write(dev, VEMPTY, ((config->empty_voltage / 10) << 7) |
+					  ((config->recovery_voltage / 40) & 0x7F));
+
+	/* Write ModelCFG */
+	if (config->charge_voltage > 4275) {
+		max17262_reg_write(dev, MODELCFG, 0x8400);
+	} else {
+		max17262_reg_write(dev, MODELCFG, 0x8000);
+	}
+
+	/*
+	 * Read ModelCFG.Refresh (highest bit),
+	 * proceed to Step 3 when ModelCFG.Refresh == 0
+	 */
+	max17262_reg_read(dev, MODELCFG, &tmp);
+
+	/* Do not continue until ModelCFG.Refresh == 0 */
+	while (tmp & MODELCFG_REFRESH) {
+		k_sleep(K_MSEC(10));
+		max17262_reg_read(dev, MODELCFG, &tmp);
+	}
+
+	/* Restore Original HibCFG value */
+	max17262_reg_write(dev, HIBCFG, hibcfg);
+
+	/** STEP 3 */
+	/* Read Status register */
+	max17262_reg_read(dev, STATUS, &tmp);
+
+	/* Clear PowerOnReset bit */
+	tmp &= ~STATUS_POR;
+	max17262_reg_write(dev, STATUS, tmp);
+
+	return 0;
+}
+
+static const struct sensor_driver_api max17262_battery_driver_api = {
+	.sample_fetch = max17262_sample_fetch,
+	.channel_get = max17262_channel_get,
+};
+
+#define MAX17262_INIT(n)						\
+	static struct max17262_data max17262_data_##n;			\
+									\
+	static const struct max17262_config max17262_config_##n = {	\
+		.i2c = DEVICE_DT_GET(DT_BUS(DT_DRV_INST(n))),		\
+		.i2c_addr = DT_INST_REG_ADDR(n),			\
+		.design_voltage = DT_INST_PROP(n, design_voltage),	\
+		.desired_voltage = DT_INST_PROP(n, desired_voltage),	\
+		.desired_charging_current =				\
+			DT_INST_PROP(n, desired_charging_current),	\
+		.design_cap = DT_INST_PROP(n, design_cap),		\
+		.empty_voltage = DT_INST_PROP(n, empty_voltage),	\
+		.recovery_voltage = DT_INST_PROP(n, recovery_voltage),	\
+		.charge_voltage = DT_INST_PROP(n, charge_voltage),	\
+	};								\
+									\
+	DEVICE_DT_INST_DEFINE(n, &max17262_gauge_init,			\
+			    device_pm_control_nop,			\
+			    &max17262_data_##n,				\
+			    &max17262_config_##n, POST_KERNEL,		\
+			    CONFIG_SENSOR_INIT_PRIORITY,		\
+			    &max17262_battery_driver_api);
+
+DT_INST_FOREACH_STATUS_OKAY(MAX17262_INIT)
diff --git a/drivers/sensor/max17262/max17262.h b/drivers/sensor/max17262/max17262.h
new file mode 100644
index 0000000..ed7aaa8
--- /dev/null
+++ b/drivers/sensor/max17262/max17262.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021 Matija Tudan
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef ZEPHYR_DRIVERS_SENSOR_BATTERY_MAX17262_H_
+#define ZEPHYR_DRIVERS_SENSOR_BATTERY_MAX17262_H_
+
+#define VOLTAGE_MULTIPLIER_UV	1250 / 16
+#define CURRENT_MULTIPLIER_NA	156250
+#define TIME_MULTIPLIER_MS	5625
+
+/* Register addresses */
+enum {
+	STATUS          = 0x00,
+	REP_CAP         = 0x05,
+	REP_SOC         = 0x06,
+	INT_TEMP        = 0x08,
+	VCELL           = 0x09,
+	AVG_CURRENT     = 0x0b,
+	FULL_CAP_REP    = 0x10,
+	TTE             = 0x11,
+	CYCLES          = 0x17,
+	DESIGN_CAP      = 0x18,
+	ICHG_TERM       = 0x1E,
+	TTF             = 0x20,
+	VEMPTY          = 0x3A,
+	FSTAT           = 0x3D,
+	COULOMB_COUNTER = 0x4D,
+	SOFT_WAKEUP     = 0x60,
+	HIBCFG          = 0xBA,
+	MODELCFG        = 0xDB,
+};
+
+/* Masks */
+enum {
+	FSTAT_DNR        = 0x01,
+	STATUS_POR       = 0x02,
+	MODELCFG_REFRESH = 0x8000,
+};
+
+/* MAX17262 specific channels */
+enum max17262_channel {
+	MAX17262_COULOMB_COUNTER,
+};
+
+struct max17262_data {
+	/* Current cell voltage in units of 1.25/16mV */
+	uint16_t voltage;
+	/* Average current in units of 156.25uA */
+	int16_t avg_current;
+	/* Desired charging current in mA */
+	uint16_t ichg_term;
+	/* Remaining capacity as a %age */
+	uint16_t state_of_charge;
+	/* Internal temperature in units of 1/256 degrees C */
+	int16_t internal_temp;
+	/* Full charge capacity in mAh */
+	uint16_t full_cap;
+	/* Remaining capacity in mAh */
+	uint16_t remaining_cap;
+	/* Time to empty in seconds */
+	uint16_t time_to_empty;
+	/* Time to full in seconds */
+	uint16_t time_to_full;
+	/* Cycle count in 1/100ths (number of charge/discharge cycles) */
+	uint16_t cycle_count;
+	/* Battery capacity in mAh */
+	uint16_t design_cap;
+	/* Spent capacity in mAh */
+	uint16_t coulomb_counter;
+};
+
+struct max17262_config {
+	const struct device *i2c;
+	uint16_t i2c_addr;
+	/* Value of Rsense resistor in milliohms (typicallly 5 or 10) */
+	uint16_t rsense_mohms;
+	/* Design voltage of cell in mV */
+	uint16_t design_voltage;
+	/* Desired voltage of cell in mV */
+	uint16_t desired_voltage;
+	/* Desired charging current in mA */
+	uint16_t desired_charging_current;
+	/* Battery capacity in mAh */
+	uint16_t design_cap;
+	/* Empty voltage detection in mV */
+	uint16_t empty_voltage;
+	/* Recovery voltage detection in mV */
+	uint16_t recovery_voltage;
+	/* Defined charge voltage value in mV */
+	uint16_t charge_voltage;
+};
+
+#endif
diff --git a/dts/bindings/sensor/maxim,max17262.yaml b/dts/bindings/sensor/maxim,max17262.yaml
new file mode 100644
index 0000000..ddfd3e7
--- /dev/null
+++ b/dts/bindings/sensor/maxim,max17262.yaml
@@ -0,0 +1,47 @@
+#
+# Copyright 2020 Matija Tudan
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+description: Maxim MAX17262 Fuel Gauge
+
+compatible: "maxim,max17262"
+
+include: i2c-device.yaml
+
+properties:
+    design-voltage:
+      type: int
+      required: true
+      description: Battery Design Voltage in mV (3300 to 4400)
+
+    desired-voltage:
+      type: int
+      required: true
+      description: Battery Desired Voltage in mV (3300 to 4400)
+
+    desired-charging-current:
+      type: int
+      required: true
+      description: Battery Design Charging Current in mA (e.g. 2000)
+
+    design-cap:
+      type: int
+      required: true
+      description: Battery Capacity in mAh (default 3000)
+
+    empty-voltage:
+      type: int
+      required: true
+      description: Empty voltage target during load in mV (default 3300)
+
+    recovery-voltage:
+      type: int
+      required: true
+      description: The voltage level for clearing empty detection in mV (default 3880)
+
+    charge-voltage:
+      type: int
+      required: true
+      description: Charge voltage in mV
diff --git a/samples/sensor/max17262/CMakeLists.txt b/samples/sensor/max17262/CMakeLists.txt
new file mode 100644
index 0000000..b1d92ae
--- /dev/null
+++ b/samples/sensor/max17262/CMakeLists.txt
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: Apache-2.0
+
+cmake_minimum_required(VERSION 3.13.1)
+find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
+project(max17262)
+
+FILE(GLOB app_sources src/*.c)
+target_sources(app PRIVATE ${app_sources})
diff --git a/samples/sensor/max17262/README.rst b/samples/sensor/max17262/README.rst
new file mode 100644
index 0000000..d540399
--- /dev/null
+++ b/samples/sensor/max17262/README.rst
@@ -0,0 +1,57 @@
+.. _max17262:
+
+MAX17262 Fuel Gauge Sensor
+###################################
+
+Overview
+********
+
+This sample application periodically reads voltage, current and temperature
+data from the MAX17262 device that implements SENSOR_CHAN_GAUGE_VOLTAGE,
+SENSOR_CHAN_GAUGE_AVG_CURRENT, and SENSOR_CHAN_GAUGE_TEMP.
+
+Requirements
+************
+
+The MAX17262 is an ultra-low power fuel-gauge IC which implements the Maxim
+ModelGauge m5 algorithm. The IC monitors a single-cell battery pack and
+supports internal current sensing for up to 3.1A pulse current. The IC
+provides best performance for batteries with 100mAhr to 6Ahr capacity.
+
+This sample requires a board which provides a configuration for Arduino
+connectors and defines node aliases for the I2C interface.
+For more info about the node structure see
+:zephyr_file:`samples/sensor/max17262/app.overlay`
+
+Building and Running
+********************
+
+This sample application uses an MAX17262 sensor connected to a board via I2C.
+Connect the sensor pins according to the connection diagram given in the
+`max17262 datasheet`_.
+
+.. zephyr-app-commands::
+   :zephyr-app: samples/sensor/max17262
+   :board: nrf52840dk_nrf52840
+   :goals: build flash
+   :compact:
+
+Sample Output
+=============
+To check output of this sample , any serial console program can be used.
+This example uses ``picocom`` on the serial port ``/dev/ttyUSB0``:
+
+.. code-block:: console
+
+        $ sudo picocom -D /dev/ttyUSB0
+
+.. code-block:: console
+
+        V: 3.626406 V; I: -3.437500 mA; T: 28.011718 °C
+        V: 3.626406 V; I: -3.437500 mA; T: 28.011718 °C
+        V: 3.626406 V; I: -3.437500 mA; T: 28.011718 °C
+
+References
+***********
+
+.. _max17262 datasheet: https://datasheets.maximintegrated.com/en/ds/MAX17262.pdf
diff --git a/samples/sensor/max17262/app.overlay b/samples/sensor/max17262/app.overlay
new file mode 100644
index 0000000..c330fb0
--- /dev/null
+++ b/samples/sensor/max17262/app.overlay
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021 Matija Tudan
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+&arduino_i2c {
+	status = "okay";
+
+	max17262@36 {
+		compatible = "maxim,max17262";
+		label = "MAX17262";
+		reg = <0x36>;
+		design-voltage = <3600>;
+		desired-voltage = <3600>;
+		desired-charging-current = <2000>;
+		design-cap = <17000>;
+		empty-voltage = <3300>;
+		recovery-voltage = <3880>;
+		charge-voltage = <3600>;
+		status = "okay";
+	};
+};
diff --git a/samples/sensor/max17262/prj.conf b/samples/sensor/max17262/prj.conf
new file mode 100644
index 0000000..b253952
--- /dev/null
+++ b/samples/sensor/max17262/prj.conf
@@ -0,0 +1,5 @@
+CONFIG_I2C=y
+CONFIG_LOG=y
+CONFIG_SENSOR=y
+CONFIG_MAX17262=y
+CONFIG_CBPRINTF_FP_SUPPORT=y
diff --git a/samples/sensor/max17262/sample.yaml b/samples/sensor/max17262/sample.yaml
new file mode 100644
index 0000000..097a40c
--- /dev/null
+++ b/samples/sensor/max17262/sample.yaml
@@ -0,0 +1,15 @@
+sample:
+  description: MAX17262 sensor sample
+  name: MAX17262 sample
+tests:
+  sample.sensor.max17262:
+    build_only: true
+    depends_on: arduino_i2c
+    harness: console
+    tags: sensors
+    platform_allow: nrf52840dk_nrf52840
+    harness_config:
+        type: one_line
+        regex:
+            - "V: (.*) V; I: (.*) mA; T: (.*) °C"
+        fixture: fixture_i2c_max17262
diff --git a/samples/sensor/max17262/src/main.c b/samples/sensor/max17262/src/main.c
new file mode 100644
index 0000000..69d0254
--- /dev/null
+++ b/samples/sensor/max17262/src/main.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Matija Tudan
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <zephyr.h>
+#include <device.h>
+#include <devicetree.h>
+#include <drivers/sensor.h>
+
+#define MAX17262 DT_INST(0, maxim_max17262)
+
+#if DT_NODE_HAS_STATUS(MAX17262, okay)
+#define MAX17262_LABEL DT_LABEL(MAX17262)
+#else
+#error Your devicetree has no enabled nodes with compatible "maxim,max17262"
+#define MAX17262_LABEL "<none>"
+#endif
+
+void main(void)
+{
+	const struct device *dev = device_get_binding(MAX17262_LABEL);
+
+	if (dev == NULL) {
+		printk("No device %s found...\n", dev->name);
+		return;
+	}
+	printk("Found device %s\n", dev->name);
+
+	while (1) {
+		struct sensor_value voltage, avg_current, temperature;
+		float i_avg;
+
+		sensor_sample_fetch(dev);
+		sensor_channel_get(dev, SENSOR_CHAN_GAUGE_VOLTAGE, &voltage);
+		sensor_channel_get(dev, SENSOR_CHAN_GAUGE_AVG_CURRENT,
+						  &avg_current);
+		sensor_channel_get(dev, SENSOR_CHAN_GAUGE_TEMP, &temperature);
+
+		i_avg = avg_current.val1 + (avg_current.val2 / 1000000.0);
+
+		printk("V: %d.%06d V; I: %f mA; T: %d.%06d °C\n",
+		      voltage.val1, voltage.val2, i_avg,
+		      temperature.val1, temperature.val2);
+
+		k_sleep(K_MSEC(1000));
+	}
+}
diff --git a/tests/drivers/build_all/i2c.dtsi b/tests/drivers/build_all/i2c.dtsi
index 13fc1f6..35be384 100644
--- a/tests/drivers/build_all/i2c.dtsi
+++ b/tests/drivers/build_all/i2c.dtsi
@@ -573,6 +573,19 @@
 	v-empty = <3300>;
 };
 
+test_i2c_max17262: max17262@36 {
+	compatible = "maxim,max17262";
+	label = "MAX17262";
+	reg = <0x36>;
+	design-voltage = <3600>;
+	desired-voltage = <3600>;
+	desired-charging-current = <2000>;
+	design-cap = <17000>;
+	empty-voltage = <3300>;
+	recovery-voltage = <3880>;
+	charge-voltage = <3600>;
+};
+
 test_i2c_vcnl4040: vcnl4040@60 {
 	compatible = "vishay,vcnl4040";
 	label = "VCNL4040";
diff --git a/tests/drivers/build_all/sensors_i_z.conf b/tests/drivers/build_all/sensors_i_z.conf
index ab8be05..b404b5e 100644
--- a/tests/drivers/build_all/sensors_i_z.conf
+++ b/tests/drivers/build_all/sensors_i_z.conf
@@ -26,6 +26,7 @@
 CONFIG_MAX30101=y
 CONFIG_MAX44009=y
 CONFIG_MAX17055=y
+CONFIG_MAX17262=y
 CONFIG_MAX6675=y
 CONFIG_MCP9808=y
 CONFIG_MPU6050=y