mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
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 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>
This commit is contained in:
committed by
ChromeBot
parent
fcce7223a5
commit
8c7a18616f
@@ -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)
|
||||
@@ -220,10 +229,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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
139
test/adapter.c
139
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();
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user