--- /dev/null
+/****************************************************************************
+ * extdrv/bq769x0_bms.c
+ *
+ *
+ * Copyright 2020 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+
+#include "core/system.h"
+#include "lib/errno.h"
+#include "lib/string.h"
+#include "drivers/i2c.h"
+#include "extdrv/bq769x0_bms.h"
+
+
+/***************************************************************************** */
+/* Support for TMP101 temperature bmss from Texas Instrument */
+/***************************************************************************** */
+/* This driver is made for the TMP101 version of the chip, though there's few
+ * diferences between the TMP100 and TMP101 version.
+ * This driver does not handle the SMBus Alert command.
+ */
+
+
+enum bq769x0_internal_reg_numbers {
+ SYSTEM_STATUS = 0,
+ CELL_BALANCE_1,
+ CELL_BALANCE_2,
+ CELL_BALANCE_3,
+ SYS_CTRL_1,
+ SYS_CTRL_2,
+ PROTECT_1,
+ PROTECT_2,
+ PROTECT_3,
+ OVER_VOLTAGE_TRIP,
+ UNDER_VOLTAGE_TRIP,
+ CC_CFG, /* Coulomb Counter */
+ VC1_HIGH, /* 0x0C */
+ VC1_LOW,
+ /* VC2 to VC15 ... */
+ BAT_HIGH = 0x2A,
+ BAT_LOW,
+ TS1_HIGH,
+ TS1_LOW,
+ /* TS2 and TS3 */
+ CC_HIGH = 0x32,
+ CC_LOW,
+ ADC_GAIN_1 = 0x50,
+ ADC_OFFSET,
+ ADC_GAIN_2 = 0x59,
+ BQ769X0_LAST_REG,
+};
+
+
+/* Aditional defines, not exported to userspace */
+
+/* Sys Ctrl 1 */
+#define LOAD_PRESENT(x) ((x) & 0x80)
+#define ADC_ENABLE (0x01 << 4)
+#define TEMP_SEL_DIE (0 << 3)
+#define TEMP_SEL_TSX (1 << 3)
+#define SHUTDOWN_CMD_A (0x01)
+#define SHUTDOWN_CMD_B (0x02)
+
+/* Sys Ctrl 2 */
+#define DELAYS_OFF_FOR_TESTING (0x01 << 7)
+#define CC_ENABLE (0x01 << 6)
+#define CC_ONE_SHOT (0x01 << 5)
+#define DISCHARGE_ON (0x01 << 1)
+#define CHARGE_ON (0x01 << 0)
+
+/* CC Config */
+/* The documentation asks for CC_CFG to be set to 0x19 upon startup */
+#define CC_CFG_DEFAULT 0x19
+
+
+/* Check the bms presence, return 1 if bms was found.
+ * This is a basic check, it could be anything with the same address ...
+ */
+int bq769x0_probe_bms(struct bq769x0_bms_conf* conf)
+{
+ char cmd_buf = (conf->addr | I2C_READ_BIT);
+
+ /* Did we already probe the bms ? */
+ /* 1 is the only valid value, all other values indicate an error state */
+ if (conf->probe_ok != 1) {
+ conf->probe_ok = i2c_read(conf->bus_num, &cmd_buf, 1, NULL, NULL, 0);
+ msleep(10);
+ }
+ return conf->probe_ok;
+}
+
+
+/* Read registers from the BMS
+ * Return value(s):
+ * Upon successfull completion, returns 0 and the registers content is placed in the buffer.
+ * On error, returns a negative integer equivalent to errors from glibc.
+ */
+#define CMD_BUF_SIZE 3
+int bq769x0_bms_get_regs(struct bq769x0_bms_conf* conf,
+ uint8_t reg_start, uint8_t* values, uint8_t len)
+{
+ int ret = 0;
+ char cmd_buf[CMD_BUF_SIZE] = { conf->addr, 0, (conf->addr | I2C_READ_BIT), };
+ char ctrl_buf[CMD_BUF_SIZE] = { I2C_CONT, I2C_DO_REPEATED_START, I2C_CONT, };
+
+ if (bq769x0_probe_bms(conf) != 1) {
+ return -ENODEV;
+ }
+ if (values == NULL) {
+ return -EINVAL;
+ }
+ if ((reg_start + len - 1) > BQ769X0_LAST_REG) {
+ return -EINVAL;
+ }
+ cmd_buf[1] = reg_start;
+
+ ret = i2c_read(conf->bus_num, cmd_buf, CMD_BUF_SIZE, ctrl_buf, values, len);
+ if (ret != len) {
+ conf->probe_ok = 0;
+ return ret;
+ }
+ return 0;
+}
+
+#define REG_WR_CMD_SIZE 2
+#define MAX_WR_BUF_SIZE (REG_WR_CMD_SIZE + CC_CFG) /* Maybe someone wants to write all regs at once ? */
+int bq769x0_bms_set_regs(struct bq769x0_bms_conf* conf,
+ uint8_t reg_start, uint8_t* values, uint8_t len)
+{
+ int ret = 0;
+ char cmd_buf[MAX_WR_BUF_SIZE] = { conf->addr, };
+
+ if (bq769x0_probe_bms(conf) != 1) {
+ return -ENODEV;
+ }
+ if (values == NULL) {
+ return -EINVAL;
+ }
+ if ((reg_start + len - 1) > CC_CFG) { /* CC_CFG is the last RW reg */
+ return -EINVAL;
+ }
+ cmd_buf[1] = reg_start;
+
+ memcpy((cmd_buf + REG_WR_CMD_SIZE), values, len);
+ ret = i2c_write(conf->bus_num, cmd_buf, (REG_WR_CMD_SIZE + len), NULL);
+ if (ret != (REG_WR_CMD_SIZE + len)) {
+ conf->probe_ok = 0;
+ return ret;
+ }
+ return 0;
+}
+
+int bq769x0_bms_read_adc_gain(struct bq769x0_bms_conf* conf)
+{
+ int ret = 0;
+ uint8_t gain = 0, tmp = 0;
+
+ /* Get GAIN two MSB bits */
+ ret = bq769x0_bms_get_regs(conf, ADC_GAIN_1, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 6;
+ return -1;
+ }
+ msleep(2);
+ gain = (tmp & 0x0C) << 1;
+
+ /* Get GAIN three LSB bits */
+ ret = bq769x0_bms_get_regs(conf, ADC_GAIN_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 7;
+ return -1;
+ }
+ msleep(2);
+ gain |= ((tmp >> 5) & 0x07);
+
+ /* Store gain and gain in µV */
+ conf->adc_gain = gain;
+ conf->adc_gain_uV = 365 + gain;
+
+ /* Get ADC offset */
+ ret = bq769x0_bms_get_regs(conf, ADC_OFFSET, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 8;
+ return -1;
+ }
+ conf->adc_offset = (int8_t)tmp;
+
+ return 0;
+}
+
+/* Check load presence.
+ * This is valid only when the battery charging is disabled.
+ * Return 1 if load is present, or 0 if load is not present and charge is disabled.
+ * Returns -1 on error, or -2 if charge is enabled
+ */
+int bq769x0_bms_load_present(struct bq769x0_bms_conf* conf)
+{
+ int ret = 0;
+ uint8_t sys_ctrl[2];
+
+ ret = bq769x0_bms_get_regs(conf, SYS_CTRL_1, sys_ctrl, 2);
+ if (ret != 0) {
+ conf->probe_ok = 9;
+ return -1;
+ }
+ if (sys_ctrl[1] & CHARGE_ON) {
+ return -2;
+ }
+ if (LOAD_PRESENT(sys_ctrl[0])) {
+ return 1;
+ }
+ return 0; /* */
+}
+
+/* BMS Shut-Down.
+ * Disable both charge and discharge and turn off BMS by sending shutdown sequence.
+ * Only way out of sequence is power cycle (battery removal and re-insertion or button).
+ */
+int bq769x0_bms_shutdown(struct bq769x0_bms_conf* conf)
+{
+ int ret = 0;
+ uint8_t tmp = 0;
+
+ /* Turn off both charge and discharge */
+ tmp = 0;
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 10;
+ return ret;
+ }
+ msleep(2);
+
+ /* Write shutdown sequence part 1 */
+ tmp = SHUTDOWN_CMD_A;
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_1, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 11;
+ return ret;
+ }
+ msleep(2);
+ /* Write shutdown sequence part 2 */
+ tmp = SHUTDOWN_CMD_B;
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_1, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 12;
+ return ret;
+ }
+ return 0; /* Shutdown OK ... should we reach this point ??? */
+}
+
+/* Start a conversion when the bms is not in Continuous CC mode. */
+int bq769x0_bms_start_conversion(struct bq769x0_bms_conf* conf)
+{
+ int ret = 0;
+ uint8_t tmp = 0;
+
+ /* Read actual config */
+ ret = bq769x0_bms_get_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 13;
+ return ret;
+ }
+ msleep(2);
+ /* Set CC one-shot conversion start bit and write back */
+ tmp &= ~(CC_ENABLE);
+ tmp |= CC_ONE_SHOT;
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 14;
+ return ret;
+ }
+
+ return 0; /* Conversion start success */
+}
+
+/* Place the bms in continuous CC convertion mode */
+int bq769x0_bms_set_continuous_conversion(struct bq769x0_bms_conf* conf)
+{
+ int ret = 0;
+ uint8_t tmp = 0;
+
+ /* Read actual config */
+ ret = bq769x0_bms_get_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 15;
+ return ret;
+ }
+ msleep(2);
+ /* Set CC continuous conversion bit and write back */
+ tmp |= CC_ENABLE;
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 16;
+ return ret;
+ }
+ return 0; /* Configuration change success */
+}
+
+/* Enable/Disable charge and/or discharge
+ * Note that it is not possible to keep the old charge/discharge state and modify
+ * only the other one with this function.
+ */
+int bq769x0_bms_change_state(struct bq769x0_bms_conf* conf, uint8_t charge, uint8_t discharge)
+{
+ int ret = 0;
+ uint8_t tmp = 0;
+
+ /* Read actual config */
+ ret = bq769x0_bms_get_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 17;
+ return ret;
+ }
+ msleep(2);
+ /* Update required bits */
+ tmp &= ~(CHARGE_ON | DISCHARGE_ON);
+ if (charge) {
+ tmp |= CHARGE_ON;
+ }
+ if (discharge) {
+ tmp |= DISCHARGE_ON;
+ }
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 18;
+ return ret;
+ }
+ return 0; /* Configuration change success */
+}
+
+
+/* Set the uvlo (under voltage lockout), ovp (overvoltage protection),
+ * ocd (over curent in discharge) and scd (short circuit in discharge) values
+ * Note that timmings will be set to their minimum values.
+ * - scd is between 0 and 7, 0 is 22mV and 7 is 100mV with approx 11mV steps.
+ * - ocd is between 0 and 15, 0 is 8mV and 15 is 50mV with approx 3mV steps.
+ * - uvlo and ovp are the middle 8 bits of the 13 bits of ADC values with the corresponding mapping :
+ * 0b(10 <ovp> 1000) which is between 8200 and 12280
+ * 0b(01 <uvlo> 0000) which is between 4096 and 8176
+ * The uvlo and ovp values depend on ADC gain and ADC offset which are stored in
+ * conf->adc_gain_uV and conf->adc_offset upon configuration.
+ */
+int bq769x0_bms_set_ranges(struct bq769x0_bms_conf* conf,
+ uint8_t uvlo, uint8_t ovp, uint8_t ocd, uint8_t scd)
+{
+ int ret = 0;
+ uint8_t protect[5];
+
+ if ((scd > 0x07) || (ocd > 0x0F)) {
+ return -EINVAL;
+ }
+ protect[0] = scd & 0x07;
+ protect[1] = ocd & 0x0F;
+ protect[2] = 0;
+ protect[3] = ovp;
+ protect[4] = uvlo;
+ ret = bq769x0_bms_set_regs(conf, PROTECT_1, protect, 5);
+ if (ret != 0) {
+ conf->probe_ok = 19;
+ return ret;
+ }
+ return 0;
+}
+
+
+/* Read ADC values.
+ * type is one of :
+ * - ALL : Read all values (up to nb_val)
+ * - ALL_CELLS : Read all cells values. nb_val must equal conf->nb_cells (max 15)
+ * (number of available cells depends on package)
+ * - BATTERY : Read only the battery voltage (nb_val must be 1)
+ * - THERMISTORS : Read only the Thermistor values. nb_val between 1 and 3 and
+ * must equal conf->nb_thermistors
+ * (number of available thermistors depends on package)
+ * - CELL(x) : Read only cell "x" voltage
+ * - CC_COUNT : Read the Coulomb counter value (nb_val must be 1)
+ */
+int bq769x0_bms_read_adc(struct bq769x0_bms_conf* conf, uint16_t* data, int type, int nb_val)
+{
+ int ret = 0, i = 0;
+ uint8_t offset = 0;
+
+ if ((nb_val == 0) || (data == NULL)) {
+ return -EINVAL;
+ }
+
+ switch (type) {
+ case BATTERY:
+ offset = BAT_HIGH;
+ if (nb_val != 1) {
+ return -EINVAL;
+ }
+ break;
+ case ALL_CELLS:
+ if (nb_val != conf->nb_cells) {
+ return -EINVAL;
+ }
+ /* Breakthrough */
+ case ALL:
+ offset = VC1_HIGH;
+ break;
+ case THERMISTORS:
+ offset = TS1_HIGH;
+ if (nb_val > conf->nb_thermistors) {
+ return -EINVAL;
+ }
+ break;
+ case CC_COUNT:
+ offset = CC_HIGH;
+ if (nb_val != 1) {
+ return -EINVAL;
+ }
+ break;
+ default:
+ offset = VC1_HIGH + (2 * (type - 10));
+ if (nb_val != 1) {
+ return -EINVAL;
+ }
+ break;
+ }
+ ret = bq769x0_bms_get_regs(conf, offset, (uint8_t*)data, (nb_val * 2));
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Change endianness */
+ for (i = 0; i < nb_val; i++) {
+ data[i] = (uint16_t)byte_swap_16(data[i]);
+ }
+ return 0;
+}
+
+int bq769x0_bms_get_and_erase_status(struct bq769x0_bms_conf* conf, uint8_t* status)
+{
+ int ret = 0;
+
+ if (status == NULL) {
+ return -EINVAL;
+ }
+ /* Read status */
+ ret = bq769x0_bms_get_regs(conf, SYSTEM_STATUS, status, 1);
+ if (ret != 0) {
+ return ret;
+ }
+ msleep(2);
+ /* Write back to clear all bits */
+ ret = bq769x0_bms_set_regs(conf, SYSTEM_STATUS, status, 1);
+ if (ret != 0) {
+ return ret;
+ }
+ return 0;
+}
+
+
+/* BMS config
+ * Performs default configuration of the bms.
+ * Return value :
+ * Upon successfull completion, returns 0. On error, returns a negative integer
+ * equivalent to errors from glibc.
+ */
+#define CONF_BUF_SIZE 4
+int bq769x0_bms_config(struct bq769x0_bms_conf* conf, uint8_t* old_status)
+{
+ int ret = 0;
+ uint8_t tmp = 0;
+
+ /* Probe BMS and get old status */
+ ret = bq769x0_bms_get_and_erase_status(conf, &tmp);
+ if (ret != 0) {
+ conf->probe_ok = 2;
+ return ret;
+ }
+ if (old_status != NULL) {
+ *old_status = tmp;
+ }
+ msleep(2);
+
+ /* Programm CC_CFG as requested in datasheet */
+ tmp = CC_CFG_DEFAULT;
+ ret = bq769x0_bms_set_regs(conf, CC_CFG, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 3;
+ return ret;
+ }
+ msleep(2);
+
+ /* Program first control register :
+ * - enable ADC
+ * - set temp readings to externel thermistor instead of Die temperature
+ */
+ tmp = ADC_ENABLE | TEMP_SEL_TSX;
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_1, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 4;
+ return ret;
+ }
+
+ msleep(2);
+ /* Program second control register :
+ * - Enable coulomb counter
+ * - Enable discharge
+ * - Enable charge
+ */
+ tmp = CC_ENABLE | DISCHARGE_ON | CHARGE_ON;
+ ret = bq769x0_bms_set_regs(conf, SYS_CTRL_2, &tmp, 1);
+ if (ret != 0) {
+ conf->probe_ok = 5;
+ return ret;
+ }
+ msleep(2);
+
+ /* Re-read (and discard) status so that any new status read reflects a fresh status */
+ ret = bq769x0_bms_get_and_erase_status(conf, &tmp);
+ if (ret != 0) {
+ return ret;
+ }
+ msleep(2);
+
+ /* Get the ADC gain and offset once upon startup */
+ ret = bq769x0_bms_read_adc_gain(conf);
+ if (ret != 0) {
+ return ret;
+ }
+
+ return 0; /* Config success */
+}
+
--- /dev/null
+/****************************************************************************
+ * extdrv/bq769x0_bms.h
+ *
+ *
+ * Copyright 2020 Nathael Pajani <nathael.pajani@ed3l.fr>
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *************************************************************************** */
+
+#ifndef EXTDRV_BQ769X0_H
+#define EXTDRV_BQ769X0_H
+
+#include "lib/stdint.h"
+
+
+/***************************************************************************** */
+/* Support for BQ769X0 Battery Protection from Texas Instrument */
+/***************************************************************************** */
+/* This driver is made for the BQ76920 version of the chip, though there's few
+ * diferences between the BQ76920, BQ76930 and BQ76950 versions.
+ * This driver does not handle the Alert command.
+ */
+
+/* BQ769X0 instance data.
+ * Use one of this for each BMS you want to access.
+ * - addr is the BMS address on most significant bits.
+ */
+struct bq769x0_bms_conf {
+ uint8_t addr;
+ uint8_t bus_num;
+ uint8_t probe_ok;
+ uint8_t crc_check; /* 0 : No CRC check */
+ uint8_t adc_gain;
+ int8_t adc_offset;
+ uint16_t adc_gain_uV; /* ADC gain converted to µV */
+ uint8_t nb_cells;
+ uint8_t nb_thermistors;
+};
+
+/* Check the bms presence, return 1 if found
+ * This is a basic check, it could be anything with the same address ...
+ */
+int bq769x0_probe_bms(struct bq769x0_bms_conf* conf);
+
+
+int bq769x0_bms_get_regs(struct bq769x0_bms_conf* conf,
+ uint8_t reg_start, uint8_t* values, uint8_t len);
+
+int bq769x0_bms_set_regs(struct bq769x0_bms_conf* conf,
+ uint8_t reg_start, uint8_t* values, uint8_t len);
+
+
+/* Read the BMS status Word and erase it's content
+ * conf: the bms configuration structure.
+ * status: pointer to an uint8_t value to store the old status value. May NOT be NULL.
+ * Return value:
+ * Upon successfull completion, returns 0. On error, returns a negative integer
+ * equivalent to errors from glibc.
+ */
+int bq769x0_bms_get_and_erase_status(struct bq769x0_bms_conf* conf, uint8_t* status);
+
+/* SYS Status */
+#define CC_READY(x) ((x) & 0x80) /* New Coulomb Counter reading available */
+#define DEVICE_NOT_READY(x) ((x) & 0x20) /* Set means internal fault */
+#define EXT_OVERRIDE_ALERT(x) ((x) & 0x10)
+#define UNDER_VOLTAGE(x) ((x) & 0x08) /* UV */
+#define OVER_VOLTAGE(x) ((x) & 0x04) /* OV */
+#define SHORT_CIRCUIT_DISCHARGE(x) ((x) & 0x02) /* SCD */
+#define OVER_CURRENT_DISCHARGE(x) ((x) & 0x01) /* OCD */
+
+
+
+/* Check load presence.
+ * This is valid only when the battery charging is disabled.
+ * Return 1 if load is present, or 0 if load is not present and charge is disabled.
+ * Returns -1 on error, or -2 if charge is enabled
+ */
+int bq769x0_bms_load_present(struct bq769x0_bms_conf* conf);
+
+/* BMS Shut-Down.
+ * Disable both charge and discharge and turn off BMS by sending shutdown sequence.
+ * Only way out of sequence is power cycle (battery removal and re-insertion or button).
+ */
+int bq769x0_bms_shutdown(struct bq769x0_bms_conf* conf);
+
+/* Start a conversion when the bms is not in Continuous CC mode. */
+int bq769x0_bms_start_conversion(struct bq769x0_bms_conf* conf);
+
+/* Place the bms in continuous CC convertion mode */
+int bq769x0_bms_set_continuous_conversion(struct bq769x0_bms_conf* conf);
+
+/* Enable/Disable charge and/or discharge
+ * Note that it is not possible to keep the old charge/discharge state and modify
+ * only the other one with this function.
+ */
+int bq769x0_bms_change_state(struct bq769x0_bms_conf* conf, uint8_t charge, uint8_t discharge);
+
+/* Set the uvlo (under voltage lockout), ovp (overvoltage protection),
+ * ocd (over curent in discharge) and scd (short circuit in discharge) values
+ * Note that timmings will be set to their minimum values.
+ * - scd is between 0 and 7, 0 is 22mV and 7 is 100mV with approx 11mV steps.
+ * - ocd is between 0 and 15, 0 is 8mV and 15 is 50mV with approx 3mV steps.
+ * - uvlo and ovp are the middle 8 bits of the 13 bits of ADC values with the corresponding mapping :
+ * 0b(10 <ovp> 1000) which is between 8200 and 12280
+ * 0b(01 <uvlo> 0000) which is between 4096 and 8176
+ * The uvlo and ovp values depend on ADC gain and ADC offset which are stored in
+ * conf->adc_gain_uV and conf->adc_offset upon configuration.
+ */
+int bq769x0_bms_set_ranges(struct bq769x0_bms_conf* conf,
+ uint8_t uvlo, uint8_t ovp, uint8_t ocd, uint8_t scd);
+
+
+
+enum bq769x0_bms_adc_values {
+ ALL = 0,
+ BATTERY,
+ ALL_CELLS,
+ THERMISTORS,
+ CC_COUNT,
+};
+#define CELL(x) ((x) + 10)
+
+/* Read ADC values.
+ * type is one of :
+ * - ALL : Read all values (up to nb_val)
+ * - ALL_CELLS : Read all cells values. nb_val must equal conf->nb_cells (max 15)
+ * (number of available cells depends on package)
+ * - BATTERY : Read only the battery voltage (nb_val must be 1)
+ * - THERMISTORS : Read only the Thermistor values. nb_val between 1 and 3 and
+ * must equal conf->nb_thermistors
+ * (number of available thermistors depends on package)
+ * - CELL(x) : Read only cell "x" voltage
+ * - CC_COUNT : Read the Coulomb counter value (nb_val must be 1)
+ */
+int bq769x0_bms_read_adc(struct bq769x0_bms_conf* conf, uint16_t* data, int type, int nb_val);
+
+
+/* BMS config
+ * Performs default configuration of the BMS.
+ * conf: the bms configuration structure.
+ * old_status: pointer to an uint8_t value to store the old status value. May be NULL.
+ * Return value:
+ * Upon successfull completion, returns 0. On error, returns a negative integer
+ * equivalent to errors from glibc.
+ */
+int bq769x0_bms_config(struct bq769x0_bms_conf* conf, uint8_t* old_status);
+
+#endif /* EXTDRV_BQ769X0_H */
+