diff options
-rw-r--r-- | common/charge_state.c | 51 | ||||
-rw-r--r-- | include/charge_state.h | 1 |
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; }; |