summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-02-28 12:51:24 -0800
committerRandall Spangler <rspangler@chromium.org>2013-03-05 15:26:52 -0800
commit2e59225288b604537e61489a15d8db93e42ff79c (patch)
tree0f264387e34b275c263193893d544d3b1236ee84
parent56fd9a7c00b1f673d4599a67a3f57ace63ac5213 (diff)
downloadchrome-ec-2e59225288b604537e61489a15d8db93e42ff79c.tar.gz
Wait to power on system until battery state is known
This prevents the system from waking from hibernate at very low battery, then powering on the AP to do software sync only to find that the charge state machine shuts down the AP before software sync can complete. BUG=chrome-os-partner:17124 BRANCH=link TEST=manual On both AC and mostly-charged battery: - With lid open, reboot EC -> on - With lid open, reboot EC with power held down -> on - With lid closed, reboot EC -> system boots and does EC software sync - With system on -> battfake 2 shuts system down (and at that point, opening lid or pressing power does nothing) With a hacked charge_state.c so fake_state_of_charge starts at 2: - With lid open or closed, reboot EC -> off - Opening lid does not turn on system - Pressing power button does not turn on system - Plug power back in and press power -> system turns on Original-Change-Id: Ie1f2933060fac87b1afe68718f374d51cb8994de Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/44313 (cherry picked from commit 70cdf52ea1aec0681372a21bc41308a1e4ad20e4) Conflicts: common/charge_state.c Change-Id: I9351bf9de763fe34267c6f8009fb17df313d1ac0 Reviewed-on: https://gerrit.chromium.org/gerrit/44690 Commit-Queue: Randall Spangler <rspangler@chromium.org> Reviewed-by: Randall Spangler <rspangler@chromium.org> Tested-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--chip/lm4/power_button.c64
-rw-r--r--common/charge_state.c7
2 files changed, 56 insertions, 15 deletions
diff --git a/chip/lm4/power_button.c b/chip/lm4/power_button.c
index a928f4895b..1b6bb13ab8 100644
--- a/chip/lm4/power_button.c
+++ b/chip/lm4/power_button.c
@@ -1,10 +1,11 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* Power button and lid switch module for Chrome EC */
+#include "charge_state.h"
#include "chipset.h"
#include "common.h"
#include "console.h"
@@ -70,6 +71,11 @@ enum power_button_state {
PWRBTN_STATE_RELEASED,
/* Ignore next button release */
PWRBTN_STATE_EAT_RELEASE,
+ /*
+ * Need to power on system after init, but waiting to find out if
+ * sufficient battery power.
+ */
+ PWRBTN_STATE_INIT_ON,
/* Forced pulse at EC boot due to keyboard controlled reset */
PWRBTN_STATE_BOOT_KB_RESET,
/* Power button pressed when chipset was off; stretching pulse */
@@ -86,6 +92,7 @@ static const char * const state_names[] = {
"lid-open",
"released",
"eat-release",
+ "init-on",
"recovery",
"was-off",
};
@@ -126,6 +133,15 @@ static void update_other_switches(void)
static void set_pwrbtn_to_pch(int high)
{
+ /*
+ * If the battery is discharging and low enough we'd shut down the
+ * system, don't press the power button.
+ */
+ if (!high && charge_want_shutdown()) {
+ CPRINTF("[%T PB PCH pwrbtn ignored due to battery level\n");
+ high = 1;
+ }
+
CPRINTF("[%T PB PCH pwrbtn=%s]\n", high ? "HIGH" : "LOW");
gpio_set_level(GPIO_PCH_PWRBTNn, high);
}
@@ -252,6 +268,7 @@ static void lid_switch_close(uint64_t tnow)
static void power_button_changed(uint64_t tnow)
{
if (pwrbtn_state == PWRBTN_STATE_BOOT_KB_RESET ||
+ pwrbtn_state == PWRBTN_STATE_INIT_ON ||
pwrbtn_state == PWRBTN_STATE_LID_OPEN ||
pwrbtn_state == PWRBTN_STATE_WAS_OFF) {
/* Ignore all power button changes during an initial pulse */
@@ -332,20 +349,7 @@ static void set_initial_pwrbtn_state(void)
* it can verify the EC.
*/
CPRINTF("[%T PB init-on]\n");
- chipset_exit_hard_off();
- set_pwrbtn_to_pch(0);
- tnext_state = get_time().val + PWRBTN_INITIAL_US;
-
- if (debounced_power_pressed) {
- *memmap_switches |= EC_SWITCH_POWER_BUTTON_PRESSED;
-
- if (reset_flags & RESET_FLAG_RESET_PIN)
- pwrbtn_state = PWRBTN_STATE_BOOT_KB_RESET;
- else
- pwrbtn_state = PWRBTN_STATE_WAS_OFF;
- } else {
- pwrbtn_state = PWRBTN_STATE_RELEASED;
- }
+ pwrbtn_state = PWRBTN_STATE_INIT_ON;
}
}
@@ -420,6 +424,36 @@ static void state_machine(uint64_t tnow)
set_pwrbtn_to_pch(1);
pwrbtn_state = PWRBTN_STATE_IDLE;
break;
+ case PWRBTN_STATE_INIT_ON:
+ /*
+ * Don't do anything until the charger knows the battery level.
+ * Otherwise we could power on the AP only to shut it right
+ * back down due to insufficient battery.
+ */
+ if (charge_get_state() == PWR_STATE_INIT)
+ break;
+
+ /*
+ * Power the system on if possible. Gating due to insufficient
+ * battery is handled inside set_pwrbtn_to_pch().
+ */
+ chipset_exit_hard_off();
+ set_pwrbtn_to_pch(0);
+ tnext_state = get_time().val + PWRBTN_INITIAL_US;
+
+ if (debounced_power_pressed) {
+ *memmap_switches |= EC_SWITCH_POWER_BUTTON_PRESSED;
+
+ if (system_get_reset_flags() & RESET_FLAG_RESET_PIN)
+ pwrbtn_state = PWRBTN_STATE_BOOT_KB_RESET;
+ else
+ pwrbtn_state = PWRBTN_STATE_WAS_OFF;
+ } else {
+ pwrbtn_state = PWRBTN_STATE_RELEASED;
+ }
+
+ break;
+
case PWRBTN_STATE_BOOT_KB_RESET:
/* Initial forced pulse is done. Ignore the actual power
* button until it's released, so that holding down the
diff --git a/common/charge_state.c b/common/charge_state.c
index 44d3f81346..09337fd409 100644
--- a/common/charge_state.c
+++ b/common/charge_state.c
@@ -675,6 +675,13 @@ void charge_state_machine_task(void)
state_name[new_state]);
}
+ /*
+ * After first init, wake the switch task so it can
+ * power on the AP if necessary.
+ */
+ if (ctx->prev.state == PWR_STATE_INIT &&
+ new_state != PWR_STATE_INIT)
+ task_wake(TASK_ID_POWERBTN);
switch (new_state) {
case PWR_STATE_IDLE0: