diff options
-rw-r--r-- | board/spring/board.h | 7 | ||||
-rw-r--r-- | chip/stm32/system.c | 9 | ||||
-rw-r--r-- | common/battery_spring.c | 60 | ||||
-rw-r--r-- | common/gaia_power.c | 20 | ||||
-rw-r--r-- | include/battery_pack.h | 14 |
5 files changed, 107 insertions, 3 deletions
diff --git a/board/spring/board.h b/board/spring/board.h index 5510e0087e..baee52d947 100644 --- a/board/spring/board.h +++ b/board/spring/board.h @@ -34,6 +34,13 @@ /* Go to STANDBY mode when system is off without external power for too long */ #define CONFIG_AUTO_HIBERNATE_SECS 180 +/* Wake from hibernate every hour */ +#define CONFIG_HIBERNATE_WAKE_PERIOD_SECS 3600 + +/* Auto battery cut-off */ +#define BATTERY_CUT_OFF_MV 10500 +#define BATTERY_CUT_OFF_DELAY (11 * SECOND) + /* use STOP mode when we have nothing to do */ #define CONFIG_LOW_POWER_IDLE diff --git a/chip/stm32/system.c b/chip/stm32/system.c index 7e0c0acb0c..e89c024d12 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -7,6 +7,7 @@ #include "console.h" #include "cpu.h" +#include "gpio.h" #include "registers.h" #include "system.h" #include "task.h" @@ -111,6 +112,14 @@ static void check_reset_cause(void) /* Hibernated and subsequently awakened */ flags |= RESET_FLAG_HIBERNATE; + if (pwr_status & 0x00000001) { + flags |= RESET_FLAG_WAKE_PIN; + + if (gpio_get_level(GPIO_BCHGR_VACG) == 0) + /* WKUP=1 but not waken by WKUP pin. Must be RTC. */ + flags |= RESET_FLAG_RTC_ALARM; + } + if (!flags && (raw_cause & 0xfe000000)) flags |= RESET_FLAG_OTHER; diff --git a/common/battery_spring.c b/common/battery_spring.c index 99bf8b771c..34fb2f8aed 100644 --- a/common/battery_spring.c +++ b/common/battery_spring.c @@ -5,15 +5,27 @@ * Smart battery driver for Spring. */ +#include "battery_pack.h" +#include "console.h" #include "host_command.h" #include "i2c.h" +#include "pmu_tpschrome.h" #include "smart_battery.h" +#include "timer.h" #include "util.h" #define PARAM_CUT_OFF_LOW 0x10 #define PARAM_CUT_OFF_HIGH 0x00 -int battery_command_cut_off(struct host_cmd_handler_args *args) +#ifndef BATTERY_CUT_OFF_MV +#define BATTERY_CUT_OFF_MV 0 +#endif + +#ifndef BATTERY_CUT_OFF_DELAY +#define BATTERY_CUT_OFF_DELAY 0 +#endif + +int battery_cut_off(void) { int rv; uint8_t buf[3]; @@ -27,9 +39,53 @@ int battery_command_cut_off(struct host_cmd_handler_args *args) rv = i2c_xfer(I2C_PORT_BATTERY, BATTERY_ADDR, buf, 3, NULL, 0); i2c_unlock(); - if (rv) + return rv; +} + +int battery_check_cut_off(void) +{ + int voltage; + + if (!BATTERY_CUT_OFF_MV) + return 0; + if (battery_voltage(&voltage)) + return 0; + if (voltage > BATTERY_CUT_OFF_MV) + return 0; + if (board_get_ac()) + return 0; + + ccprintf("[%T Cutting off battery]\n"); + cflush(); + battery_cut_off(); + return 1; +} + +int battery_command_cut_off(struct host_cmd_handler_args *args) +{ + if (battery_cut_off()) return EC_RES_ERROR; return EC_RES_SUCCESS; } DECLARE_HOST_COMMAND(EC_CMD_BATTERY_CUT_OFF, battery_command_cut_off, EC_VER_MASK(0)); + +static int command_cutoff(int argc, char **argv) +{ + int tries = 5; + + while (board_get_ac() && tries) { + ccprintf("Remove AC power in %d seconds...\n", tries); + tries--; + usleep(SECOND); + } + + if (board_get_ac()) + return EC_ERROR_UNKNOWN; + + ccprintf("Cutting off. Please wait for 10 seconds.\n"); + + return battery_cut_off(); +} +DECLARE_CONSOLE_COMMAND(cutoff, command_cutoff, NULL, + "Cut off the battery", NULL); diff --git a/common/gaia_power.c b/common/gaia_power.c index a11990add4..878ea7331b 100644 --- a/common/gaia_power.c +++ b/common/gaia_power.c @@ -23,6 +23,7 @@ * - If XPSHOLD is dropped by the AP, then we power the AP off */ +#include "battery_pack.h" #include "clock.h" #include "chipset.h" /* This module implements chipset functions too */ #include "common.h" @@ -87,6 +88,10 @@ /* Default timeout for input transition */ #define FAIL_TIMEOUT (500 * MSEC) /* 500ms */ +#ifndef CONFIG_HIBERNATE_WAKE_PERIOD_SECS +#define CONFIG_HIBERNATE_WAKE_PERIOD_SECS 0 +#endif + /* Application processor power state */ static int ap_on; @@ -150,7 +155,7 @@ static void check_hibernate_timer(void) !board_get_ac()) { CPRINTF("[%T hibernating]\n"); pmu_battery_mode(); - system_hibernate(0, 0); + system_hibernate(CONFIG_HIBERNATE_WAKE_PERIOD_SECS, 0); } } #else @@ -576,6 +581,19 @@ void gaia_power_task(void) gaia_power_init(); ap_on = 0; + /* + * If we are waken by RTC, check if we want to cut off the battery + * instead of booting the AP + */ + if (system_get_reset_flags() & RESET_FLAG_RTC_ALARM) { + int rv; + auto_power_on = 0; + ccprintf("[%T Wake from RTC. Check battery.]\n"); + rv = battery_check_cut_off(); + ccprintf("[%T Want cut off = %d]\n", rv); + system_hibernate(CONFIG_HIBERNATE_WAKE_PERIOD_SECS, 0); + } + while (1) { /* Wait until we need to power on, then power on */ wait_for_power_on(); diff --git a/include/battery_pack.h b/include/battery_pack.h index 10022ddac1..0a43619102 100644 --- a/include/battery_pack.h +++ b/include/battery_pack.h @@ -44,4 +44,18 @@ const struct battery_info *battery_get_info(void); */ void battery_vendor_params(struct batt_params *batt); +/** + * Cut off the battery. + * This must be called without external power. After the battery is + * cut off, the user need to plug in a charger to revive it. + */ +int battery_cut_off(void); + +/** + * Check battery status and cut off the battery if needed. + * + * @return 1 if cutting off the battery. Otherwise, 0. + */ +int battery_check_cut_off(void); + #endif |