sensor: bq274xx: Add BQ27421 driver

Add support for TI BQ27421 fuel gauge sensor

Signed-off-by: Parthiban Nallathambi <parthiban@linumiz.com>
Signed-off-by: NavinSankar Velliangiri <navin@linumiz.com>
This commit is contained in:
Parthiban Nallathambi 2020-03-19 19:27:43 +01:00 committed by Maureen Helm
commit e65b14c2b6
10 changed files with 828 additions and 0 deletions

View file

@ -15,6 +15,7 @@ add_subdirectory_ifdef(CONFIG_BME680 bme680)
add_subdirectory_ifdef(CONFIG_BMG160 bmg160)
add_subdirectory_ifdef(CONFIG_BMI160 bmi160)
add_subdirectory_ifdef(CONFIG_BMM150 bmm150)
add_subdirectory_ifdef(CONFIG_BQ274XX bq274xx)
add_subdirectory_ifdef(CONFIG_CCS811 ccs811)
add_subdirectory_ifdef(CONFIG_DHT dht)
add_subdirectory_ifdef(CONFIG_ENS210 ens210)

View file

@ -59,6 +59,8 @@ source "drivers/sensor/bmi160/Kconfig"
source "drivers/sensor/bmm150/Kconfig"
source "drivers/sensor/bq274xx/Kconfig"
source "drivers/sensor/ccs811/Kconfig"
source "drivers/sensor/dht/Kconfig"

View file

@ -0,0 +1,7 @@
# Copyright (c) 2020 Linumiz
#
# SPDX-License-Identifier: Apache-2.0
zephyr_library()
zephyr_library_sources_ifdef(CONFIG_BQ274XX bq274xx.c)

View file

@ -0,0 +1,9 @@
# Copyright (c) 2020 Linumiz
#
# SPDX-License-Identifier: Apache-2.0
config BQ274XX
bool "BQ274xx Fuel Gauge"
depends on (I2C && HAS_DTS_I2C)
help
Enable I2C-based driver for BQ274xx Fuel Gauge.

View file

