mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 17:41:54 +00:00
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>
This commit is contained in:
committed by
chrome-internal-fetch
parent
cf48a3640c
commit
4340685cf9
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user