diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-12-15 08:45:54 -0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-12-15 22:44:28 +0000 |
commit | fca4977983cb6082047321c935e5efa64f9f5bdb (patch) | |
tree | de5919c4048b55782b005c2cfc0c7e5cea1203e8 | |
parent | 6cc992c3d703ecee5e44966a2a3f6580e85b60c3 (diff) | |
download | chrome-ec-fca4977983cb6082047321c935e5efa64f9f5bdb.tar.gz |
samus: add high battery temp warning to charge state machine
Add high (and low) battery temperature warning which sends host
event to AP. After 30 seconds of out of range temp readings force
shut off AP and hibernate the EC.
BUG=chrome-os-partner:27641, chrome-os-partner:33111
BRANCH=samus
TEST=make buildall, and write unit tests to test this condition.
Change-Id: I95b7d9d753c17e4b76218a9845aa63dd1b96a500
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/235645
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r-- | common/charge_state_v2.c | 55 | ||||
-rw-r--r-- | include/charge_state.h | 2 | ||||
-rw-r--r-- | test/sbs_charging_v2.c | 33 |
3 files changed, 71 insertions, 19 deletions
diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index 74d8e910f5..531cc8bf83 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -29,6 +29,7 @@ #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 PRECHARGE_TIMEOUT_US (PRECHARGE_TIMEOUT * SECOND) #define LFCC_EVENT_THRESH 5 /* Full-capacity change reqd for host event */ @@ -43,6 +44,7 @@ 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; @@ -360,23 +362,19 @@ static int charge_force_idle(int enable) return EC_SUCCESS; } +/* True if we know the battery temp is too high or too low */ +static inline int battery_too_hot(int batt_temp_c) +{ + return (!(curr.batt.flags & BATT_FLAG_BAD_TEMPERATURE) && + (batt_temp_c > batt_info->discharging_max_c || + batt_temp_c < batt_info->discharging_min_c)); +} + static void prevent_hot_discharge(void) { int batt_temp_c; - /* If the AP is off already, the thermal task should handle it. */ - if (!chipset_in_state(CHIPSET_STATE_ON)) - return; - - /* Same if we can't read the battery temp. */ - if (curr.batt.flags & BATT_FLAG_BAD_TEMPERATURE) - return; - /* - * TODO(crosbug.com/p/27641): Shouldn't we do this in stages, like - * prevent_deep_discharge()? Send an event, give the AP time to react, - * maybe even hibernate the EC if things are really bad? - * * 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 @@ -384,12 +382,35 @@ static void prevent_hot_discharge(void) * should, just in case. */ batt_temp_c = DECI_KELVIN_TO_CELSIUS(curr.batt.temperature); - if (batt_temp_c > batt_info->discharging_max_c || - batt_temp_c < batt_info->discharging_min_c) { - CPRINTS("charge force shutdown due to battery temp %dC", + + if (!battery_too_hot(batt_temp_c)) { + /* Reset shutdown warning time */ + shutdown_batttemp_warning_time.val = 0; + return; + } + + 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); - chipset_force_shutdown(); - host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN); + 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(); + } } } diff --git a/include/charge_state.h b/include/charge_state.h index c23e70c260..5c81decf10 100644 --- a/include/charge_state.h +++ b/include/charge_state.h @@ -12,6 +12,8 @@ /* Seconds after AP battery shutdown warning before we kill the AP */ #define LOW_BATTERY_SHUTDOWN_TIMEOUT 30 +#define HIGH_TEMP_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 bb15a8d18b..bb5097948c 100644 --- a/test/sbs_charging_v2.c +++ b/test/sbs_charging_v2.c @@ -222,6 +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); TEST_ASSERT(is_shutdown); TEST_ASSERT(state == PWR_STATE_DISCHARGE); sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(40)); @@ -265,14 +266,20 @@ static int test_low_battery(void) { test_setup(1); - ccprintf("[CHARGING TEST] Low battery with AC\n"); - + ccprintf("[CHARGING TEST] Low battery with AC and positive current\n"); sb_write(SB_RELATIVE_STATE_OF_CHARGE, 2); + sb_write(SB_CURRENT, 1000); wait_charging_state(); mock_chipset_state = CHIPSET_STATE_SOFT_OFF; hook_notify(HOOK_CHIPSET_SHUTDOWN); TEST_ASSERT(!is_hibernated); + ccprintf("[CHARGING TEST] Low battery with AC and negative current\n"); + sb_write(SB_CURRENT, -1000); + wait_charging_state(); + sleep(LOW_BATTERY_SHUTDOWN_TIMEOUT); + TEST_ASSERT(is_hibernated); + ccprintf("[CHARGING TEST] Low battery shutdown S0->S5\n"); mock_chipset_state = CHIPSET_STATE_ON; hook_notify(HOOK_CHIPSET_PRE_INIT); @@ -317,6 +324,27 @@ static int test_low_battery(void) return EC_SUCCESS; } +static int test_high_temp_battery(void) +{ + test_setup(1); + + ccprintf("[CHARGING TEST] High battery temperature shutdown\n"); + ev_clear(EC_HOST_EVENT_BATTERY_SHUTDOWN); + sb_write(SB_TEMPERATURE, CELSIUS_TO_DECI_KELVIN(90)); + wait_charging_state(); + TEST_ASSERT(ev_is_set(EC_HOST_EVENT_BATTERY_SHUTDOWN)); + TEST_ASSERT(!is_shutdown); + sleep(HIGH_TEMP_SHUTDOWN_TIMEOUT); + TEST_ASSERT(is_shutdown); + + ccprintf("[CHARGING TEST] High battery temp S0->S5 hibernate\n"); + mock_chipset_state = CHIPSET_STATE_SOFT_OFF; + wait_charging_state(); + TEST_ASSERT(is_hibernated); + + return EC_SUCCESS; +} + static int test_external_funcs(void) { int rv, temp; @@ -650,6 +678,7 @@ void run_test(void) { RUN_TEST(test_charge_state); RUN_TEST(test_low_battery); + RUN_TEST(test_high_temp_battery); RUN_TEST(test_external_funcs); RUN_TEST(test_hc_charge_state); RUN_TEST(test_hc_current_limit); |