summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-03-01 11:13:30 -0800
committerChromeBot <chrome-bot@google.com>2013-03-05 10:26:21 -0800
commite60f1ab2246e2eac9b667690c39873baa974ab5b (patch)
treec3f4335919dce865d37f5e76c55c33177155b3b9
parent6971fd7a7f8a2351f011bdd60eabda664e0c3ba2 (diff)
downloadchrome-ec-e60f1ab2246e2eac9b667690c39873baa974ab5b.tar.gz
Give the AP 30 sec warning before shutting down due to low battery
This allows the AP to shut down cleanly. If it doesn't shut down in that time period, the EC will forcibly shut it down. BUG=chrome-os-partner:17124 BRANCH=link TEST=manual 1. With system off, - battfake 2 -> EC hibernates immediately 2. With system on, - battfake 2 -> battery shutdown event posted to AP - power off system manually within 30 sec -> EC hibernates 3. With system on, - battfake 2 -> battery shutdown event posted to AP - do not power off AP - after 30 sec, EC shuts down AP then hibernates 4. With system on, - battfake 2 -> battery shutdown event posted to AP - after 15 sec, apply AC power - system does NOT shut down - remove AC power -> battery shutdown event posted to AP (because battfake 2 is still faking 2% battery left) - after 30 sec, EC shuts down AP then hibernates (check to make sure the full 30 sec elapses; the timer should have been restarted when AC power was removed; if the EC shuts down the AP immediately this is a failure indicating the timer is still running from the first shutdown event) Change-Id: I1a13765f501d705d3a580b2acbbb173d47e020ff Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/44413
-rw-r--r--common/charge_state.c45
-rw-r--r--include/charge_state.h1
2 files changed, 28 insertions, 18 deletions
diff --git a/common/charge_state.c b/common/charge_state.c
index 7612f91036..5cbea09aa6 100644
--- a/common/charge_state.c
+++ b/common/charge_state.c
@@ -34,6 +34,9 @@
/* Time period between setting power LED */
#define SET_LED_PERIOD (10 * SECOND)
+/* Timeout after AP battery shutdown warning before we kill the AP */
+#define LOW_BATTERY_SHUTDOWN_TIMEOUT_US (30 * SECOND)
+
static const char * const state_name[] = POWER_STATE_NAME_TABLE;
static int state_machine_force_idle = 0;
@@ -104,23 +107,23 @@ static void update_battery_info(void)
/**
* Prevent battery from going into deep discharge state
- *
- * @param hibernate_ec Also force EC into its lowest-power state?
*/
-static void poweroff_wait_ac(int hibernate_ec)
+static void low_battery_shutdown(struct power_state_context *ctx)
{
- if (chipset_in_state(CHIPSET_STATE_ON)) {
- /*
- * Shut down the AP. The EC will hibernate after the AP shuts
- * down.
- */
- CPRINTF("[%T charge force shutdown due to low battery]\n");
- chipset_force_shutdown();
- host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN);
- } else if (hibernate_ec) {
- /* If battery level is critical, hibernate the EC */
+ if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
+ /* AP is off, so shut down the EC now */
CPRINTF("[%T charge force EC hibernate due to low battery]\n");
system_hibernate(0, 0);
+ } else if (!ctx->shutdown_warning_time.val) {
+ /* Warn AP battery level is so low we'll shut down */
+ CPRINTF("[%T charge warn shutdown due to low battery]\n");
+ ctx->shutdown_warning_time = get_time();
+ host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN);
+ } else if (get_time().val > ctx->shutdown_warning_time.val +
+ LOW_BATTERY_SHUTDOWN_TIMEOUT_US) {
+ /* Timeout waiting for AP to shut down, so kill it */
+ CPRINTF("[%T charge force shutdown due to low battery]\n");
+ chipset_force_shutdown();
}
}
@@ -245,7 +248,7 @@ static int state_common(struct power_state_context *ctx)
!(curr->error & F_BATTERY_STATE_OF_CHARGE)) ||
(batt->voltage <= ctx->battery->voltage_min &&
!(curr->error & F_BATTERY_VOLTAGE)))
- poweroff_wait_ac(1);
+ low_battery_shutdown(ctx);
}
/* Check battery presence */
@@ -317,6 +320,9 @@ static enum power_state state_init(struct power_state_context *ctx)
/* Update static battery info */
update_battery_info();
+ /* Clear shutdown timer */
+ ctx->shutdown_warning_time.val = 0;
+
/* If AC is not present, switch to discharging state */
if (!ctx->curr.ac)
return PWR_STATE_DISCHARGE;
@@ -490,10 +496,13 @@ static enum power_state state_discharge(struct power_state_context *ctx)
return PWR_STATE_ERROR;
/* Handle overtemp in discharging state by powering off host */
- if (batt->temperature > ctx->battery->temp_discharge_max ||
- batt->temperature < ctx->battery->temp_discharge_min)
- poweroff_wait_ac(0);
-
+ if ((batt->temperature > ctx->battery->temp_discharge_max ||
+ batt->temperature < ctx->battery->temp_discharge_min) &&
+ chipset_in_state(CHIPSET_STATE_ON)) {
+ CPRINTF("[%T charge force shutdown due to battery temp]\n");
+ chipset_force_shutdown();
+ host_set_single_event(EC_HOST_EVENT_BATTERY_SHUTDOWN);
+ }
return PWR_STATE_UNCHANGE;
}
diff --git a/include/charge_state.h b/include/charge_state.h
index 5f90de36fd..fcb68be89d 100644
--- a/include/charge_state.h
+++ b/include/charge_state.h
@@ -111,6 +111,7 @@ struct power_state_context {
timestamp_t charger_update_time;
timestamp_t trickle_charging_time;
timestamp_t voltage_debounce_time;
+ timestamp_t shutdown_warning_time;
int battery_present;
};