From 83ef084f95e2dd83bf5f43472fb6f9ebeb57583f Mon Sep 17 00:00:00 2001 From: Alec Berg Date: Mon, 19 Jan 2015 10:22:55 -0800 Subject: [PATCH] pd: fix PD power swap when lots of protocol erros Fix a couple bugs that cause problems when executing a power swap with a poor PD connection. 1) If we are a sink switching to a source and we have turned on vbus and then get an error, then make sure to turn off vbus. 2) If we are a sink switching to a source and we receive a redundant PD_RDY, then ignore it. BUG=chrome-os-partner:32392 BRANCH=samus TEST=load on samus and connect port 0 to 1 creating a poor PD connection with a lot of retries and missed responses. with this change, I swapped power ~20 times with "pd 0 swap power" and each time it was eventually successful. Change-Id: Ib6b97961c7e40186a14ca1d2922b2ce6a6598180 Signed-off-by: Alec Berg Reviewed-on: https://chromium-review.googlesource.com/241872 Reviewed-by: Vincent Palatin --- common/usb_pd_protocol.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index a04dada1aa..8b03f38798 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -818,11 +818,13 @@ static void execute_hard_reset(int port) #ifdef CONFIG_USB_PD_DUAL_ROLE /* * If we are swapping to a source and have changed to Rp, restore back - * to Rd to match our power_role. + * to Rd and turn off vbus to match our power_role. */ if (pd[port].task_state == PD_STATE_SNK_SWAP_STANDBY || - pd[port].task_state == PD_STATE_SNK_SWAP_COMPLETE) + pd[port].task_state == PD_STATE_SNK_SWAP_COMPLETE) { pd_set_host_mode(port, 0); + pd_power_supply_reset(port); + } /* * If we are swapping to a sink and have changed to Rd, change role to * sink to match the CC pull resistor. @@ -1113,6 +1115,8 @@ static void handle_ctrl_request(int port, uint16_t head, } else if (pd[port].task_state == PD_STATE_SNK_DISCOVERY) { /* Don't know what power source is ready. Reset. */ set_state(port, PD_STATE_HARD_RESET_SEND); + } else if (pd[port].task_state == PD_STATE_SNK_SWAP_STANDBY) { + /* Do nothing, assume this is a redundant PD_RDY */ } else if (pd[port].power_role == PD_ROLE_SINK) { set_state(port, PD_STATE_SNK_READY); #ifdef CONFIG_CHARGE_MANAGER @@ -2611,6 +2615,7 @@ void pd_task(void) if (res < 0) { /* Restore Rd */ pd_set_host_mode(port, 0); + pd_power_supply_reset(port); timeout = 10 * MSEC; set_state(port, PD_STATE_SNK_DISCONNECTED); break;