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