summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-03-01 11:13:30 -0800
committerRandall Spangler <rspangler@chromium.org>2013-03-05 15:43:06 -0800
commit30c7f6f0a52d7b0f1878c0dfbfbe633f55efd7db (patch)
treeb7887889831efd9f0cdcd3a93a673dfc8f93930d
parentac05ba645e813d5a77af63cf031fd547ecf49ba5 (diff)
downloadchrome-ec-30c7f6f0a52d7b0f1878c0dfbfbe633f55efd7db.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) Original-Change-Id: I1a13765f501d705d3a580b2acbbb173d47e020ff Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/44413 (cherry picked from commit e60f1ab2246e2eac9b667690c39873baa974ab5b) Conflicts: common/charge_state.c Change-Id: I2033a50d302e63dbaa368e8f980f9a1b41bedee4 Reviewed-on: https://gerrit.chromium.org/gerrit/44693 Commit-Queue: Randall Spangler <rspangler@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org> Tested-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--common/charge_state.c51
-rw-r--r--include/charge_state.h1
2 files changed, 32 insertions, 20 deletions
diff --git a/common/charge_state.c b/common/charge_state.c
index a68ddfe6e7..b61f41b05b 100644
--- a/common/charge_state.c
+++ b/common/charge_state.c
@@ -35,6 +35,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;
@@ -101,21 +104,25 @@ static void update_battery_info(void)
*host_get_memmap(EC_MEMMAP_BATTERY_VERSION) = 1;
}
-/* Prevent battery from going into deep discharge state */
-static void poweroff_wait_ac(int hibernate_ec)
+/**
+ * Prevent battery from going into deep discharge state
+ */
+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();
}
}
@@ -242,7 +249,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 */
@@ -314,6 +321,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;
@@ -480,13 +490,14 @@ static enum power_state state_discharge(struct power_state_context *ctx)
if (ctx->curr.error)
return PWR_STATE_ERROR;
- /* Overtemp in discharging state
- * - poweroff host and ec
- */
- if (batt->temperature > ctx->battery->temp_discharge_max ||
- batt->temperature < ctx->battery->temp_discharge_min)
- poweroff_wait_ac(0);
-
+ /* Handle overtemp in discharging state by powering off host */
+ 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 285164c75a..4dcc7cdfa0 100644
--- a/include/charge_state.h
+++ b/include/charge_state.h
@@ -117,6 +117,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;
};