sensor: max17055: Add MAX17055 driver
Add support for the Maxim MAX17055 fueld-gauge sensor. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
9b8c04401d
commit
ee34aced6a
9 changed files with 363 additions and 0 deletions
|
@ -47,6 +47,7 @@ add_subdirectory_ifdef(CONFIG_LSM6DSL lsm6dsl)
|
||||||
add_subdirectory_ifdef(CONFIG_LSM6DSO lsm6dso)
|
add_subdirectory_ifdef(CONFIG_LSM6DSO lsm6dso)
|
||||||
add_subdirectory_ifdef(CONFIG_LSM9DS0_GYRO lsm9ds0_gyro)
|
add_subdirectory_ifdef(CONFIG_LSM9DS0_GYRO lsm9ds0_gyro)
|
||||||
add_subdirectory_ifdef(CONFIG_LSM9DS0_MFD lsm9ds0_mfd)
|
add_subdirectory_ifdef(CONFIG_LSM9DS0_MFD lsm9ds0_mfd)
|
||||||
|
add_subdirectory_ifdef(CONFIG_MAX17055 max17055)
|
||||||
add_subdirectory_ifdef(CONFIG_MAX30101 max30101)
|
add_subdirectory_ifdef(CONFIG_MAX30101 max30101)
|
||||||
add_subdirectory_ifdef(CONFIG_MAX44009 max44009)
|
add_subdirectory_ifdef(CONFIG_MAX44009 max44009)
|
||||||
add_subdirectory_ifdef(CONFIG_MCP9808 mcp9808)
|
add_subdirectory_ifdef(CONFIG_MCP9808 mcp9808)
|
||||||
|
|
|
@ -123,6 +123,8 @@ source "drivers/sensor/lsm9ds0_gyro/Kconfig"
|
||||||
|
|
||||||
source "drivers/sensor/lsm9ds0_mfd/Kconfig"
|
source "drivers/sensor/lsm9ds0_mfd/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/sensor/max17055/Kconfig"
|
||||||
|
|
||||||
source "drivers/sensor/max30101/Kconfig"
|
source "drivers/sensor/max30101/Kconfig"
|
||||||
|
|
||||||
source "drivers/sensor/max44009/Kconfig"
|
source "drivers/sensor/max44009/Kconfig"
|
||||||
|
|
7
drivers/sensor/max17055/CMakeLists.txt
Normal file
7
drivers/sensor/max17055/CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Copyright 2020 Google LLC
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_MAX17055 max17055.c)
|
12
drivers/sensor/max17055/Kconfig
Normal file
12
drivers/sensor/max17055/Kconfig
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Copyright 2020 Google LLC
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
config MAX17055
|
||||||
|
bool "MAX17055 Fuel Gauge"
|
||||||
|
depends on I2C && HAS_DTS_I2C
|
||||||
|
help
|
||||||
|
Enable I2C-based driver for MAX17055 Fuel Gauge. This driver supports
|
||||||
|
reading various sensor settings including charge level percentage,
|
||||||
|
time to full/empty, design voltage, temperature and remaining
|
||||||
|
capacity in mA.
|
237
drivers/sensor/max17055/max17055.c
Normal file
237
drivers/sensor/max17055/max17055.c
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 Google LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <drivers/i2c.h>
|
||||||
|
#include <drivers/sensor.h>
|
||||||
|
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(max17055, CONFIG_SENSOR_LOG_LEVEL);
|
||||||
|
|
||||||
|
#include "max17055.h"
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT maxim_max17055
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read a register value
|
||||||
|
*
|
||||||
|
* Registers have an address and a 16-bit value
|
||||||
|
*
|
||||||
|
* @param priv Private data for the driver
|
||||||
|
* @param reg_addr Register address to read
|
||||||
|
* @param val Place to put the value on success
|
||||||
|
* @return 0 if successful, or negative error code from I2C API
|
||||||
|
*/
|
||||||
|
static int max17055_reg_read(struct max17055_data *priv, int reg_addr,
|
||||||
|
int16_t *valp)
|
||||||
|
{
|
||||||
|
uint8_t i2c_data[2];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = i2c_burst_read(priv->i2c, DT_INST_REG_ADDR(0), reg_addr,
|
||||||
|
i2c_data, 2);
|
||||||
|
if (rc < 0) {
|
||||||
|
LOG_ERR("Unable to read register");
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
*valp = (i2c_data[1] << 8) | i2c_data[0];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert capacity in MAX17055 units to milliamps
|
||||||
|
*
|
||||||
|
* @param rsense_mohms Value of Rsense in milliohms
|
||||||
|
* @param val Value to convert (taken from a MAX17055 register)
|
||||||
|
* @return corresponding value in milliamps
|
||||||
|
*/
|
||||||
|
static int capacity_to_ma(unsigned int rsense_mohms, int16_t val)
|
||||||
|
{
|
||||||
|
int lsb_units, rem;
|
||||||
|
|
||||||
|
/* Get units for the LSB in uA */
|
||||||
|
lsb_units = 5 * 1000 / rsense_mohms;
|
||||||
|
/* Get remaining capacity in uA */
|
||||||
|
rem = val * lsb_units;
|
||||||
|
|
||||||
|
return rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_millis(struct sensor_value *val, int val_millis)
|
||||||
|
{
|
||||||
|
val->val1 = val_millis / 1000;
|
||||||
|
val->val2 = (val_millis % 1000) * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sensor value get
|
||||||
|
*
|
||||||
|
* @param dev MAX17055 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 max17055_channel_get(struct device *dev, enum sensor_channel chan,
|
||||||
|
struct sensor_value *valp)
|
||||||
|
{
|
||||||
|
const struct max17055_config *const config = dev->config_info;
|
||||||
|
struct max17055_data *const priv = dev->driver_data;
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
switch (chan) {
|
||||||
|
case SENSOR_CHAN_GAUGE_VOLTAGE:
|
||||||
|
/* Get voltage in uV */
|
||||||
|
tmp = priv->voltage * 1250 / 16;
|
||||||
|
valp->val1 = tmp / 1000000;
|
||||||
|
valp->val2 = tmp % 1000000;
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_AVG_CURRENT: {
|
||||||
|
int cap_ma;
|
||||||
|
|
||||||
|
cap_ma = capacity_to_ma(config->rsense_mohms,
|
||||||
|
priv->avg_current);
|
||||||
|
set_millis(valp, cap_ma);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
|
||||||
|
valp->val1 = priv->state_of_charge / 256;
|
||||||
|
valp->val2 = priv->state_of_charge % 256 * 1000000 / 256;
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_TEMP:
|
||||||
|
valp->val1 = priv->internal_temp / 256;
|
||||||
|
valp->val2 = priv->internal_temp % 256 * 1000000 / 256;
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY:
|
||||||
|
tmp = capacity_to_ma(config->rsense_mohms, priv->full_cap);
|
||||||
|
set_millis(valp, tmp);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY:
|
||||||
|
tmp = capacity_to_ma(config->rsense_mohms, priv->remaining_cap);
|
||||||
|
set_millis(valp, tmp);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_TIME_TO_EMPTY:
|
||||||
|
/* Get time in ms */
|
||||||
|
if (priv->time_to_empty == 0xffff) {
|
||||||
|
valp->val1 = 0;
|
||||||
|
valp->val2 = 0;
|
||||||
|
} else {
|
||||||
|
tmp = priv->time_to_empty * 5625;
|
||||||
|
set_millis(valp, tmp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_TIME_TO_FULL:
|
||||||
|
if (priv->time_to_full == 0xffff) {
|
||||||
|
valp->val1 = 0;
|
||||||
|
valp->val2 = 0;
|
||||||
|
} else {
|
||||||
|
/* Get time in ms */
|
||||||
|
tmp = priv->time_to_full * 5625;
|
||||||
|
set_millis(valp, tmp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_CYCLE_COUNT:
|
||||||
|
valp->val1 = priv->cycle_count / 100;
|
||||||
|
valp->val2 = priv->cycle_count % 100 * 10000;
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY:
|
||||||
|
tmp = capacity_to_ma(config->rsense_mohms, priv->design_cap);
|
||||||
|
set_millis(valp, tmp);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE:
|
||||||
|
set_millis(valp, config->design_voltage);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE:
|
||||||
|
set_millis(valp, config->desired_voltage);
|
||||||
|
break;
|
||||||
|
case SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT:
|
||||||
|
valp->val1 = config->desired_charging_current;
|
||||||
|
valp->val2 = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max17055_sample_fetch(struct device *dev, enum sensor_channel chan)
|
||||||
|
{
|
||||||
|
struct max17055_data *priv = dev->driver_data;
|
||||||
|
struct {
|
||||||
|
int reg_addr;
|
||||||
|
int16_t *dest;
|
||||||
|
} regs[] = {
|
||||||
|
{ VCELL, &priv->voltage },
|
||||||
|
{ AVG_CURRENT, &priv->avg_current },
|
||||||
|
{ REP_SOC, &priv->state_of_charge },
|
||||||
|
{ INT_TEMP, &priv->internal_temp },
|
||||||
|
{ REP_CAP, &priv->remaining_cap },
|
||||||
|
{ FULL_CAP_REP, &priv->full_cap },
|
||||||
|
{ TTE, &priv->time_to_empty },
|
||||||
|
{ TTF, &priv->time_to_full },
|
||||||
|
{ CYCLES, &priv->cycle_count },
|
||||||
|
{ DESIGN_CAP, &priv->design_cap },
|
||||||
|
};
|
||||||
|
|
||||||
|
__ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL);
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = max17055_reg_read(priv, 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
|
||||||
|
*
|
||||||
|
* @return 0 for success
|
||||||
|
* @return -EINVAL if the I2C controller could not be found
|
||||||
|
*/
|
||||||
|
static int max17055_gauge_init(struct device *dev)
|
||||||
|
{
|
||||||
|
struct max17055_data *priv = dev->driver_data;
|
||||||
|
const struct max17055_config *const config = dev->config_info;
|
||||||
|
|
||||||
|
priv->i2c = device_get_binding(config->bus_name);
|
||||||
|
if (!priv->i2c) {
|
||||||
|
LOG_ERR("Could not get pointer to %s device", config->bus_name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct sensor_driver_api max17055_battery_driver_api = {
|
||||||
|
.sample_fetch = max17055_sample_fetch,
|
||||||
|
.channel_get = max17055_channel_get,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX17055_INIT(index) \
|
||||||
|
static struct max17055_data max17055_driver_##index; \
|
||||||
|
\
|
||||||
|
static const struct max17055_config max17055_config_##index = { \
|
||||||
|
.bus_name = DT_INST_BUS_LABEL(index), \
|
||||||
|
.rsense_mohms = DT_INST_PROP(index, rsense_mohms), \
|
||||||
|
.design_voltage = DT_INST_PROP(index, design_voltage), \
|
||||||
|
.desired_voltage = DT_INST_PROP(index, desired_voltage), \
|
||||||
|
.desired_charging_current = \
|
||||||
|
DT_INST_PROP(index, desired_charging_current), \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
DEVICE_AND_API_INIT(max17055_##index, DT_INST_LABEL(index), \
|
||||||
|
&max17055_gauge_init, &max17055_driver_##index, \
|
||||||
|
&max17055_config_##index, POST_KERNEL, \
|
||||||
|
CONFIG_SENSOR_INIT_PRIORITY, \
|
||||||
|
&max17055_battery_driver_api)
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(MAX17055_INIT);
|
60
drivers/sensor/max17055/max17055.h
Normal file
60
drivers/sensor/max17055/max17055.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 Google LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_DRIVERS_SENSOR_BATTERY_MAX17055_H_
|
||||||
|
#define ZEPHYR_DRIVERS_SENSOR_BATTERY_MAX17055_H_
|
||||||
|
|
||||||
|
/* Register addresses */
|
||||||
|
enum {
|
||||||
|
REP_CAP = 0x5,
|
||||||
|
REP_SOC = 0x6,
|
||||||
|
INT_TEMP = 0x8,
|
||||||
|
VCELL = 0x9,
|
||||||
|
AVG_CURRENT = 0xb,
|
||||||
|
FULL_CAP_REP = 0x10,
|
||||||
|
TTE = 0x11,
|
||||||
|
CYCLES = 0x17,
|
||||||
|
DESIGN_CAP = 0x18,
|
||||||
|
TTF = 0x20,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct max17055_data {
|
||||||
|
struct device *i2c;
|
||||||
|
/* Current cell voltage in units of 1.25/16mV */
|
||||||
|
uint16_t voltage;
|
||||||
|
/* Average current in units of 1.5625uV / Rsense */
|
||||||
|
int16_t avg_current;
|
||||||
|
/* 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 5/Rsense uA */
|
||||||
|
uint16_t full_cap;
|
||||||
|
/* Remaining capacity in 5/Rsense uA */
|
||||||
|
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;
|
||||||
|
/* Design capacity in 5/Rsense uA */
|
||||||
|
uint16_t design_cap;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct max17055_config {
|
||||||
|
char *bus_name;
|
||||||
|
/* 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
33
dts/bindings/sensor/maxim,max17055.yaml
Normal file
33
dts/bindings/sensor/maxim,max17055.yaml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#
|
||||||
|
# Copyright 2020 Google LLC
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
description: Maxim MAX17055 Fuel Gauge
|
||||||
|
|
||||||
|
compatible: "maxim,max17055"
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
rsense-mohms:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: >
|
||||||
|
Value of Rsense resistor in milliohms (e.g. 5). It cannot be 0.
|
|
@ -543,3 +543,13 @@ test_i2c_itds: itds@18 {
|
||||||
reg = <0x18>;
|
reg = <0x18>;
|
||||||
int-gpios = <&test_gpio 0 0>;
|
int-gpios = <&test_gpio 0 0>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test_i2c_max17055: max17055@49 {
|
||||||
|
compatible = "maxim,max17055";
|
||||||
|
label = "max17055";
|
||||||
|
reg = <0x49>;
|
||||||
|
design-voltage = <3860>;
|
||||||
|
desired-voltage = <4400>;
|
||||||
|
desired-charging-current = <2000>;
|
||||||
|
rsense-mohms = <5>;
|
||||||
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ CONFIG_LSM9DS0_GYRO=y
|
||||||
CONFIG_LSM9DS0_MFD=y
|
CONFIG_LSM9DS0_MFD=y
|
||||||
CONFIG_MAX30101=y
|
CONFIG_MAX30101=y
|
||||||
CONFIG_MAX44009=y
|
CONFIG_MAX44009=y
|
||||||
|
CONFIG_MAX17055=y
|
||||||
CONFIG_MCP9808=y
|
CONFIG_MCP9808=y
|
||||||
CONFIG_MPU6050=y
|
CONFIG_MPU6050=y
|
||||||
CONFIG_MS5607=y
|
CONFIG_MS5607=y
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue