diff options
author | Shawn Nematbakhsh <shawnn@chromium.org> | 2014-11-25 11:10:43 -0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-12-09 02:07:03 +0000 |
commit | 6f010b635d48b0f77028e2d6ed11608ae6e8ce82 (patch) | |
tree | cf2894f5dc0eef4c4c16cb81fc3d96f8af5d44ba /common/charge_manager.c | |
parent | c8f98e80fdbe85fc0bc0f892d4b22dad19186aef (diff) | |
download | chrome-ec-6f010b635d48b0f77028e2d6ed11608ae6e8ce82.tar.gz |
charge_manager: Add delayed port override for role swap
If override charge is selected on a port currently acting as a charge
source, but the attached device is also capable of acting as a source,
request a charge role swap and initiate a pending delayed port override.
If the role swap completes successfully and a charge source is found,
the selected port will become the override port. If the role swap fails
or no charge source is found within 2 seconds, the delayed port override
will be lost.
BUG=chrome-os-partner:28343,chrome-os-partner:31195
TEST=Manual on Samus. Connect two Samus units together through charge
ports.
"pd 1 swap power" - put port on test device into source role
"chgoverride 1" - set charge override, verify that role swap takes
effect and charge manager selects PD charge source, 900mA @ 5V
Disconnect charge cable, verify that charge manager goes back to not
charging.
BRANCH=Samus
Change-Id: Iadcc4dc98631661f254245eeff18973df517f652
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/231900
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Diffstat (limited to 'common/charge_manager.c')
-rw-r--r-- | common/charge_manager.c | 95 |
1 files changed, 67 insertions, 28 deletions
diff --git a/common/charge_manager.c b/common/charge_manager.c index d8990e56da..b2ef55a796 100644 --- a/common/charge_manager.c +++ b/common/charge_manager.c @@ -7,12 +7,19 @@ #include "console.h" #include "hooks.h" #include "host_command.h" +#include "timer.h" #include "usb_pd.h" #include "usb_pd_config.h" #include "util.h" #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) +#define POWER(charge_port) ((charge_port.current) * (charge_port.voltage)) + +/* Timeout for delayed override power swap, allow for 500ms extra */ +#define POWER_SWAP_TIMEOUT (PD_T_SRC_RECOVER_MAX + PD_T_SRC_TURN_ON + \ + PD_T_SAFE_0V + 500 * MSEC) + /* Keep track of available charge for each charge port. */ static struct charge_port_info available_charge[CHARGE_SUPPLIER_COUNT] [PD_PORT_COUNT]; @@ -31,6 +38,9 @@ static int charge_voltage; static int charge_supplier = CHARGE_SUPPLIER_NONE; static int override_port = OVERRIDE_OFF; +static int delayed_override_port = OVERRIDE_OFF; +static timestamp_t delayed_override_deadline; + /** * Initialize available charge. Run before board init, so board init can * initialize data, if needed. @@ -215,17 +225,31 @@ void charge_manager_update(int supplier, if (available_charge[supplier][port].current != charge->current || available_charge[supplier][port].voltage != charge->voltage) { /* Remove override when a dedicated charger is plugged */ - if (override_port != OVERRIDE_OFF && - available_charge[supplier][port].current == 0 && + if (available_charge[supplier][port].current == 0 && charge->current > 0 && - !pd_get_partner_dualrole_capable(port)) + !pd_get_partner_dualrole_capable(port)) { override_port = OVERRIDE_OFF; - - + if (delayed_override_port != OVERRIDE_OFF) { + delayed_override_port = OVERRIDE_OFF; + hook_call_deferred( + board_charge_manager_override_timeout, + -1); + } + } available_charge[supplier][port].current = charge->current; available_charge[supplier][port].voltage = charge->voltage; /* + * If we have a charge on our delayed override port within + * the deadline, make it our override port. + */ + if (port == delayed_override_port && + charge->current > 0 && + pd_get_role(delayed_override_port) == PD_ROLE_SINK && + get_time().val < delayed_override_deadline.val) + charge_manager_set_override(port); + + /* * Don't call charge_manager_refresh unless all ports + * suppliers have reported in. We don't want to make changes * to our charge port until we are certain we know what is @@ -255,21 +279,52 @@ void charge_manager_set_ceil(int port, int ceil) /** * Select an 'override port', a port which is always the preferred charge port. + * Returns EC_SUCCESS on success, ec_error_list status on failure. * * @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) +int charge_manager_set_override(int port) { + int retval = EC_SUCCESS; + ASSERT(port >= OVERRIDE_DONT_CHARGE && port < PD_PORT_COUNT); + /* Supersede any pending delayed overrides. */ - if (override_port != port) { - override_port = port; - if (charge_manager_is_seeded()) - hook_call_deferred(charge_manager_refresh, 0); + if (delayed_override_port != OVERRIDE_OFF) { + delayed_override_port = OVERRIDE_OFF; + hook_call_deferred( + board_charge_manager_override_timeout, -1); } + + /* Set the override port if it's a sink. */ + if (port < 0 || pd_get_role(port) == PD_ROLE_SINK) { + if (override_port != port) { + override_port = port; + if (charge_manager_is_seeded()) + hook_call_deferred(charge_manager_refresh, 0); + } + } + /* + * If the attached device is capable of being a sink, request a + * power swap and set the delayed override for swap completion. + */ + else if (pd_get_role(port) != PD_ROLE_SINK && + pd_get_partner_dualrole_capable(port)) { + delayed_override_deadline.val = get_time().val + + POWER_SWAP_TIMEOUT; + delayed_override_port = port; + hook_call_deferred( + board_charge_manager_override_timeout, + POWER_SWAP_TIMEOUT); + pd_request_power_swap(port); + /* Can't charge from requested port -- return error. */ + } else + retval = EC_ERROR_INVAL; + + return retval; } int charge_manager_get_active_charge_port(void) @@ -384,15 +439,7 @@ static int hc_charge_port_override(struct host_cmd_handler_args *args) override_port >= PD_PORT_COUNT) return EC_RES_INVALID_PARAM; - if (override_port >= 0 && pd_get_role(override_port) != PD_ROLE_SINK) - /* - * TODO(crosbug.com/p/31195): Switch dual-role ports - * from source to sink. - */ - return EC_RES_ERROR; - - charge_manager_set_override(override_port); - return EC_RES_SUCCESS; + return charge_manager_set_override(override_port); } DECLARE_HOST_COMMAND(EC_CMD_PD_CHARGE_PORT_OVERRIDE, hc_charge_port_override, @@ -409,16 +456,8 @@ static int command_charge_port_override(int argc, char **argv) return EC_ERROR_PARAM1; } - if (port >= 0 && pd_get_role(override_port) != PD_ROLE_SINK) - /* - * TODO(crosbug.com/p/31195): Switch dual-role ports - * from source to sink. - */ - return EC_ERROR_PARAM1; - - charge_manager_set_override(port); ccprintf("Set override: %d\n", port); - return EC_SUCCESS; + return charge_manager_set_override(port); } DECLARE_CONSOLE_COMMAND(chgoverride, command_charge_port_override, "[port | -1 | -2]", |