From 07b614df7fed45289e2b30b1c3505adbe3387bf6 Mon Sep 17 00:00:00 2001 From: Dave Parker Date: Thu, 12 Jun 2014 20:31:26 -0700 Subject: Add 'at-shutdown' option to batterycutoff host command If at-shutdown is specified, the battery is cut off 1 seconds after the host has shutdown. BUG=chrome-os-partner:29292,chrome-os-partner:28887 BRANCH=tot,nyan TEST=Run batterycutoff ectool command and cutoff console command with and without 'at-shutdown' option. Verify the battery is cut off immediately without the option specified and 1 seconds after shutdown with. View the console log to see the deferred cutoff occur. The following tests are verified on big. console: cutoff, AC on: system is off after removing AC. cutoff, AC off: system is off immediately. at-shutdown, AC on: system is off after "power off" and removing AC. at-shutdown, AC off: system is off after "power off". ectool: batterycutoff, AC on: system is off after removing AC. batterycutoff, AC off: system is off immediately. at-shutdown, AC on: battery is cut off after 1s of shutdown. system is off right after removing AC power. at-shutdown, AC off: system is off after 1s of shutdown. [84.058416 power state 3 = S0, in 0x0000] [84.058803 power lost input; wanted 0x0001, got 0x0000] [84.059120 power off 3] [84.072148 Cutting off battery in 1 second(s)] [84.123896 power shutdown complete] [84.128790 power state 7 = S0->S3, in 0x0002] [84.139694 power state 2 = S3, in 0x0002] [84.150857 power state 8 = S3->S5, in 0x0002] [84.166975 power state 1 = S5, in 0x0002] [84.177972 power state 1 = S5, in 0x0002] [85.080012 Battery cut off succeeded.] Change-Id: I56236187fb41c3b9f8cb0c4d0e48080922f075a2 Original-Change-Id: Id4bacf79ad3add885260655f80cb8127bafe1ad6 Signed-off-by: Dave Parker Signed-off-by: Louis Yung-Chieh Lo Reviewed-on: https://chromium-review.googlesource.com/203849 Reviewed-by: David Hendricks --- common/battery.c | 97 ++++++++++++++++++++++++++++++++++++++++++--------- include/battery.h | 6 ++++ include/config.h | 20 +++++++++++ include/ec_commands.h | 14 ++++++-- util/ectool.c | 27 ++++++++++---- 5 files changed, 138 insertions(+), 26 deletions(-) diff --git a/common/battery.c b/common/battery.c index b6e79bb383..277222f5da 100644 --- a/common/battery.c +++ b/common/battery.c @@ -17,8 +17,17 @@ #include "util.h" #include "watchdog.h" +#define CPRINTF(format, args...) cprintf(CC_CHARGER, format, ## args) + #ifdef CONFIG_BATTERY_CUT_OFF -static int is_cut_off; + +#ifndef CONFIG_BATTERY_CUTOFF_DELAY_US +#define CONFIG_BATTERY_CUTOFF_DELAY_US (1 * SECOND) +#endif + +static enum battery_cutoff_states battery_cutoff_state = + BATTERY_CUTOFF_STATE_NORMAL; + #endif #ifdef CONFIG_BATTERY_PRESENT_GPIO @@ -256,41 +265,95 @@ DECLARE_CONSOLE_COMMAND(battery, command_battery, "Print battery info", NULL); - #ifdef CONFIG_BATTERY_CUT_OFF int battery_is_cut_off(void) { - return is_cut_off; + return (battery_cutoff_state == BATTERY_CUTOFF_STATE_CUT_OFF); } -static void clean_cut_off(void) +static void pending_cutoff_deferred(void) { - if (extpower_is_present()) - is_cut_off = 0; + int rv; + + rv = board_cut_off_battery(); + + if (rv == EC_SUCCESS) + CPRINTF("[%T Battery cut off succeeded.]\n"); + else + CPRINTF("[%T Battery cut off failed!]\n"); } -DECLARE_HOOK(HOOK_AC_CHANGE, clean_cut_off, HOOK_PRIO_DEFAULT); +DECLARE_DEFERRED(pending_cutoff_deferred); -static int battery_command_cut_off(struct host_cmd_handler_args *args) +static void clear_pending_cutoff(void) { - int rv = board_cut_off_battery(); - if (!rv) - is_cut_off = 1; + if (extpower_is_present()) { + battery_cutoff_state = BATTERY_CUTOFF_STATE_NORMAL; + hook_call_deferred(pending_cutoff_deferred, -1); + } +} +DECLARE_HOOK(HOOK_AC_CHANGE, clear_pending_cutoff, HOOK_PRIO_DEFAULT); + +static int battery_command_cutoff(struct host_cmd_handler_args *args) +{ + const struct ec_params_battery_cutoff *p; + int rv; + + if (args->version == 1) { + p = args->params; + if (p->flags & EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN) { + battery_cutoff_state = BATTERY_CUTOFF_STATE_PENDING; + CPRINTF("[%T BAT cut off at-shutdown is scheduled]\n"); + return EC_RES_SUCCESS; + } + } + + rv = board_cut_off_battery(); + if (!rv) { + CPRINTF("[%T Battery cut off is successful.]\n"); + battery_cutoff_state = BATTERY_CUTOFF_STATE_CUT_OFF; + } else { + CPRINTF("[%T Battery cut off has failed.]\n"); + } return rv; } -DECLARE_HOST_COMMAND(EC_CMD_BATTERY_CUT_OFF, battery_command_cut_off, - EC_VER_MASK(0)); +DECLARE_HOST_COMMAND(EC_CMD_BATTERY_CUT_OFF, battery_command_cutoff, + EC_VER_MASK(0) | EC_VER_MASK(1)); + +static void check_pending_cutoff(void) +{ + if (battery_cutoff_state == BATTERY_CUTOFF_STATE_PENDING) { + CPRINTF("[%T Cutting off battery in %d second(s)]\n", + CONFIG_BATTERY_CUTOFF_DELAY_US / SECOND); + hook_call_deferred(pending_cutoff_deferred, + CONFIG_BATTERY_CUTOFF_DELAY_US); + } +} +DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, check_pending_cutoff, HOOK_PRIO_LAST); static int command_cutoff(int argc, char **argv) { - int rv = board_cut_off_battery(); - if (!rv) - is_cut_off = 1; + int rv; + + if (argc > 1) { + if (!strcasecmp(argv[1], "at-shutdown")) { + battery_cutoff_state = BATTERY_CUTOFF_STATE_PENDING; + return EC_SUCCESS; + } else { + return EC_ERROR_INVAL; + } + } + + rv = board_cut_off_battery(); + if (!rv) { + ccprintf("[%T Battery cut off]\n"); + battery_cutoff_state = BATTERY_CUTOFF_STATE_CUT_OFF; + } return rv; } DECLARE_CONSOLE_COMMAND(cutoff, command_cutoff, - "", + "[at-shutdown]", "Cut off the battery output", NULL); #else diff --git a/include/battery.h b/include/battery.h index c66b5f3064..4402bf8cfb 100644 --- a/include/battery.h +++ b/include/battery.h @@ -43,6 +43,12 @@ enum battery_present { BP_NOT_SURE, }; +enum battery_cutoff_states { + BATTERY_CUTOFF_STATE_NORMAL = 0, + BATTERY_CUTOFF_STATE_CUT_OFF, + BATTERY_CUTOFF_STATE_PENDING, +}; + /* Battery parameters */ struct batt_params { int temperature; /* Temperature in 0.1 K */ diff --git a/include/config.h b/include/config.h index 6ae0edc71b..a34426d9c0 100644 --- a/include/config.h +++ b/include/config.h @@ -136,6 +136,26 @@ */ #undef CONFIG_BATTERY_CUT_OFF +/* + * The default delay is 1 second. Define this if a board prefers + * different delay. + */ +#undef CONFIG_BATTERY_CUTOFF_DELAY_US + +/* + * The board-specific battery.c implements get and set functions to read and + * write arbirary vendor-specific parameters stored in the battery. + * See include/battery.h for prototypes. + */ +#undef CONFIG_BATTERY_VENDOR_PARAM + +/* + * TODO(crosbug.com/p/29467): allows charging of a dead battery that + * requests nil for current and voltage. Remove this workaround when + * possible. + */ +#undef CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD + /*****************************************************************************/ /* diff --git a/include/ec_commands.h b/include/ec_commands.h index eac00da6b3..5bdd8dc265 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -1842,12 +1842,20 @@ struct ec_params_charge_control { /*****************************************************************************/ /* - * Cut off battery power output if the battery supports. + * Cut off battery power immediately or after the host has shut down. * - * For unsupported battery, just don't implement this command and lets EC - * return EC_RES_INVALID_COMMAND. + * return EC_RES_INVALID_COMMAND if unsupported by a board/battery. + * EC_RES_SUCCESS if the command was successful. + * EC_RES_ERROR if the cut off command failed. */ #define EC_CMD_BATTERY_CUT_OFF 0x99 +#define EC_VER_BATTERY_CUT_OFF 1 + +#define EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN (1 << 0) + +struct ec_params_battery_cutoff { + uint8_t flags; +} __packed; /*****************************************************************************/ /* USB port mux control. */ diff --git a/util/ectool.c b/util/ectool.c index 4d827f52af..7e5050d908 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -34,7 +34,7 @@ const char help_str[] = " Enable/disable LCD backlight\n" " battery\n" " Prints battery info\n" - " batterycutoff\n" + " batterycutoff [at-shutdown]\n" " Cut off battery output power\n" " boardversion\n" " Prints the board version\n" @@ -3303,9 +3303,21 @@ cmd_error: int cmd_battery_cut_off(int argc, char *argv[]) { + struct ec_params_battery_cutoff p; int rv; - rv = ec_command(EC_CMD_BATTERY_CUT_OFF, 0, NULL, 0, NULL, 0); + memset(&p, 0, sizeof(p)); + if (argc > 1) { + if (!strcasecmp(argv[1], "at-shutdown")) { + p.flags = EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN; + } else { + fprintf(stderr, "Bad parameter: %s\n", argv[1]); + return -1; + } + } + + rv = ec_command(EC_CMD_BATTERY_CUT_OFF, EC_VER_BATTERY_CUT_OFF, + &p, sizeof(p), NULL, 0); rv = (rv < 0 ? rv : 0); if (rv < 0) { @@ -3316,11 +3328,14 @@ int cmd_battery_cut_off(int argc, char *argv[]) EC_RES_INVALID_COMMAND); } else { printf("\n"); - printf("SUCCESS. The battery has arranged a cut-off and\n"); - printf("the system should be shutdown immediately.\n"); + printf("SUCCESS. The battery has arranged a cut-off.\n"); + + if (p.flags & EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN) + printf("The battery will be cut off after shutdown.\n"); + else + printf("The system should be shutdown immediately.\n"); + printf("\n"); - printf("If the system is still alive, you could remove\n"); - printf("the AC power and try again.\n"); } return rv; } -- cgit v1.2.1