summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/spring/board.h7
-rw-r--r--chip/stm32/system.c9
-rw-r--r--common/battery_spring.c60
-rw-r--r--common/gaia_power.c20
-rw-r--r--include/battery_pack.h14
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