diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-02-28 12:51:24 -0800 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-03-05 10:26:20 -0800 |
commit | 70cdf52ea1aec0681372a21bc41308a1e4ad20e4 (patch) | |
tree | 4740adeee5f6a3368be4d8fa6ea2e8ce53c37b9a | |
parent | 1866d471f496a4b6905332199f870cc45b7f2515 (diff) | |
download | chrome-ec-70cdf52ea1aec0681372a21bc41308a1e4ad20e4.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
Change-Id: Ie1f2933060fac87b1afe68718f374d51cb8994de
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/44313
-rw-r--r-- | chip/lm4/switch.c | 62 | ||||
-rw-r--r-- | common/charge_state.c | 8 |
2 files changed, 56 insertions, 14 deletions
diff --git a/chip/lm4/switch.c b/chip/lm4/switch.c index 5edf047869..4283916f76 100644 --- a/chip/lm4/switch.c +++ b/chip/lm4/switch.c @@ -5,6 +5,7 @@ /* 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", }; @@ -131,6 +138,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); } @@ -262,6 +278,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 */ @@ -347,20 +364,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; } } @@ -439,6 +443,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 2ab00a68f2..e13f8969ce 100644 --- a/common/charge_state.c +++ b/common/charge_state.c @@ -683,6 +683,14 @@ 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_SWITCH); + switch (new_state) { case PWR_STATE_IDLE0: /* |