diff options
-rw-r--r-- | board/careena/battery.c | 12 | ||||
-rw-r--r-- | board/careena/board.h | 3 | ||||
-rw-r--r-- | common/battery_fuel_gauge.c | 19 | ||||
-rw-r--r-- | common/charge_state_v2.c | 9 | ||||
-rw-r--r-- | driver/battery/bq4050.c | 39 | ||||
-rw-r--r-- | driver/battery/smart.c | 5 | ||||
-rw-r--r-- | driver/build.mk | 1 | ||||
-rw-r--r-- | include/battery.h | 7 | ||||
-rw-r--r-- | include/battery_fuel_gauge.h | 19 | ||||
-rw-r--r-- | include/config.h | 51 |
10 files changed, 159 insertions, 6 deletions
diff --git a/board/careena/battery.c b/board/careena/battery.c index fecd14b582..aefbcdfe97 100644 --- a/board/careena/battery.c +++ b/board/careena/battery.c @@ -45,7 +45,8 @@ const struct board_batt_params board_battery_info[] = { .reg_addr = 0x0, .reg_mask = 0x6000, .disconnect_val = 0x6000, - } + }, + .imbalance_mv = &battery_bq4050_imbalance_mv, }, .batt_info = { .voltage_max = 8800, /* mV */ @@ -74,7 +75,8 @@ const struct board_batt_params board_battery_info[] = { .reg_addr = 0x0, .reg_mask = 0x6000, .disconnect_val = 0x6000, - } + }, + .imbalance_mv = &battery_bq4050_imbalance_mv, }, .batt_info = { .voltage_max = 8800, /* mV */ @@ -103,7 +105,8 @@ const struct board_batt_params board_battery_info[] = { .reg_addr = 0x0, .reg_mask = 0x6000, .disconnect_val = 0x6000, - } + }, + .imbalance_mv = &battery_bq4050_imbalance_mv, }, .batt_info = { .voltage_max = 8800, /* mV */ @@ -132,7 +135,8 @@ const struct board_batt_params board_battery_info[] = { .reg_addr = 0x0, .reg_mask = 0x6000, .disconnect_val = 0x6000, - } + }, + .imbalance_mv = &battery_default_imbalance_mv, }, .batt_info = { .voltage_max = 8800, /* mV */ diff --git a/board/careena/board.h b/board/careena/board.h index e86f97c07e..e7710102d9 100644 --- a/board/careena/board.h +++ b/board/careena/board.h @@ -24,6 +24,9 @@ #define CONFIG_CMD_LEDTEST #define CONFIG_KEYBOARD_FACTORY_TEST +#define CONFIG_BATTERY_MEASURE_IMBALANCE +#define CONFIG_BATTERY_BQ4050 + #ifndef __ASSEMBLER__ enum pwm_channel { diff --git a/common/battery_fuel_gauge.c b/common/battery_fuel_gauge.c index 204b562401..476ca52570 100644 --- a/common/battery_fuel_gauge.c +++ b/common/battery_fuel_gauge.c @@ -162,3 +162,22 @@ enum battery_disconnect_state battery_get_disconnect_state(void) return BATTERY_NOT_DISCONNECTED; } + +#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE +int battery_imbalance_mv(void) +{ + int type = get_battery_type(); + + /* + * If battery type is unknown, we cannot safely access non-standard + * registers. + */ + return (type == BATTERY_TYPE_COUNT) ? 0 : + board_battery_info[type].fuel_gauge.imbalance_mv(); +} + +int battery_default_imbalance_mv(void) +{ + return 0; +} +#endif /* CONFIG_BATTERY_MEASURE_IMBALANCE */ diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index d97157e38b..5cca92f181 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -1973,14 +1973,19 @@ int charge_prevent_power_on(int power_button_pressed) automatic_power_on = 0; /* * Require a minimum battery level to power on and ensure that the - * battery can prvoide power to the system. + * battery can provide power to the system. */ if (current_batt_params->is_present != BP_YES || +#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE + (current_batt_params->flags & BATT_FLAG_IMBALANCED_CELL && + current_batt_params->state_of_charge < + CONFIG_CHARGER_MIN_BAT_PCT_IMBALANCED_POWER_ON) || +#endif #ifdef CONFIG_BATTERY_REVIVE_DISCONNECT battery_get_disconnect_state() != BATTERY_NOT_DISCONNECTED || #endif current_batt_params->state_of_charge < - CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) + CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON) prevent_power_on = 1; #if defined(CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON) && \ diff --git a/driver/battery/bq4050.c b/driver/battery/bq4050.c new file mode 100644 index 0000000000..6f2890ff2d --- /dev/null +++ b/driver/battery/bq4050.c @@ -0,0 +1,39 @@ +/* Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Smart battery driver for TI BQ4050 family, including BQ40Z50 (and -R1, -R2) + * and BQ40Z552. + */ + +#include "battery_smart.h" +#include "util.h" + +#include <stdint.h> + +int battery_bq4050_imbalance_mv(void) +{ + /* + * The BQ4050 family can manage up to four cells. In testing it always + * returns a voltage for each cell, regardless of the number of cells + * actually installed in the pack. Unpopulated cells read exactly zero. + */ + static const uint8_t cell_voltage_address[4] = { + 0x3c, 0x3d, 0x3e, 0x3f + }; + int i, res, cell_voltage; + int n_cells = 0; + int max_voltage = 0; + int min_voltage = 0xffff; + + for (i = 0; i != ARRAY_SIZE(cell_voltage_address); ++i) { + res = sb_read(cell_voltage_address[i], &cell_voltage); + if (res == EC_SUCCESS && cell_voltage != 0) { + n_cells++; + max_voltage = MAX(max_voltage, cell_voltage); + min_voltage = MIN(min_voltage, cell_voltage); + } + } + return (n_cells == 0) ? 0 : max_voltage - min_voltage; +} + diff --git a/driver/battery/smart.c b/driver/battery/smart.c index 743ebc1ee1..0ae35a5fba 100644 --- a/driver/battery/smart.c +++ b/driver/battery/smart.c @@ -351,6 +351,11 @@ void battery_get_params(struct batt_params *batt) if ((batt_new.flags & BATT_FLAG_BAD_ANY) != BATT_FLAG_BAD_ANY) batt_new.flags |= BATT_FLAG_RESPONSIVE; +#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE + if (battery_imbalance_mv() > CONFIG_BATTERY_MAX_IMBALANCE_MV) + batt_new.flags |= BATT_FLAG_IMBALANCED_CELL; +#endif + #if defined(CONFIG_BATTERY_PRESENT_CUSTOM) || \ defined(CONFIG_BATTERY_PRESENT_GPIO) /* Hardware can tell us for certain */ diff --git a/driver/build.mk b/driver/build.mk index 6746c1642f..44673c07bf 100644 --- a/driver/build.mk +++ b/driver/build.mk @@ -40,6 +40,7 @@ driver-$(CONFIG_BATTERY_BQ27541)+=battery/bq27541.o driver-$(CONFIG_BATTERY_BQ27621)+=battery/bq27621_g1.o driver-$(CONFIG_BATTERY_MAX17055)+=battery/max17055.o driver-$(CONFIG_BATTERY_SMART)+=battery/smart.o +driver-$(CONFIG_BATTERY_BQ4050)+=battery/bq4050.o # Battery charger ICs driver-$(CONFIG_CHARGER_BD9995X)+=charger/bd9995x.o diff --git a/include/battery.h b/include/battery.h index a97745b794..2ba56e1c9d 100644 --- a/include/battery.h +++ b/include/battery.h @@ -117,6 +117,7 @@ int battery_get_avg_voltage(void); /* in mV */ #define BATT_FLAG_BAD_REMAINING_CAPACITY 0x00000100 #define BATT_FLAG_BAD_FULL_CAPACITY 0x00000200 #define BATT_FLAG_BAD_STATUS 0x00000400 +#define BATT_FLAG_IMBALANCED_CELL 0x00000800 /* All of the above BATT_FLAG_BAD_* bits */ #define BATT_FLAG_BAD_ANY 0x000007fc @@ -328,6 +329,12 @@ int battery_device_chemistry(char *dest, int size); int battery_manufacturer_date(int *year, int *month, int *day); /** + * Report the absolute difference between the highest and lowest cell voltage in + * the battery pack, in millivolts. On error or unimplemented, returns '0'. + */ +int battery_imbalance_mv(void); + +/** * Call board-specific cut-off function. * * @return EC_RES_INVALID_COMMAND if the battery doesn't support. diff --git a/include/battery_fuel_gauge.h b/include/battery_fuel_gauge.h index 8de72d7d4e..9c3b0b12da 100644 --- a/include/battery_fuel_gauge.h +++ b/include/battery_fuel_gauge.h @@ -31,6 +31,11 @@ struct fuel_gauge_info { const uint8_t override_nil; const struct ship_mode_info ship_mode; const struct fet_info fet; + +#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE + /* See battery_*_imbalance_mv() for functions which are suitable. */ + int (*imbalance_mv)(void); +#endif }; struct board_batt_params { @@ -42,4 +47,18 @@ struct board_batt_params { extern const struct board_batt_params board_battery_info[]; extern const enum battery_type DEFAULT_BATTERY_TYPE; + +#ifdef CONFIG_BATTERY_MEASURE_IMBALANCE +/** + * Report the absolute difference between the highest and lowest cell voltage in + * the battery pack, in millivolts. On error or unimplemented, returns '0'. + */ +int battery_default_imbalance_mv(void); + +#ifdef CONFIG_BATTERY_BQ4050 +int battery_bq4050_imbalance_mv(void); +#endif + +#endif + #endif /* __CROS_EC_BATTERY_FUEL_GAUGE_H */ diff --git a/include/config.h b/include/config.h index 619ee9f55c..4f5688010f 100644 --- a/include/config.h +++ b/include/config.h @@ -266,6 +266,7 @@ #undef CONFIG_BATTERY_BQ20Z453 #undef CONFIG_BATTERY_BQ27541 #undef CONFIG_BATTERY_BQ27621 +#undef CONFIG_BATTERY_BQ4050 #undef CONFIG_BATTERY_MAX17055 /* Compile mock battery support; used by tests. */ @@ -398,6 +399,12 @@ #undef CONFIG_BATTERY_COUNT /* + * Smart battery driver should measure the voltage cell imbalance in the battery + * pack. This requires a battery driver capable of the measurement. + */ +#undef CONFIG_BATTERY_MEASURE_IMBALANCE + +/* * Expose some data when it is needed. * For example, battery disconnect state */ @@ -695,6 +702,15 @@ /* Minimum charger power (in mW) required for powering on. */ #undef CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON +/* Minimum battery percentage for power on with an imbalanced pack */ +#undef CONFIG_CHARGER_MIN_BAT_PCT_IMBALANCED_POWER_ON + +/* + * Maximum battery cell imbalance to accept before considering the pack to be + * imbalanced, in millivolts. + */ +#undef CONFIG_BATTERY_MAX_IMBALANCE_MV + /* Set this option when using a Narrow VDC (NVDC) charger, such as ISL9237/8. */ #undef CONFIG_CHARGER_NARROW_VDC @@ -3667,6 +3683,7 @@ #if defined(CONFIG_BATTERY_BQ20Z453) || \ defined(CONFIG_BATTERY_BQ27541) || \ defined(CONFIG_BATTERY_BQ27621) || \ + defined(CONFIG_BATTERY_BQ4050) || \ defined(CONFIG_BATTERY_MAX17055) || \ defined(CONFIG_BATTERY_SMART) #define CONFIG_BATTERY @@ -3794,6 +3811,40 @@ #endif /* !defined(CONFIG_CHARGER_MIN_POWER_MW_FOR_POWER_ON) */ #endif /* defined(HAS_TASK_CHIPSET) */ +#ifndef CONFIG_CHARGER_MIN_BAT_PCT_IMBALANCED_POWER_ON +/* + * The function of MEASURE_BATTERY_IMBALANCE and these variables is to prevent a + * battery brownout when the management IC reports a state of charge that is + * higher than CHARGER_MIN_BAT_PCT_FOR_POWER_ON, but an individual cell is lower + * than the rest of the pack. The critical term is MAX_IMBALANCE_MV, which must + * be small enough to ensure that the system can reliably boot even when the + * battery total state of charge barely passes the + * CHARGER_MIN_BAT_PCT_FOR_POWER_ON threshold. + * + * Lowering CHARGER_MIN_BAT_PCT_IMBALANCED_POWER_ON below + * CHARGER_MIN_BAT_PCT_FOR_POWER_ON disables this check. Raising it too high + * may needlessly prevent boot when the lowest cell can still support the + * system. + * + * As this term is lowered and BATTERY_MAX_IMBALANCE_MV is raised, the risk of + * cell-undervoltage brownout during startup increases. Raising this term and + * lowering MAX_IMBALANCE_MV increases the risk of poor UX when the user must + * wait longer to turn on their device. + */ +#define CONFIG_CHARGER_MIN_BAT_PCT_IMBALANCED_POWER_ON 5 +#endif + +#ifndef CONFIG_BATTERY_MAX_IMBALANCE_MV +/* + * WAG. Imbalanced battery packs in this situation appear to have balanced + * charge very quickly after beginning the charging cycle, since dV/dQ rapidly + * decreases as the cell is charged out of deep discharge. Increasing the value + * of CHARGER_MIN_BAT_PCT_IMBALANCED_POWER_ON will make a system tolerant of + * larger values of BATTERY_MAX_IMBALANCE_MV. + */ +#define CONFIG_BATTERY_MAX_IMBALANCE_MV 200 +#endif + #ifndef HAS_TASK_KEYPROTO #undef CONFIG_KEYBOARD_PROTOCOL_8042 /* |