diff options
author | Bill Richardson <wfrichar@chromium.org> | 2013-08-22 10:18:58 -0700 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-08-23 10:54:53 -0700 |
commit | cf5812c2539f40a9a5f9402711b8bae5adc453cf (patch) | |
tree | 76c6d7199900a8cae3b74106759d1da49e1e1ca5 | |
parent | cd46f51bc83784b81169adcf14ed5a9ad0b0ea7e (diff) | |
download | chrome-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.c | 37 | ||||
-rw-r--r-- | include/extpower_falco.h | 1 | ||||
-rw-r--r-- | test/adapter.c | 139 | ||||
-rw-r--r-- | test/adapter_externs.h | 2 |
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 */ |