diff options
-rw-r--r-- | common/charge_state_v2.c | 40 | ||||
-rw-r--r-- | include/charge_state.h | 5 | ||||
-rw-r--r-- | include/config.h | 15 | ||||
-rw-r--r-- | test/sbs_charging_v2.c | 30 | ||||
-rw-r--r-- | test/test_config.h | 3 |
5 files changed, 93 insertions, 0 deletions
diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index 110d63c7bf..59f38edee8 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -1857,6 +1857,39 @@ static void wakeup_battery(int *need_static) } } +__test_only enum charge_state_v2 charge_get_state_v2(void) +{ + return curr.state; +} + +static void deep_charge_battery(int *need_static) +{ + if (curr.state == ST_IDLE) { + /* Deep charge time out , do nothing */ + curr.requested_voltage = 0; + curr.requested_current = 0; + } else if (curr.state == ST_PRECHARGE + && (get_time().val > precharge_start_time.val + + CONFIG_BATTERY_LOW_VOLTAGE_TIMEOUT)) { + /* We've tried long enough, give up */ + CPRINTS("Precharge for low voltage timed out"); + set_charge_state(ST_IDLE); + curr.requested_voltage = 0; + curr.requested_current = 0; + } else { + /* See if we can wake it up */ + if (curr.state != ST_PRECHARGE) { + CPRINTS("Start precharge for low voltage"); + precharge_start_time = get_time(); + *need_static = 1; + } + set_charge_state(ST_PRECHARGE); + curr.requested_voltage = batt_info->voltage_max; + curr.requested_current = batt_info->precharge_current; + } +} + + static void revive_battery(int *need_static) { if (IS_ENABLED(CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD) @@ -2108,6 +2141,13 @@ void charger_task(void *u) goto wait_for_it; } + if (IS_ENABLED(CONFIG_BATTERY_LOW_VOLTAGE_PROTECTION) + && !(curr.batt.flags & BATT_FLAG_BAD_VOLTAGE) + && (curr.batt.voltage <= batt_info->voltage_min)) { + deep_charge_battery(&need_static); + goto wait_for_it; + } + /* The battery is responding. Yay. Try to use it. */ /* diff --git a/include/charge_state.h b/include/charge_state.h index 0ab7ecd686..9349c3ea4c 100644 --- a/include/charge_state.h +++ b/include/charge_state.h @@ -82,6 +82,11 @@ enum charge_state { enum charge_state charge_get_state(void); /** + * Return current charge v2 state. + */ +__test_only enum charge_state_v2 charge_get_state_v2(void); + +/** * Return non-zero if battery is so low we want to keep AP off. */ int charge_keep_power_off(void); diff --git a/include/config.h b/include/config.h index 71f649bbc9..9ce47f8287 100644 --- a/include/config.h +++ b/include/config.h @@ -610,6 +610,21 @@ #undef CONFIG_BATTERY_REVIVE_DISCONNECT /* + * Low voltage protection for a battery (a.k.a. deep charge inspection): + * If battery voltage is lower than voltage_min, deep charge for more + * than precharge time The battery voltage is still lower than voltage_min, + * the system will stop charging + */ +#undef CONFIG_BATTERY_LOW_VOLTAGE_PROTECTION + +/* + * If battery voltage is lower than voltage_min, precharge voltage & current + * are supplied and charging will be disabled after + * CONFIG_BATTERY_LOW_VOLTAGE_TIMEOUT seconds. + */ +#define CONFIG_BATTERY_LOW_VOLTAGE_TIMEOUT (30*60*SECOND) + +/* * Specify the battery percentage at which the host is told it is full. * If this value is not specified the default is 97% set in battery.h. */ diff --git a/test/sbs_charging_v2.c b/test/sbs_charging_v2.c index bdca592d6c..2f9ddee57c 100644 --- a/test/sbs_charging_v2.c +++ b/test/sbs_charging_v2.c @@ -365,6 +365,35 @@ static int test_low_battery(void) return EC_SUCCESS; } +static int test_deep_charge_battery(void) +{ + enum charge_state_v2 state_v2; + const struct battery_info *bat_info = battery_get_info(); + + test_setup(1); + + /* battery pack voltage bellow voltage_min */ + sb_write(SB_VOLTAGE, (bat_info->voltage_min - 200)); + wait_charging_state(); + state_v2 = charge_get_state_v2(); + TEST_ASSERT(state_v2 == ST_PRECHARGE); + + /* + * Battery voltage keep bellow voltage_min, + * precharge over time CONFIG_BATTERY_LOW_VOLTAGE_TIMEOUT + */ + usleep(CONFIG_BATTERY_LOW_VOLTAGE_TIMEOUT); + state_v2 = charge_get_state_v2(); + TEST_ASSERT(state_v2 == ST_IDLE); + + /* recovery from a low voltage. */ + sb_write(SB_VOLTAGE, (bat_info->voltage_normal)); + wait_charging_state(); + state_v2 = charge_get_state_v2(); + TEST_ASSERT(state_v2 == ST_CHARGE); + + return EC_SUCCESS; +} static int test_high_temp_battery(void) { test_setup(1); @@ -935,6 +964,7 @@ void run_test(int argc, char **argv) RUN_TEST(test_low_battery_hostevents); RUN_TEST(test_battery_sustainer); RUN_TEST(test_battery_sustainer_discharge_idle); + RUN_TEST(test_deep_charge_battery); test_print_result(); } diff --git a/test/test_config.h b/test/test_config.h index 5afc5d1282..a60393dc42 100644 --- a/test/test_config.h +++ b/test/test_config.h @@ -282,6 +282,9 @@ int board_discharge_on_ac(int enabled); #define I2C_PORT_MASTER 0 #define I2C_PORT_BATTERY 0 #define I2C_PORT_CHARGER 0 +#define CONFIG_BATTERY_LOW_VOLTAGE_PROTECTION +#undef CONFIG_BATTERY_LOW_VOLTAGE_TIMEOUT +#define CONFIG_BATTERY_LOW_VOLTAGE_TIMEOUT (2*SECOND) #endif #ifdef TEST_THERMAL |