summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-08-22 10:18:58 -0700
committerChromeBot <chrome-bot@google.com>2013-08-23 10:54:53 -0700
commitcf5812c2539f40a9a5f9402711b8bae5adc453cf (patch)
tree76c6d7199900a8cae3b74106759d1da49e1e1ca5
parentcd46f51bc83784b81169adcf14ed5a9ad0b0ea7e (diff)
downloadchrome-ec-cf5812c2539f40a9a5f9402711b8bae5adc453cf.tar.gz
Falco: throttle if battery current drain is too high
I missed this requirement the first time. Now it's here. Also adding a test for it as well. BUG=chrome-os-partner:20739 BRANCH=falco TEST=manual make BOARD=falco runtests Original-Change-Id: I88aac8d12d09f7970b04c4aa02b6986b5ea16306 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/66684 Reviewed-by: Aaron Durbin <adurbin@chromium.org> (cherry picked from commit 8c7a18616f216fe4c6df2d7fc2b3fc6319c385fd) Change-Id: I868ff17b722d27eb6e86ef9f2fce1ce295ac7760 Reviewed-on: https://gerrit.chromium.org/gerrit/66832 Commit-Queue: Bill Richardson <wfrichar@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Tested-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--common/extpower_falco.c37
-rw-r--r--include/extpower_falco.h1
-rw-r--r--test/adapter.c139
-rw-r--r--test/adapter_externs.h2
4 files changed, 179 insertions, 0 deletions
diff --git a/common/extpower_falco.c b/common/extpower_falco.c
index 51f0f1c28d..1769196c12 100644
--- a/common/extpower_falco.c
+++ b/common/extpower_falco.c
@@ -120,6 +120,15 @@ struct adapter_limits ad_limits[][NUM_AC_TURBO_STATES][NUM_AC_THRESHOLDS] = {
};
BUILD_ASSERT(ARRAY_SIZE(ad_limits) == NUM_ADAPTER_TYPES);
+/* The battery current limits are independent of Turbo or adapter rating.
+ * hi_val and lo_val are DISCHARGE current in mA.
+ */
+test_export_static
+struct adapter_limits batt_limits[] = {
+ { 7500, 7000, 16, 50, },
+ { 8000, 7500, 1, 50, },
+};
+BUILD_ASSERT(ARRAY_SIZE(batt_limits) == NUM_BATT_THRESHOLDS);
static int last_mv;
static enum adapter_type identify_adapter(void)
@@ -221,10 +230,38 @@ void check_threshold(int current, struct adapter_limits *lim)
}
}
+
+test_export_static
+void watch_battery_closely(struct power_state_context *ctx)
+{
+ int i;
+ int current = ctx->curr.batt.current;
+
+ /* NB: The values in batt_limits[] indicate DISCHARGE current (mA).
+ * However, the value returned from battery_current() is CHARGE
+ * current: postive for charging and negative for discharging.
+ *
+ * Turbo mode can discharge the battery even while connected to the
+ * charger. The spec says not to turn throttling off until the battery
+ * drain has been below the threshold for 5 seconds. That means we
+ * still need to check while on AC, or else just plugging the adapter
+ * in and out would mess up that 5-second timeout. Since the threshold
+ * logic uses signed numbers to compare the limits, everything Just
+ * Works.
+ */
+
+ /* Check limits against DISCHARGE current, not CHARGE current! */
+ for (i = 0; i < NUM_BATT_THRESHOLDS; i++)
+ check_threshold(-current, &batt_limits[i]); /* invert sign! */
+}
+
void watch_adapter_closely(struct power_state_context *ctx)
{
int current, i;
+ /* We always watch the battery current drain, even when on AC. */
+ watch_battery_closely(ctx);
+
/* We can only talk to the charger if we're on AC. If there are no
* errors and we recognize the adapter, enable Turbo at 15% charge,
* disable it at 10% to provide hysteresis. */
diff --git a/include/extpower_falco.h b/include/extpower_falco.h
index 6731b9f0c6..74d51f5acd 100644
--- a/include/extpower_falco.h
+++ b/include/extpower_falco.h
@@ -38,6 +38,7 @@ struct adapter_limits {
/* Number of special states */
#define NUM_AC_TURBO_STATES 2
#define NUM_AC_THRESHOLDS 2
+#define NUM_BATT_THRESHOLDS 2
/* Change turbo mode or throttle the AP depending on the adapter state. */
void watch_adapter_closely(struct power_state_context *ctx);
diff --git a/test/adapter.c b/test/adapter.c
index 4a2af66404..de927343b6 100644
--- a/test/adapter.c
+++ b/test/adapter.c
@@ -74,6 +74,11 @@ int charger_set_option(int option)
return EC_SUCCESS;
}
+void chipset_throttle_cpu(int throttle)
+{
+ /* PROCHOT, ugh. */
+}
+
/* Local functions to control the mocked functions. */
static void change_ac(int val)
@@ -88,6 +93,11 @@ static void set_id(int val)
mock_id = val;
}
+/* Specify as discharge current */
+static void mock_batt(int cur)
+{
+ ctx.curr.batt.current = -cur;
+}
/* And the tests themselves... */
@@ -284,6 +294,134 @@ static int test_thresholds(void)
return EC_SUCCESS;
}
+static int test_batt(void)
+{
+ struct adapter_limits *l, *h;
+ int longtime;
+ int i;
+
+ /* NB: struct adapter_limits assumes hi_val > lo_val, so the values in
+ * batt_limits[] indicate discharge current (mA). However, the value
+ * returned from battery_current() is postive for charging, and
+ * negative for discharging.
+ */
+
+ /* We're assuming two limits, mild and urgent. */
+ TEST_ASSERT(NUM_BATT_THRESHOLDS == 2);
+ /* Find out which is which */
+ if (batt_limits[0].hi_val > batt_limits[1].hi_val) {
+ h = &batt_limits[0];
+ l = &batt_limits[1];
+ } else {
+ h = &batt_limits[1];
+ l = &batt_limits[0];
+ }
+
+ /* Find a time longer than all sample count limits */
+ for (i = longtime = 0; i < NUM_BATT_THRESHOLDS; i++)
+ longtime = MAX(longtime,
+ MAX(batt_limits[i].lo_cnt,
+ batt_limits[i].hi_cnt));
+ longtime += 2;
+
+ test_reset_mocks();
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* reset, by staying low for a long time */
+ for (i = 1; i < longtime; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 0);
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* mock_batt() specifies the DISCHARGE current. Charging
+ * should do nothing, no matter how high. */
+ mock_batt(-(h->hi_val + 2));
+ for (i = 1; i < longtime; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 0);
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* midrange for a long time shouldn't do anything */
+ mock_batt((l->lo_val + l->hi_val) / 2);
+ for (i = 1; i < longtime; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 0);
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* above high limit for not quite long enough */
+ mock_batt(l->hi_val + 1);
+ for (i = 1; i < l->hi_cnt; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->count != 0);
+ TEST_ASSERT(l->triggered == 0);
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* drop below the high limit once */
+ mock_batt(l->hi_val - 1);
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->count == 0);
+ TEST_ASSERT(l->triggered == 0);
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* now back up */
+ mock_batt(l->hi_val + 1);
+ for (i = 1; i < l->hi_cnt; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->count != 0);
+ TEST_ASSERT(l->triggered == 0);
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* one more ought to do it */
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 1);
+ TEST_ASSERT(ap_is_throttled == 1);
+
+ /* going midrange for a long time shouldn't change anything */
+ mock_batt((l->lo_val + l->hi_val) / 2);
+ for (i = 1; i < longtime; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 1);
+ TEST_ASSERT(ap_is_throttled == 1);
+
+ /* charge for not quite long enough */
+ mock_batt(-1);
+ for (i = 1; i < l->lo_cnt; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 1);
+ TEST_ASSERT(ap_is_throttled == 1);
+
+ /* back above the low limit once */
+ mock_batt(l->lo_val + 1);
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 1);
+ TEST_ASSERT(ap_is_throttled == 1);
+
+ /* now charge again - that should have reset the count */
+ mock_batt(-1);
+ for (i = 1; i < l->lo_cnt; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 1);
+ TEST_ASSERT(ap_is_throttled == 1);
+
+ /* One more ought to do it */
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(l->triggered == 0);
+ TEST_ASSERT(ap_is_throttled == 0);
+
+ /* Check the high limits too, just for fun */
+ mock_batt(h->hi_val + 1);
+ for (i = 1; i < h->hi_cnt; i++)
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(h->triggered == 0);
+ /* one more */
+ watch_battery_closely(&ctx);
+ TEST_ASSERT(h->triggered == 1);
+ TEST_ASSERT(ap_is_throttled == 1);
+
+ return EC_SUCCESS;
+}
+
+
void run_test(void)
{
test_reset();
@@ -291,6 +429,7 @@ void run_test(void)
RUN_TEST(test_identification);
RUN_TEST(test_turbo);
RUN_TEST(test_thresholds);
+ RUN_TEST(test_batt);
test_print_result();
}
diff --git a/test/adapter_externs.h b/test/adapter_externs.h
index 6e9d5fd1d3..9cb7c562b3 100644
--- a/test/adapter_externs.h
+++ b/test/adapter_externs.h
@@ -15,5 +15,7 @@ extern struct adapter_limits
extern int ac_turbo;
extern int ap_is_throttled;
extern void check_threshold(int current, struct adapter_limits *lim);
+extern struct adapter_limits batt_limits[NUM_BATT_THRESHOLDS];
+extern void watch_battery_closely(struct power_state_context *ctx);
#endif /* __ADAPTER_EXTERNS_H */