@ -0,0 +1,633 @@
/*
* Copyright (c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT ti_bq274xx
#include <drivers/i2c.h>
#include <init.h>
#include <drivers/sensor.h>
#include <sys/__assert.h>
#include <string.h>
#include <sys/byteorder.h>
#include "bq274xx.h"
#define BQ274XX_SUBCLASS_DELAY 5 /* subclass 64 & 82 needs 5ms delay */
static int bq274xx_command_reg_read(struct bq274xx_data *bq274xx, u8_t reg_addr,
s16_t *val)
{
u8_t i2c_data[2];
int status;
status = i2c_burst_read(bq274xx->i2c, DT_INST_REG_ADDR(0), reg_addr,
i2c_data, 2);
if (status < 0) {
LOG_ERR("Unable to read register");
return -EIO;
}
*val = (i2c_data[1] << 8) | i2c_data[0];
return 0;
}
static int bq274xx_control_reg_write(struct bq274xx_data *bq274xx,
u16_t subcommand)
{
u8_t i2c_data, reg_addr;
int status = 0;
reg_addr = BQ274XX_COMMAND_CONTROL_LOW;
i2c_data = (u8_t)((subcommand)&0x00FF);
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0), reg_addr,
i2c_data);
if (status < 0) {
LOG_ERR("Failed to write into control low register");
return -EIO;
}
k_msleep(BQ274XX_SUBCLASS_DELAY);
reg_addr = BQ274XX_COMMAND_CONTROL_HIGH;
i2c_data = (u8_t)((subcommand >> 8) & 0x00FF);
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0), reg_addr,
i2c_data);
if (status < 0) {
LOG_ERR("Failed to write into control high register");
return -EIO;
}
return 0;
}
static int bq274xx_command_reg_write(struct bq274xx_data *bq274xx, u8_t command,
u8_t data)
{
u8_t i2c_data, reg_addr;
int status = 0;
reg_addr = command;
i2c_data = data;
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0), reg_addr,
i2c_data);
if (status < 0) {
LOG_ERR("Failed to write into control register");
return -EIO;
}
return 0;
}
static int bq274xx_read_data_block(struct bq274xx_data *bq274xx, u8_t offset,
u8_t *data, u8_t bytes)
{
u8_t i2c_data;
int status = 0;
i2c_data = BQ274XX_EXTENDED_BLOCKDATA_START + offset;
status = i2c_burst_read(bq274xx->i2c, DT_INST_REG_ADDR(0), i2c_data,
data, bytes);
if (status < 0) {
LOG_ERR("Failed to read block");
return -EIO;
}
k_msleep(BQ274XX_SUBCLASS_DELAY);
return 0;
}
static int bq274xx_get_device_type(struct bq274xx_data *bq274xx, u16_t *val)
{
int status;
status =
bq274xx_control_reg_write(bq274xx, BQ274XX_CONTROL_DEVICE_TYPE);
if (status < 0) {
LOG_ERR("Unable to write control register");
return -EIO;
}
status = bq274xx_command_reg_read(bq274xx, BQ274XX_COMMAND_CONTROL_LOW,
val);
if (status < 0) {
LOG_ERR("Unable to read register");
return -EIO;
}
return 0;
}
/**
* @brief sensor value get
*
* @return -ENOTSUP for unsupported channels
*/
static int bq274xx_channel_get(struct device *dev, enum sensor_channel chan,
struct sensor_value *val)
{
struct bq274xx_data *bq274xx = dev->driver_data;
float int_temp;
switch (chan) {
case SENSOR_CHAN_GAUGE_VOLTAGE:
val->val1 = ((bq274xx->voltage / 1000));
val->val2 = ((bq274xx->voltage % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_AVG_CURRENT:
val->val1 = ((bq274xx->avg_current / 1000));
val->val2 = ((bq274xx->avg_current % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_STDBY_CURRENT:
val->val1 = ((bq274xx->stdby_current / 1000));
val->val2 = ((bq274xx->stdby_current % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT:
val->val1 = ((bq274xx->max_load_current / 1000));
val->val2 = ((bq274xx->max_load_current % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_TEMP:
int_temp = (bq274xx->internal_temperature * 0.1);
int_temp = int_temp - 273.15;
val->val1 = (s32_t)int_temp;
val->val2 = (int_temp - (s32_t)int_temp) * 1000000;
break;
case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
val->val1 = bq274xx->state_of_charge;
val->val2 = 0;
break;
case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH:
val->val1 = bq274xx->state_of_health;
val->val2 = 0;
break;
case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY:
val->val1 = (bq274xx->full_charge_capacity / 1000);
val->val2 = ((bq274xx->full_charge_capacity % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY:
val->val1 = (bq274xx->remaining_charge_capacity / 1000);
val->val2 =
((bq274xx->remaining_charge_capacity % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY:
val->val1 = (bq274xx->nom_avail_capacity / 1000);
val->val2 = ((bq274xx->nom_avail_capacity % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY:
val->val1 = (bq274xx->full_avail_capacity / 1000);
val->val2 = ((bq274xx->full_avail_capacity % 1000) * 1000U);
break;
case SENSOR_CHAN_GAUGE_AVG_POWER:
val->val1 = (bq274xx->avg_power / 1000);
val->val2 = ((bq274xx->avg_power % 1000) * 1000U);
break;
default:
return -ENOTSUP;
}
return 0;
}
static int bq274xx_sample_fetch(struct device *dev, enum sensor_channel chan)
{
struct bq274xx_data *bq274xx = dev->driver_data;
int status = 0;
switch (chan) {
case SENSOR_CHAN_GAUGE_VOLTAGE:
status = bq274xx_command_reg_read(
bq274xx, BQ274XX_COMMAND_VOLTAGE, &bq274xx->voltage);
if (status < 0) {
LOG_ERR("Failed to read voltage");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_AVG_CURRENT:
status = bq274xx_command_reg_read(bq274xx,
BQ274XX_COMMAND_AVG_CURRENT,
&bq274xx->avg_current);
if (status < 0) {
LOG_ERR("Failed to read average current ");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_TEMP:
status = bq274xx_command_reg_read(
bq274xx, BQ274XX_COMMAND_INT_TEMP,
&bq274xx->internal_temperature);
if (status < 0) {
LOG_ERR("Failed to read internal temperature");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_STDBY_CURRENT:
status = bq274xx_command_reg_read(bq274xx,
BQ274XX_COMMAND_STDBY_CURRENT,
&bq274xx->stdby_current);
if (status < 0) {
LOG_ERR("Failed to read standby current");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT:
status = bq274xx_command_reg_read(bq274xx,
BQ274XX_COMMAND_MAX_CURRENT,
&bq274xx->max_load_current);
if (status < 0) {
LOG_ERR("Failed to read maximum current");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
status = bq274xx_command_reg_read(bq274xx, BQ274XX_COMMAND_SOC,
&bq274xx->state_of_charge);
if (status < 0) {
LOG_ERR("Failed to read state of charge");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY:
status = bq274xx_command_reg_read(
bq274xx, BQ274XX_COMMAND_FULL_CAPACITY,
&bq274xx->full_charge_capacity);
if (status < 0) {
LOG_ERR("Failed to read full charge capacity");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY:
status = bq274xx_command_reg_read(
bq274xx, BQ274XX_COMMAND_REM_CAPACITY,
&bq274xx->remaining_charge_capacity);
if (status < 0) {
LOG_ERR("Failed to read remaining charge capacity");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY:
status = bq274xx_command_reg_read(bq274xx,
BQ274XX_COMMAND_NOM_CAPACITY,
&bq274xx->nom_avail_capacity);
if (status < 0) {
LOG_ERR("Failed to read nominal available capacity");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY:
status =
bq274xx_command_reg_read(bq274xx,
BQ274XX_COMMAND_AVAIL_CAPACITY,
&bq274xx->full_avail_capacity);
if (status < 0) {
LOG_ERR("Failed to read full available capacity");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_AVG_POWER:
status = bq274xx_command_reg_read(bq274xx,
BQ274XX_COMMAND_AVG_POWER,
&bq274xx->avg_power);
if (status < 0) {
LOG_ERR("Failed to read battery average power");
return -EIO;
}
break;
case SENSOR_CHAN_GAUGE_STATE_OF_HEALTH:
status = bq274xx_command_reg_read(bq274xx, BQ274XX_COMMAND_SOH,
&bq274xx->state_of_health);
bq274xx->state_of_health = (bq274xx->state_of_health) & 0x00FF;
if (status < 0) {
LOG_ERR("Failed to read state of health");
return -EIO;
}
break;
default:
return -ENOTSUP;
}
return 0;
}
/**
* @brief initialise the fuel gauge
*
* @return 0 for success
*/
static int bq274xx_gauge_init(struct device *dev)
{
struct bq274xx_data *bq274xx = dev->driver_data;
const struct bq274xx_config *const config = dev->config->config_info;
int status = 0;
u8_t tmp_checksum = 0, checksum_old = 0, checksum_new = 0;
u16_t flags = 0, designenergy_mwh = 0, taperrate = 0, id;
u8_t designcap_msb, designcap_lsb, designenergy_msb, designenergy_lsb,
terminatevolt_msb, terminatevolt_lsb, taperrate_msb,
taperrate_lsb;
u8_t block[32];
designenergy_mwh = (u16_t)3.7 * config->design_capacity;
taperrate =
(u16_t)config->design_capacity / (0.1 * config->taper_current);
bq274xx->i2c = device_get_binding(config->bus_name);
if (bq274xx == NULL) {
LOG_ERR("Could not get pointer to %s device.",
config->bus_name);
return -EINVAL;
}
status = bq274xx_get_device_type(bq274xx, &id);
if (status < 0) {
LOG_ERR("Unable to get device ID");
return -EIO;
}
if (id != BQ274XX_DEVICE_ID) {
LOG_ERR("Invalid Device");
return -EINVAL;
}
/** Unseal the battery control register **/
status = bq274xx_control_reg_write(bq274xx, BQ274XX_UNSEAL_KEY);
if (status < 0) {
LOG_ERR("Unable to unseal the battery");
return -EIO;
}
status = bq274xx_control_reg_write(bq274xx, BQ274XX_UNSEAL_KEY);
if (status < 0) {
LOG_ERR("Unable to unseal the battery");
return -EIO;
}
/* Send CFG_UPDATE */
status = bq274xx_control_reg_write(bq274xx,
BQ274XX_CONTROL_SET_CFGUPDATE);
if (status < 0) {
LOG_ERR("Unable to set CFGUpdate");
return -EIO;
}
/** Step to place the Gauge into CONFIG UPDATE Mode **/
do {
status = bq274xx_command_reg_read(
bq274xx, BQ274XX_COMMAND_FLAGS, &flags);
if (status < 0) {
LOG_ERR("Unable to read flags");
return -EIO;
}
if (!(flags & 0x0010)) {
k_msleep(BQ274XX_SUBCLASS_DELAY * 10);
}
} while (!(flags & 0x0010));
status = bq274xx_command_reg_write(bq274xx,
BQ274XX_EXTENDED_DATA_CONTROL, 0x00);
if (status < 0) {
LOG_ERR("Failed to enable block data memory");
return -EIO;
}
/* Access State subclass */
status = bq274xx_command_reg_write(bq274xx, BQ274XX_EXTENDED_DATA_CLASS,
0x52);
if (status < 0) {
LOG_ERR("Failed to update state subclass");
return -EIO;
}
/* Write the block offset */
status = bq274xx_command_reg_write(bq274xx, BQ274XX_EXTENDED_DATA_BLOCK,
0x00);
if (status < 0) {
LOG_ERR("Failed to update block offset");
return -EIO;
}
for (u8_t i = 0; i < 32; i++) {
block[i] = 0;
}
status = bq274xx_read_data_block(bq274xx, 0x00, block, 32);
if (status < 0) {
LOG_ERR("Unable to read block data");
return -EIO;
}
tmp_checksum = 0;
for (u8_t i = 0; i < 32; i++) {
tmp_checksum += block[i];
}
tmp_checksum = 255 - tmp_checksum;
/* Read the block checksum */
status = i2c_reg_read_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_CHECKSUM, &checksum_old);
if (status < 0) {
LOG_ERR("Unable to read block checksum");
return -EIO;
}
designcap_msb = config->design_capacity >> 8;
designcap_lsb = config->design_capacity & 0x00FF;
designenergy_msb = designenergy_mwh >> 8;
designenergy_lsb = designenergy_mwh & 0x00FF;
terminatevolt_msb = config->terminate_voltage >> 8;
terminatevolt_lsb = config->terminate_voltage & 0x00FF;
taperrate_msb = taperrate >> 8;
taperrate_lsb = taperrate & 0x00FF;
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_HIGH,
designcap_msb);
if (status < 0) {
LOG_ERR("Failed to write designCAP MSB");
return -EIO;
}
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_LOW,
designcap_lsb);
if (status < 0) {
LOG_ERR("Failed to erite designCAP LSB");
return -EIO;
}
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_HIGH,
designenergy_msb);
if (status < 0) {
LOG_ERR("Failed to write designEnergy MSB");
return -EIO;
}
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_LOW,
designenergy_lsb);
if (status < 0) {
LOG_ERR("Failed to erite designEnergy LSB");
return -EIO;
}
status = i2c_reg_write_byte(
bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_HIGH,
terminatevolt_msb);
if (status < 0) {
LOG_ERR("Failed to write terminateVolt MSB");
return -EIO;
}
status = i2c_reg_write_byte(
bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_LOW,
terminatevolt_lsb);
if (status < 0) {
LOG_ERR("Failed to write terminateVolt LSB");
return -EIO;
}
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_HIGH,
taperrate_msb);
if (status < 0) {
LOG_ERR("Failed to write taperRate MSB");
return -EIO;
}
status = i2c_reg_write_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_LOW,
taperrate_lsb);
if (status < 0) {
LOG_ERR("Failed to erite taperRate LSB");
return -EIO;
}
for (u8_t i = 0; i < 32; i++) {
block[i] = 0;
}
status = bq274xx_read_data_block(bq274xx, 0x00, block, 32);
if (status < 0) {
LOG_ERR("Unable to read block data");
return -EIO;
}
checksum_new = 0;
for (u8_t i = 0; i < 32; i++) {
checksum_new += block[i];
}
checksum_new = 255 - checksum_new;
status = bq274xx_command_reg_write(bq274xx, BQ274XX_EXTENDED_CHECKSUM,
checksum_new);
if (status < 0) {
LOG_ERR("Failed to update new checksum");
return -EIO;
}
tmp_checksum = 0;
status = i2c_reg_read_byte(bq274xx->i2c, DT_INST_REG_ADDR(0),
BQ274XX_EXTENDED_CHECKSUM, &tmp_checksum);
if (status < 0) {
LOG_ERR("Failed to read checksum");
return -EIO;
}
status = bq274xx_control_reg_write(bq274xx, BQ274XX_CONTROL_BAT_INSERT);
if (status < 0) {
LOG_ERR("Unable to configure BAT Detect");
return -EIO;
}
status = bq274xx_control_reg_write(bq274xx, BQ274XX_CONTROL_SOFT_RESET);
if (status < 0) {
LOG_ERR("Failed to soft reset the gauge");
return -EIO;
}
flags = 0;
/* Poll Flags */
do {
status = bq274xx_command_reg_read(
bq274xx, BQ274XX_COMMAND_FLAGS, &flags);
if (status < 0) {
LOG_ERR("Unable to read flags");
return -EIO;
}
if (!(flags & 0x0010)) {
k_msleep(BQ274XX_SUBCLASS_DELAY * 10);
}
} while ((flags & 0x0010));
/* Seal the gauge */
status = bq274xx_control_reg_write(bq274xx, BQ274XX_CONTROL_SEALED);
if (status < 0) {
LOG_ERR("Failed to seal the gauge");
return -EIO;
}
return 0;
}
static const struct sensor_driver_api bq274xx_battery_driver_api = {
.sample_fetch = bq274xx_sample_fetch,
.channel_get = bq274xx_channel_get,
};
#define BQ274XX_INIT(index) \
static struct bq274xx_data bq274xx_driver_##index; \
\
static const struct bq274xx_config bq274xx_config_##index = { \
.bus_name = DT_INST_BUS_LABEL(index), \
.design_voltage = DT_INST_PROP(index, design_voltage), \
.design_capacity = DT_INST_PROP(index, design_capacity), \
.taper_current = DT_INST_PROP(index, taper_current), \
.terminate_voltage = DT_INST_PROP(index, terminate_voltage), \
}; \
\
DEVICE_AND_API_INIT(bq274xx_##index, DT_INST_LABEL(index), \
&bq274xx_gauge_init, &bq274xx_driver_##index, \
&bq274xx_config_##index, POST_KERNEL, \
CONFIG_SENSOR_INIT_PRIORITY, \
&bq274xx_battery_driver_api) \
DT_INST_FOREACH(BQ274XX_INIT)

View file

@ -0,0 +1,105 @@
/*
* Copyright(c) 2020 Linumiz
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_BATTERY_BQ274XX_H_
#define ZEPHYR_DRIVERS_SENSOR_BATTERY_BQ274XX_H_
#include <logging/log.h>
LOG_MODULE_REGISTER(bq274xx, CONFIG_SENSOR_LOG_LEVEL);
/*** General Constant ***/
#define BQ274XX_UNSEAL_KEY 0x8000 /* Secret code to unseal the BQ27441-G1A */
#define BQ274XX_DEVICE_ID 0x0421 /* Default device ID */
/*** Standard Commands ***/
#define BQ274XX_COMMAND_CONTROL_LOW 0x00 /* Control() low register */
#define BQ274XX_COMMAND_CONTROL_HIGH 0x01 /* Control() high register */
#define BQ274XX_COMMAND_TEMP 0x02 /* Temperature() */
#define BQ274XX_COMMAND_VOLTAGE 0x04 /* Voltage() */
#define BQ274XX_COMMAND_FLAGS 0x06 /* Flags() */
#define BQ274XX_COMMAND_NOM_CAPACITY 0x08 /* NominalAvailableCapacity() */
#define BQ274XX_COMMAND_AVAIL_CAPACITY 0x0A /* FullAvailableCapacity() */
#define BQ274XX_COMMAND_REM_CAPACITY 0x0C /* RemainingCapacity() */
#define BQ274XX_COMMAND_FULL_CAPACITY 0x0E /* FullChargeCapacity() */
#define BQ274XX_COMMAND_AVG_CURRENT 0x10 /* AverageCurrent() */
#define BQ274XX_COMMAND_STDBY_CURRENT 0x12 /* StandbyCurrent() */
#define BQ274XX_COMMAND_MAX_CURRENT 0x14 /* MaxLoadCurrent() */
#define BQ274XX_COMMAND_AVG_POWER 0x18 /* AveragePower() */
#define BQ274XX_COMMAND_SOC 0x1C /* StateOfCharge() */
#define BQ274XX_COMMAND_INT_TEMP 0x1E /* InternalTemperature() */
#define BQ274XX_COMMAND_SOH 0x20 /* StateOfHealth() */
#define BQ274XX_COMMAND_REM_CAP_UNFL 0x28 /* RemainingCapacityUnfiltered() */
#define BQ274XX_COMMAND_REM_CAP_FIL 0x2A /* RemainingCapacityFiltered() */
#define BQ274XX_COMMAND_FULL_CAP_UNFL 0x2C /* FullChargeCapacityUnfiltered() */
#define BQ274XX_COMMAND_FULL_CAP_FIL 0x2E /* FullChargeCapacityFiltered() */
#define BQ274XX_COMMAND_SOC_UNFL 0x30 /* StateOfChargeUnfiltered() */
/*** Control Sub-Commands ***/
#define BQ274XX_CONTROL_STATUS 0x0000
#define BQ274XX_CONTROL_DEVICE_TYPE 0x0001
#define BQ274XX_CONTROL_FW_VERSION 0x0002
#define BQ274XX_CONTROL_DM_CODE 0x0004
#define BQ274XX_CONTROL_PREV_MACWRITE 0x0007
#define BQ274XX_CONTROL_CHEM_ID 0x0008
#define BQ274XX_CONTROL_BAT_INSERT 0x000C
#define BQ274XX_CONTROL_BAT_REMOVE 0x000D
#define BQ274XX_CONTROL_SET_HIBERNATE 0x0011
#define BQ274XX_CONTROL_CLEAR_HIBERNATE 0x0012
#define BQ274XX_CONTROL_SET_CFGUPDATE 0x0013
#define BQ274XX_CONTROL_SHUTDOWN_ENABLE 0x001B
#define BQ274XX_CONTROL_SHUTDOWN 0x001C
#define BQ274XX_CONTROL_SEALED 0x0020
#define BQ274XX_CONTROL_PULSE_SOC_INT 0x0023
#define BQ274XX_CONTROL_RESET 0x0041
#define BQ274XX_CONTROL_SOFT_RESET 0x0042
#define BQ274XX_CONTROL_EXIT_CFGUPDATE 0x0043
#define BQ274XX_CONTROL_EXIT_RESIM 0x0044
/*** Extended Data Commands ***/
#define BQ274XX_EXTENDED_OPCONFIG 0x3A /* OpConfig() */
#define BQ274XX_EXTENDED_CAPACITY 0x3C /* DesignCapacity() */
#define BQ274XX_EXTENDED_DATA_CLASS 0x3E /* DataClass() */
#define BQ274XX_EXTENDED_DATA_BLOCK 0x3F /* DataBlock() */
#define BQ274XX_EXTENDED_BLOCKDATA_START 0x40 /* BlockData_start() */
#define BQ274XX_EXTENDED_BLOCKDATA_END 0x5F /* BlockData_end() */
#define BQ274XX_EXTENDED_CHECKSUM 0x60 /* BlockDataCheckSum() */
#define BQ274XX_EXTENDED_DATA_CONTROL 0x61 /* BlockDataControl() */
#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_HIGH 0x4A /* BlockData */
#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_CAP_LOW 0x4B
#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_HIGH 0x4C
#define BQ274XX_EXTENDED_BLOCKDATA_DESIGN_ENR_LOW 0x4D
#define BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_HIGH 0x50
#define BQ274XX_EXTENDED_BLOCKDATA_TERMINATE_VOLT_LOW 0x51
#define BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_HIGH 0x5B
#define BQ274XX_EXTENDED_BLOCKDATA_TAPERRATE_LOW 0x5C
#define BQ274XX_DELAY 1000
struct bq274xx_data {
struct device *i2c;
u16_t voltage;
s16_t avg_current;
s16_t stdby_current;
s16_t max_load_current;
s16_t avg_power;
u16_t state_of_charge;
s16_t state_of_health;
u16_t internal_temperature;
u16_t full_charge_capacity;
u16_t remaining_charge_capacity;
u16_t nom_avail_capacity;
u16_t full_avail_capacity;
};
struct bq274xx_config {
char *bus_name;
u16_t design_voltage;
u16_t design_capacity;
u16_t taper_current;
u16_t terminate_voltage;
};
#endif

View file

@ -0,0 +1,36 @@
#
# Copyright (c) 2020 Linumiz
#
# SPDX-License-Identifier: Apache-2.0
#
description: Texas Instruments BQ274xx Fuel Gauge
compatible: "ti,bq274xx"
include: i2c-device.yaml
properties:
design-voltage:
type: int
required: false
description: Battery Design Volatge in (3300 - 4400)mV
default: 3700
design-capacity:
type: int
required: false
description: Battery Design Capacity in mAh
default: 1800
taper-current:
type: int
required: false
description: Battery Taper current in mAh
default: 45
terminate-voltage:
type: int
required: false
description: Battery Terminate Voltage in mV
default: 3000

View file

@ -137,6 +137,31 @@ enum sensor_channel {
/** Revolutions per minute, in RPM. */
SENSOR_CHAN_RPM,
/** Voltage, in volts **/
SENSOR_CHAN_GAUGE_VOLTAGE,
/** Average current, in amps **/
SENSOR_CHAN_GAUGE_AVG_CURRENT,
/** Standy current, in amps **/
SENSOR_CHAN_GAUGE_STDBY_CURRENT,
/** Max load current, in amps **/
SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT,
/** Gauge temperature **/
SENSOR_CHAN_GAUGE_TEMP,
/** State of charge measurement in % **/
SENSOR_CHAN_GAUGE_STATE_OF_CHARGE,
/** Full Charge Capacity in mAh **/
SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY,
/** Remaining Charge Capacity in mAh **/
SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY,
/** Nominal Available Capacity in mAh **/
SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY,
/** Full Available Capacity in mAh **/
SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY,
/** Average power in mW **/
SENSOR_CHAN_GAUGE_AVG_POWER,
/** State of health measurement in % **/
SENSOR_CHAN_GAUGE_STATE_OF_HEALTH,
/** All channels. */
SENSOR_CHAN_ALL,

View file

@ -508,3 +508,12 @@ test_i2c_tmp116: tmp116@46 {
reg = <0x46>;
};
test_i2c_bq274xx: bq27xx@47 {
compatible = "ti,bq274xx";
label = "BQ274XX";
reg = <0x47>;
design-voltage = <3700>;
design-capacity = <1800>;
taper-current = <45>;
terminate-voltage = <3000>;
};

View file

@ -20,6 +20,7 @@ CONFIG_BME280=y
CONFIG_BMG160=y
CONFIG_BMI160=y
CONFIG_BMM150=y
CONFIG_BQ274XX=y
CONFIG_CCS811=y
CONFIG_DHT=y
CONFIG_ENS210=y