diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-02-28 12:51:24 -0800 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2013-03-05 15:26:52 -0800 |
commit | 2e59225288b604537e61489a15d8db93e42ff79c (patch) | |
tree | 0f264387e34b275c263193893d544d3b1236ee84 | |
parent | 56fd9a7c00b1f673d4599a67a3f57ace63ac5213 (diff) | |
download | chrome-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.c | 64 | ||||
-rw-r--r-- | common/charge_state.c | 7 |
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: |