summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/careena/battery.c12
-rw-r--r--board/careena/board.h3
-rw-r--r--common/battery_fuel_gauge.c19
-rw-r--r--common/charge_state_v2.c9
-rw-r--r--driver/battery/bq4050.c39
-rw-r--r--driver/battery/smart.c5
-rw-r--r--driver/build.mk1
-rw-r--r--include/battery.h7
-rw-r--r--include/battery_fuel_gauge.h19
-rw-r--r--include/config.h51
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
/*