diff options
-rw-r--r-- | common/charge_state_v1.c | 3 | ||||
-rw-r--r-- | common/charge_state_v2.c | 92 | ||||
-rw-r--r-- | include/charge_state.h | 3 | ||||
-rw-r--r-- | test/sbs_charging_v2.c | 12 |
4 files changed, 43 insertions, 67 deletions
diff --git a/common/charge_state_v1.c b/common/charge_state_v1.c index 9be0d47c15..a39499a75d 100644 --- a/common/charge_state_v1.c +++ b/common/charge_state_v1.c @@ -29,7 +29,8 @@ /* Voltage debounce time */ #define DEBOUNCE_TIME (10 * SECOND) -#define LOW_BATTERY_SHUTDOWN_TIMEOUT_US (LOW_BATTERY_SHUTDOWN_TIMEOUT * SECOND) +#define LOW_BATTERY_SHUTDOWN_TIMEOUT_US \ + (CRITICAL_BATTERY_SHUTDOWN_TIMEOUT * SECOND) #ifndef BATTERY_AP_OFF_LEVEL #define BATTERY_AP_OFF_LEVEL 0 diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index 051113c0e2..e692f68703 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -28,8 +28,8 @@ #define CPUTS(outstr) cputs(CC_CHARGER, outstr) #define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args) -#define LOW_BATTERY_SHUTDOWN_TIMEOUT_US (LOW_BATTERY_SHUTDOWN_TIMEOUT * SECOND) -#define HIGH_TEMP_SHUTDOWN_TIMEOUT_US (HIGH_TEMP_SHUTDOWN_TIMEOUT * SECOND) +#define CRITICAL_BATTERY_SHUTDOWN_TIMEOUT_US \ + (CRITICAL_BATTERY_SHUTDOWN_TIMEOUT * SECOND) #define PRECHARGE_TIMEOUT_US (PRECHARGE_TIMEOUT * SECOND) #define LFCC_EVENT_THRESH 5 /* Full-capacity change reqd for host event */ @@ -45,7 +45,6 @@ static int state_machine_force_idle; static int manual_mode; /* volt/curr are no longer maintained by charger */ static unsigned int user_current_limit = -1U; test_export_static timestamp_t shutdown_warning_time; -test_export_static timestamp_t shutdown_batttemp_warning_time; static timestamp_t precharge_start_time; static int battery_seems_to_be_dead; static int battery_seems_to_be_disconnected; @@ -402,87 +401,65 @@ static inline int battery_too_hot(int batt_temp_c) batt_temp_c < batt_info->discharging_min_c)); } -static void prevent_hot_discharge(void) +/* True if we know the charge is too low, or we know the voltage is too low. */ +static inline int battery_too_low(void) +{ + return ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && + curr.batt.state_of_charge < BATTERY_LEVEL_SHUTDOWN) || + (!(curr.batt.flags & BATT_FLAG_BAD_VOLTAGE) && + curr.batt.voltage <= batt_info->voltage_min)); +} + + +/* + * Send host event to the AP if the battery is temperature or charge level + * is critical. Force-shutdown if the problem isn't corrected after timeout. + */ +static void shutdown_on_critical_battery(void) { int batt_temp_c; + int battery_critical = 0; /* * TODO(crosbug.com/p/27642): The thermal loop should watch the battery - * temp anyway, so it can turn fans on. It could also force an AP - * shutdown if it's too hot, but AFAIK we don't have anything in place - * to do a battery shutdown if it's really really hot. We probably - * should, just in case. + * temp, so it can turn fans on. */ batt_temp_c = DECI_KELVIN_TO_CELSIUS(curr.batt.temperature); - - if (!battery_too_hot(batt_temp_c)) { - /* Reset shutdown warning time */ - shutdown_batttemp_warning_time.val = 0; - return; + if (battery_too_hot(batt_temp_c)) { + CPRINTS("Batt temp out of range: %dC", batt_temp_c); + battery_critical = 1; } - CPRINTS("Batt temp out of range %dC", batt_temp_c); - - if (!shutdown_batttemp_warning_time.val) { - CPRINTS("charge warn shutdown due to battery temp %dC", - batt_temp_c); - shutdown_batttemp_warning_time.val = get_time().val; - if (!chipset_in_state(CHIPSET_STATE_ANY_OFF)) - host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN); - } else if (get_time().val > shutdown_batttemp_warning_time.val + - HIGH_TEMP_SHUTDOWN_TIMEOUT_US) { - if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { -#ifdef CONFIG_HIBERNATE - /* Timeout waiting for temp to change */ - CPRINTS("charge force EC hib due to batt temp %dC", - batt_temp_c); - system_hibernate(0, 0); -#endif - } else { - CPRINTS("charge force shutdown due to batt temp %dC", - batt_temp_c); - chipset_force_shutdown(); - } + if (battery_too_low() && !curr.batt_is_charging) { + CPRINTS("Low battery: %d%%, %dmV", + curr.batt.state_of_charge, curr.batt.voltage); + battery_critical = 1; } -} - -/* True if we know the charge is too low, or we know the voltage is too low. */ -static inline int battery_too_low(void) -{ - return ((!(curr.batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) && - curr.batt.state_of_charge < BATTERY_LEVEL_SHUTDOWN) || - (!(curr.batt.flags & BATT_FLAG_BAD_VOLTAGE) && - curr.batt.voltage <= batt_info->voltage_min)); -} -/* Shut everything down before the battery completely dies. */ -static void prevent_deep_discharge(void) -{ - if (!battery_too_low() || curr.batt_is_charging) { + if (!battery_critical) { /* Reset shutdown warning time */ shutdown_warning_time.val = 0; return; } - CPRINTS("Low battery: %d%%, %dmV", - curr.batt.state_of_charge, curr.batt.voltage); - if (!shutdown_warning_time.val) { - CPRINTS("charge warn shutdown due to low battery"); + CPRINTS("charge warn shutdown due to critical battery"); shutdown_warning_time = get_time(); if (!chipset_in_state(CHIPSET_STATE_ANY_OFF)) host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN); } else if (get_time().val > shutdown_warning_time.val + - LOW_BATTERY_SHUTDOWN_TIMEOUT_US) { + CRITICAL_BATTERY_SHUTDOWN_TIMEOUT_US) { if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) { #ifdef CONFIG_HIBERNATE /* Timeout waiting for charger to provide more power */ - CPRINTS("charge force EC hibernate due to low battery"); + CPRINTS( + "charge force EC hibernate due to critical battery"); system_hibernate(0, 0); #endif } else { /* Timeout waiting for AP to shut down, so kill it */ - CPRINTS("charge force shutdown due to low battery"); + CPRINTS( + "charge force shutdown due to critical battery"); chipset_force_shutdown(); } } @@ -628,8 +605,7 @@ void charger_task(void) curr.batt_is_charging = curr.ac && (curr.batt.current >= 0); /* Don't let the battery hurt itself. */ - prevent_hot_discharge(); - prevent_deep_discharge(); + shutdown_on_critical_battery(); if (!curr.ac) { curr.state = ST_DISCHARGE; diff --git a/include/charge_state.h b/include/charge_state.h index fea4231def..ab9c1043b5 100644 --- a/include/charge_state.h +++ b/include/charge_state.h @@ -11,8 +11,7 @@ /* Stuff that's common to all charger implementations can go here. */ /* Seconds after AP battery shutdown warning before we kill the AP */ -#define LOW_BATTERY_SHUTDOWN_TIMEOUT 30 -#define HIGH_TEMP_SHUTDOWN_TIMEOUT 30 +#define CRITICAL_BATTERY_SHUTDOWN_TIMEOUT 30 /* Seconds to spend trying to wake a non-responsive battery */ #define PRECHARGE_TIMEOUT 30 diff --git a/test/sbs_charging_v2.c b/test/sbs_charging_v2.c index bb5097948c..a42d286378 100644 --- a/test/sbs_charging_v2.c +++ b/test/sbs_charging_v2.c @@ -222,7 +222,7 @@ static int test_charge_state(void) TEST_ASSERT(state == PWR_STATE_DISCHARGE); sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(90)); state = wait_charging_state(); - sleep(HIGH_TEMP_SHUTDOWN_TIMEOUT); + sleep(CRITICAL_BATTERY_SHUTDOWN_TIMEOUT); TEST_ASSERT(is_shutdown); TEST_ASSERT(state == PWR_STATE_DISCHARGE); sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(40)); @@ -277,7 +277,7 @@ static int test_low_battery(void) ccprintf("[CHARGING TEST] Low battery with AC and negative current\n"); sb_write(SB_CURRENT, -1000); wait_charging_state(); - sleep(LOW_BATTERY_SHUTDOWN_TIMEOUT); + sleep(CRITICAL_BATTERY_SHUTDOWN_TIMEOUT); TEST_ASSERT(is_hibernated); ccprintf("[CHARGING TEST] Low battery shutdown S0->S5\n"); @@ -293,7 +293,7 @@ static int test_low_battery(void) hook_notify(HOOK_CHIPSET_SHUTDOWN); wait_charging_state(); /* after a while, the EC should hibernate */ - sleep(LOW_BATTERY_SHUTDOWN_TIMEOUT); + sleep(CRITICAL_BATTERY_SHUTDOWN_TIMEOUT); TEST_ASSERT(is_hibernated); ccprintf("[CHARGING TEST] Low battery shutdown S5\n"); @@ -303,7 +303,7 @@ static int test_low_battery(void) sb_write(SB_RELATIVE_STATE_OF_CHARGE, 2); wait_charging_state(); /* after a while, the EC should hibernate */ - sleep(LOW_BATTERY_SHUTDOWN_TIMEOUT); + sleep(CRITICAL_BATTERY_SHUTDOWN_TIMEOUT); TEST_ASSERT(is_hibernated); ccprintf("[CHARGING TEST] Low battery AP shutdown\n"); @@ -334,7 +334,7 @@ static int test_high_temp_battery(void) wait_charging_state(); TEST_ASSERT(ev_is_set(EC_HOST_EVENT_BATTERY_SHUTDOWN)); TEST_ASSERT(!is_shutdown); - sleep(HIGH_TEMP_SHUTDOWN_TIMEOUT); + sleep(CRITICAL_BATTERY_SHUTDOWN_TIMEOUT); TEST_ASSERT(is_shutdown); ccprintf("[CHARGING TEST] High battery temp S0->S5 hibernate\n"); @@ -666,7 +666,7 @@ static int test_low_battery_hostevents(void) TEST_ASSERT(ev_is_set(EC_HOST_EVENT_BATTERY_SHUTDOWN)); TEST_ASSERT(!is_shutdown); /* after a while, the AP should shut down */ - sleep(LOW_BATTERY_SHUTDOWN_TIMEOUT); + sleep(CRITICAL_BATTERY_SHUTDOWN_TIMEOUT); TEST_ASSERT(is_shutdown); return EC_SUCCESS; |