diff options
author | Alec Berg <alecaberg@chromium.org> | 2014-07-16 10:50:07 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-07-28 17:12:20 +0000 |
commit | 1faa6ee20273cba9e898e192fc71d0d8ea704b3b (patch) | |
tree | 01e846a643270e0063e14dfb499295e956a1edd0 | |
parent | 3060d32ff96869e978a33b5abe822c57b83825c7 (diff) | |
download | chrome-ec-1faa6ee20273cba9e898e192fc71d0d8ea704b3b.tar.gz |
samus: include a force source mode for dual-role ports
Include a force source mode for dual-role ports to allow us to
force a dual-role port into being a source.
BUG=chrome-os-partner:28782
BRANCH=none
TEST=tested on plankton, verified using the pd 0 dualrole console
command.
Change-Id: Ic4c2a9e11984b34b1dec09d5c71e1fd15ed9198c
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/209071
Reviewed-by: Vic Yang <victoryang@chromium.org>
-rw-r--r-- | common/usb_pd_protocol.c | 78 | ||||
-rw-r--r-- | include/usb_pd.h | 9 |
2 files changed, 60 insertions, 27 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 3cf76a0973..25da8e78a5 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -214,6 +214,11 @@ enum pd_states { PD_STATE_BIST, }; +#ifdef CONFIG_USB_PD_DUAL_ROLE +/* Port dual-role state */ +enum pd_dual_role_states drp_state = PD_DRP_TOGGLE_OFF; +#endif + static struct pd_protocol { /* current port role */ uint8_t role; @@ -221,10 +226,6 @@ static struct pd_protocol { uint8_t msg_id; /* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */ uint8_t polarity; -#ifdef CONFIG_USB_PD_DUAL_ROLE - /* Port dual role toggling flag */ - uint8_t dual_role_toggle; -#endif /* PD state for port */ enum pd_states task_state; } pd[PD_PORT_COUNT]; @@ -813,22 +814,38 @@ static void execute_hard_reset(int port) } #ifdef CONFIG_USB_PD_DUAL_ROLE -void pd_set_dual_role(enum pd_dual_role_states dr_state) +void pd_set_dual_role(enum pd_dual_role_states state) { int i; + drp_state = state; for (i = 0; i < PD_PORT_COUNT; i++) { - pd[i].dual_role_toggle = (dr_state == PD_DRP_TOGGLE_ON); - - /* Change to sink if in src disconnected state or force sink */ + /* + * Change to sink if port is currently a source AND (new DRP + * state is force sink OR new DRP state is toggle off and we + * are in the source disconnected state). + */ if (pd[i].role == PD_ROLE_SOURCE && - (pd[i].task_state == PD_STATE_SRC_DISCONNECTED || - dr_state == PD_DRP_FORCE_SINK)) { + (drp_state == PD_DRP_FORCE_SINK || + (drp_state == PD_DRP_TOGGLE_OFF + && pd[i].task_state == PD_STATE_SRC_DISCONNECTED))) { pd[i].role = PD_ROLE_SINK; pd[i].task_state = PD_STATE_SNK_DISCONNECTED; pd_set_host_mode(i, 0); task_wake(PORT_TO_TASK_ID(i)); } + + /* + * Change to source if port is currently a sink and the + * new DRP state is force source. + */ + if (pd[i].role == PD_ROLE_SINK && + drp_state == PD_DRP_FORCE_SOURCE) { + pd[i].role = PD_ROLE_SOURCE; + pd[i].task_state = PD_STATE_SRC_DISCONNECTED; + pd_set_host_mode(i, 1); + task_wake(PORT_TO_TASK_ID(i)); + } } } #endif @@ -929,8 +946,9 @@ void pd_task(void) } #ifdef CONFIG_USB_PD_DUAL_ROLE /* Swap roles if time expired or VBUS is present */ - else if ((get_time().val >= next_role_swap || - pd_snk_is_vbus_provided(port))) { + else if (drp_state != PD_DRP_FORCE_SOURCE && + (get_time().val >= next_role_swap || + pd_snk_is_vbus_provided(port))) { pd[port].role = PD_ROLE_SINK; pd[port].task_state = PD_STATE_SNK_DISCONNECTED; pd_set_host_mode(port, 0); @@ -1015,7 +1033,7 @@ void pd_task(void) pd[port].task_state = PD_STATE_SNK_DISCOVERY; } - } else if (pd[port].dual_role_toggle && + } else if (drp_state == PD_DRP_TOGGLE_ON && get_time().val >= next_role_swap) { /* Swap roles to source */ pd[port].role = PD_ROLE_SOURCE; @@ -1182,19 +1200,33 @@ static int command_pd(int argc, char **argv) pd[port].task_state = PD_STATE_SRC_READY; task_wake(PORT_TO_TASK_ID(port)); } else if (!strcasecmp(argv[2], "dualrole")) { - int on; - char *e; - if (argc < 4) { - ccprintf("dual-role toggling: %d\n", - pd[port].dual_role_toggle); + ccprintf("dual-role toggling: "); + switch (drp_state) { + case PD_DRP_TOGGLE_ON: + ccprintf("on\n"); + break; + case PD_DRP_TOGGLE_OFF: + ccprintf("off\n"); + break; + case PD_DRP_FORCE_SINK: + ccprintf("force sink\n"); + break; + case PD_DRP_FORCE_SOURCE: + ccprintf("force source\n"); + break; + } } else { - on = strtoi(argv[3], &e, 10); - if (*e) + if (!strcasecmp(argv[3], "on")) + pd_set_dual_role(PD_DRP_TOGGLE_ON); + else if (!strcasecmp(argv[3], "off")) + pd_set_dual_role(PD_DRP_TOGGLE_OFF); + else if (!strcasecmp(argv[3], "sink")) + pd_set_dual_role(PD_DRP_FORCE_SINK); + else if (!strcasecmp(argv[3], "source")) + pd_set_dual_role(PD_DRP_FORCE_SOURCE); + else return EC_ERROR_PARAM3; - - pd_set_dual_role(on ? PD_DRP_TOGGLE_ON : - PD_DRP_FORCE_SINK); } } else if (!strncasecmp(argv[2], "state", 5)) { const char * const state_names[] = { diff --git a/include/usb_pd.h b/include/usb_pd.h index 2a21dc08f9..cd3971079d 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -138,15 +138,16 @@ enum pd_errors { enum pd_dual_role_states { PD_DRP_TOGGLE_ON, PD_DRP_TOGGLE_OFF, - PD_DRP_FORCE_SINK + PD_DRP_FORCE_SINK, + PD_DRP_FORCE_SOURCE }; /** * Set dual role state, from among enum pd_dual_role_states * - * @param dr_state New state of dual-role port, selected from - * enum pd_dual_role_states + * @param state New state of dual-role port, selected from + * enum pd_dual_role_states */ -void pd_set_dual_role(enum pd_dual_role_states dr_state); +void pd_set_dual_role(enum pd_dual_role_states state); #endif /* --- Policy layer functions --- */ |