link: If discharging and system is off, only poll battery once a minute

This reduces power consumption in S3/S5 because the EC doesn't need to
poll the battery every 500ms.

BUG=chrome-os-partner:9676
BRANCH=link
TEST=manual

As much as can be tested with the current debug information:

- Boot system with AC adapter in.  Charge state machine should go to
  charging state.
- Remove AC adapter.  Charge state -> discharging.
- Shut system down.
- Plug AC adapter in.  Charge state -> init -> charging over the course of
  a few seconds (NOT a minute).
- Remove AC adapter.  Charge state -> discharging.

Really good testing requires a source-level change.  Hack in a line of
debug output above task_wait_event(sleep_next) in
charge_state_machine_task() which prints how long the charge state
machine is sleeping.  It should sleep for ~250ms when charging, ~500ms
when discharging and the system is on, or ~60000ms when discharging
and the system is off.  (I did this when writing this change, but
removed it because it clutters up the debug console output.)

Change-Id: I7d3e291fbc40bfcc67d1fb4982d91f0e6bf2e785
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/33921
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Rong Chang <rongchang@chromium.org>
diff --git a/common/charge_state.c b/common/charge_state.c
index 468eb92..e97f032 100644
--- a/common/charge_state.c
+++ b/common/charge_state.c
@@ -13,12 +13,14 @@
 #include "common.h"
 #include "console.h"
 #include "gpio.h"
+#include "hooks.h"
 #include "host_command.h"
 #include "power_button.h"
 #include "power_led.h"
 #include "printf.h"
 #include "smart_battery.h"
 #include "system.h"
+#include "task.h"
 #include "timer.h"
 #include "util.h"
 #include "x86_power.h"
@@ -699,15 +701,41 @@
 		diff_usec = (int)(ts.val - ctx->curr.ts.val);
 		sleep_next = sleep_usec - diff_usec;
 
-		if (sleep_next < MIN_SLEEP_USEC)
+		if (ctx->curr.state == PWR_STATE_DISCHARGE &&
+		    chipset_in_state(CHIPSET_STATE_ANY_OFF |
+				     CHIPSET_STATE_SUSPEND)) {
+			/*
+			 * Discharging and system is off or suspended, so no
+			 * need to poll frequently.  charge_hook() will wake us
+			 * up if anything important changes.
+			 */
+			sleep_next = POLL_PERIOD_VERY_LONG - diff_usec;
+		} else if (sleep_next < MIN_SLEEP_USEC) {
 			sleep_next = MIN_SLEEP_USEC;
-		if (sleep_next > MAX_SLEEP_USEC)
+		} else if (sleep_next > MAX_SLEEP_USEC) {
 			sleep_next = MAX_SLEEP_USEC;
+		}
 
-		usleep(sleep_next);
+		task_wait_event(sleep_next);
 	}
 }
 
+/**
+ * Charge notification hook.
+ *
+ * This is triggered when the AC state changes or the system boots, so that
+ * we can update our charging state.
+ */
+static int charge_hook(void)
+{
+	/* Wake up the task now */
+	task_wake(TASK_ID_POWERSTATE);
+	return EC_SUCCESS;
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, charge_hook, HOOK_PRIO_DEFAULT);
+DECLARE_HOOK(HOOK_AC_CHANGE, charge_hook, HOOK_PRIO_DEFAULT);
+
+
 static int charge_command_force_idle(struct host_cmd_handler_args *args)
 {
 	const struct ec_params_force_idle *p = args->params;
diff --git a/include/charge_state.h b/include/charge_state.h
index d5c80ff..4810a01 100644
--- a/include/charge_state.h
+++ b/include/charge_state.h
@@ -19,6 +19,7 @@
 #define CHARGER_UPDATE_PERIOD (SECOND * 10)
 
 /* Power state task polling period in usec */
+#define POLL_PERIOD_VERY_LONG   MINUTE
 #define POLL_PERIOD_LONG        (MSEC * 500)
 #define POLL_PERIOD_CHARGE      (MSEC * 250)
 #define POLL_PERIOD_SHORT       (MSEC * 100)