diff options
author | Shawn Nematbakhsh <shawnn@chromium.org> | 2014-11-05 14:38:38 -0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-11-13 03:14:21 +0000 |
commit | 4340685cf9ab9335256d63a8a551faa85af4f892 (patch) | |
tree | f5594acdc2359c52bd3d039d0e3cc879ad0b093f | |
parent | cf48a3640c271663fc1c4156b16f4a25264944d9 (diff) | |
download | chrome-ec-4340685cf9ab9335256d63a8a551faa85af4f892.tar.gz |
charge_manager: Add charge port override functionality
Allow a charge port to be selected as the override port, which means it
will always be selected as the charge port, if any charge supplier is
available.
BUG=chrome-os-partner:32003
TEST=Attach PD charger and BC1.2 charger. Verify that active charge port
switches to BC1.2 after running `chargeoverride [port]` from console.
Also, pass unit tests.
BRANCH=Samus
Change-Id: Ia1b48ca89641842d51be7eed3b92d36d3eedc9ef
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/227730
Reviewed-by: Alec Berg <alecaberg@chromium.org>
-rw-r--r-- | common/charge_manager.c | 98 | ||||
-rw-r--r-- | include/charge_manager.h | 10 | ||||
-rw-r--r-- | test/charge_manager.c | 85 |
3 files changed, 172 insertions, 21 deletions
diff --git a/common/charge_manager.c b/common/charge_manager.c index 6926da4121..6b66d88a81 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -27,6 +27,7 @@ static int charge_ceil[PD_PORT_COUNT]; static int charge_port = CHARGE_PORT_NONE; static int charge_current = CHARGE_CURRENT_UNINITIALIZED; static int charge_supplier = CHARGE_SUPPLIER_NONE; +static int override_port = OVERRIDE_OFF; /** * Initialize available charge. Run before board init, so board init can @@ -83,29 +84,45 @@ static void charge_manager_refresh(void) int new_port = CHARGE_PORT_NONE; int new_charge_current, new_charge_voltage, i, j, old_port; - /* - * Charge supplier selection logic: - * 1. Prefer higher priority supply. - * 2. Prefer higher power over lower in case priority is tied. - * available_charge can be changed at any time by other tasks, - * so make no assumptions about its consistency. - */ - for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) - for (j = 0; j < PD_PORT_COUNT; ++j) - if (available_charge[i][j].current > 0 && - available_charge[i][j].voltage > 0 && - (new_supplier == CHARGE_SUPPLIER_NONE || - supplier_priority[i] < - supplier_priority[new_supplier] || - (supplier_priority[i] == - supplier_priority[new_supplier] && - POWER(available_charge[i][j]) > - POWER(available_charge[new_supplier] - [new_port])))) { - new_supplier = i; - new_port = j; + /* Skip port selection on OVERRIDE_DONT_CHARGE. */ + if (override_port != OVERRIDE_DONT_CHARGE) { + /* + * Charge supplier selection logic: + * 1. Prefer higher priority supply. + * 2. Prefer higher power over lower in case priority is tied. + * available_charge can be changed at any time by other tasks, + * so make no assumptions about its consistency. + */ + for (i = 0; i < CHARGE_SUPPLIER_COUNT; ++i) + for (j = 0; j < PD_PORT_COUNT; ++j) { + if (override_port != OVERRIDE_OFF && + override_port == new_port && + override_port != j) + continue; + + if (available_charge[i][j].current > 0 && + available_charge[i][j].voltage > 0 && + (new_supplier == CHARGE_SUPPLIER_NONE || + supplier_priority[i] < + supplier_priority[new_supplier] || + (j == override_port && + new_port != override_port) || + (supplier_priority[i] == + supplier_priority[new_supplier] && + POWER(available_charge[i][j]) > + POWER(available_charge[new_supplier] + [new_port])))) { + new_supplier = i; + new_port = j; + } } + /* Clear override if no charge is available on override port */ + if (override_port != OVERRIDE_OFF && + override_port != new_port) + override_port = OVERRIDE_OFF; + } + if (new_supplier == CHARGE_SUPPLIER_NONE) new_charge_current = new_charge_voltage = 0; else { @@ -189,6 +206,25 @@ void charge_manager_set_ceil(int port, int ceil) } } +/** + * Select an 'override port', a port which is always the preferred charge port. + * + * @param port Charge port to select as override, or + * OVERRIDE_OFF to select no override port, + * or OVERRIDE_DONT_CHARGE to specifc that no + * charge port should be selected. + */ +void charge_manager_set_override(int port) +{ + ASSERT(port >= OVERRIDE_DONT_CHARGE && port < PD_PORT_COUNT); + + if (override_port != port) { + override_port = port; + if (charge_manager_is_seeded()) + hook_call_deferred(charge_manager_refresh, 0); + } +} + int charge_manager_get_active_charge_port(void) { return charge_port; @@ -291,3 +327,23 @@ DECLARE_HOST_COMMAND(EC_CMD_USB_PD_POWER_INFO, hc_pd_power_info, EC_VER_MASK(0)); #endif /* TEST_CHARGE_MANAGER */ + +static int command_charge_override(int argc, char **argv) +{ + int port = OVERRIDE_OFF; + char *e; + + if (argc >= 2) { + port = strtoi(argv[1], &e, 0); + if (*e || port < OVERRIDE_DONT_CHARGE || port >= PD_PORT_COUNT) + return EC_ERROR_PARAM1; + } + + charge_manager_set_override(port); + ccprintf("Set override: %d\n", port); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(chargeoverride, command_charge_override, + "[port | -1 | -2]", + "Force charging from a given port (-1 = off, -2 = disable charging)", + NULL); diff --git a/include/charge_manager.h b/include/charge_manager.h index d32436ab81..d1b16cb7f3 100644 --- a/include/charge_manager.h +++ b/include/charge_manager.h @@ -15,6 +15,13 @@ #define CHARGE_CURRENT_UNINITIALIZED -1 #define CHARGE_VOLTAGE_UNINITIALIZED -1 +/* Port override settings */ +enum { + OVERRIDE_DONT_CHARGE = -2, + OVERRIDE_OFF = -1, + /* [0, PD_PORT_COUNT): Port# */ +}; + #define POWER(charge_port) ((charge_port.current) * (charge_port.voltage)) /* Charge tasks report available current and voltage */ @@ -31,6 +38,9 @@ void charge_manager_update(int supplier, /* Update charge ceiling for a given port */ void charge_manager_set_ceil(int port, int ceil); +/* Select an 'override port', which is always the preferred charge port */ +void charge_manager_set_override(int port); + /* Returns the current active charge port, as determined by charge manager */ int charge_manager_get_active_charge_port(void); diff --git a/test/charge_manager.c b/test/charge_manager.c index b721d79e52..66e48fc472 100644 --- a/test/charge_manager.c +++ b/test/charge_manager.c @@ -64,6 +64,7 @@ static void initialize_charge_table(int current, int voltage, int ceil) int i, j; struct charge_port_info charge; + charge_manager_set_override(OVERRIDE_OFF); charge.current = current; charge.voltage = voltage; @@ -253,6 +254,89 @@ static int test_new_power_request(void) return EC_SUCCESS; } +static int test_override(void) +{ + struct charge_port_info charge; + + /* Initialize table to no charge */ + initialize_charge_table(0, 5000, 1000); + + /* + * Set a low-priority supplier on p0 and high-priority on p1, then + * verify that p1 is selected. + */ + charge.current = 500; + charge.voltage = 5000; + charge_manager_update(CHARGE_SUPPLIER_TEST2, 0, &charge); + charge_manager_update(CHARGE_SUPPLIER_TEST1, 1, &charge); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 1); + TEST_ASSERT(active_charge_limit == 500); + + /* Set override to p0 and verify p0 is selected */ + charge_manager_set_override(0); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 0); + + /* Remove override and verify p1 is again selected */ + charge_manager_set_override(OVERRIDE_OFF); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 1); + + /* + * Set override again to p0, but set p0 charge to 0, and verify p1 + * is again selected. + */ + charge.current = 0; + charge_manager_update(CHARGE_SUPPLIER_TEST2, 0, &charge); + charge_manager_set_override(0); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 1); + + /* Set non-zero charge on port 0 and verify override was auto-removed */ + charge.current = 250; + charge_manager_update(CHARGE_SUPPLIER_TEST5, 0, &charge); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 1); + + /* + * Verify current limit is still selected according to supplier + * priority on the override port. + */ + charge_manager_set_override(0); + charge.current = 300; + charge_manager_update(CHARGE_SUPPLIER_TEST2, 0, &charge); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 0); + TEST_ASSERT(active_charge_limit == 300); + charge.current = 100; + charge_manager_update(CHARGE_SUPPLIER_TEST1, 0, &charge); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 0); + TEST_ASSERT(active_charge_limit == 100); + + /* Set override to "don't charge", then verify we're not charging */ + charge_manager_set_override(OVERRIDE_DONT_CHARGE); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == CHARGE_PORT_NONE); + TEST_ASSERT(active_charge_limit == 0); + + /* Update a charge supplier, verify that we still aren't charging */ + charge.current = 200; + charge_manager_update(CHARGE_SUPPLIER_TEST1, 0, &charge); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == CHARGE_PORT_NONE); + TEST_ASSERT(active_charge_limit == 0); + + /* Turn override off, verify that we go back to the correct charge */ + charge_manager_set_override(OVERRIDE_OFF); + wait_for_charge_manager_refresh(); + TEST_ASSERT(active_charge_port == 1); + TEST_ASSERT(active_charge_limit == 500); + + return EC_SUCCESS; +} + void run_test(void) { test_reset(); @@ -261,6 +345,7 @@ void run_test(void) RUN_TEST(test_priority); RUN_TEST(test_charge_ceil); RUN_TEST(test_new_power_request); + RUN_TEST(test_override); test_print_result(); } |