summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_pd_protocol.c44
-rw-r--r--include/usb_pd_tcpm.h8
2 files changed, 42 insertions, 10 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index e245ddbd56..7d9ade5e2c 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -621,6 +621,14 @@ static void pd_update_saved_port_flags(int port, uint8_t flag, uint8_t val)
}
#endif /* defined(CONFIG_USB_PD_DUAL_ROLE) */
+/**
+ * Returns true if the port is currently in the try src state.
+ */
+static inline int is_try_src(int port)
+{
+ return pd[port].flags & PD_FLAGS_TRY_SRC;
+}
+
static inline void set_state(int port, enum pd_states next_state)
{
enum pd_states last_state = pd[port].task_state;
@@ -2929,17 +2937,32 @@ void pd_task(void *u)
*/
if (auto_toggle_supported &&
!(pd[port].flags & PD_FLAGS_TCPC_DRP_TOGGLE) &&
- !(pd[port].flags & PD_FLAGS_TRY_SRC) &&
+ !is_try_src(port) &&
cc_is_open(cc1, cc2)) {
set_state(port, PD_STATE_DRP_AUTO_TOGGLE);
timeout = 2*MSEC;
break;
}
#endif
-
- /* Vnc monitoring */
- if (cc_is_at_least_one_rd(cc1, cc2) ||
- cc_is_audio_acc(cc1, cc2)) {
+ /*
+ * Transition to DEBOUNCE if we detect appropriate
+ * signals
+ *
+ * (from 4.5.2.2.10.2 Exiting from Try.SRC State)
+ * If try_src -and-
+ * have only one Rd (not both) => DEBOUNCE
+ *
+ * (from 4.5.2.2.7.2 Exiting from Unattached.SRC State)
+ * If not try_src -and-
+ * have at least one Rd => DEBOUNCE -or-
+ * have audio access => DEBOUNCE
+ *
+ * try_src should not exit if both pins are Rd
+ */
+ if ((is_try_src(port) && cc_is_only_one_rd(cc1, cc2)) ||
+ (!is_try_src(port) &&
+ (cc_is_at_least_one_rd(cc1, cc2) ||
+ cc_is_audio_acc(cc1, cc2)))) {
#ifdef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
/* Enable VBUS */
if (pd_set_power_supply_ready(port))
@@ -2960,7 +2983,7 @@ void pd_task(void *u)
* (PD_T_TRY_TIMEOUT). Otherwise we should stay
* within Try.SRC (break).
*/
- if (pd[port].flags & PD_FLAGS_TRY_SRC) {
+ if (is_try_src(port)) {
if (now.val < pd[port].try_src_marker) {
break;
} else if (now.val < pd[port].try_timeout) {
@@ -3024,9 +3047,10 @@ void pd_task(void *u)
/* Set debounce timer */
if (new_cc_state != pd[port].cc_state) {
- pd[port].cc_debounce = get_time().val +
- (pd[port].flags & PD_FLAGS_TRY_SRC) ?
- PD_T_DEBOUNCE : PD_T_CC_DEBOUNCE;
+ pd[port].cc_debounce =
+ get_time().val +
+ (is_try_src(port) ? PD_T_DEBOUNCE
+ : PD_T_CC_DEBOUNCE);
pd[port].cc_state = new_cc_state;
break;
}
@@ -3483,7 +3507,7 @@ void pd_task(void *u)
*/
if (auto_toggle_supported &&
!(pd[port].flags & PD_FLAGS_TCPC_DRP_TOGGLE) &&
- !(pd[port].flags & PD_FLAGS_TRY_SRC) &&
+ !is_try_src(port) &&
cc_is_open(cc1, cc2)) {
set_state(port, PD_STATE_DRP_AUTO_TOGGLE);
timeout = 2*MSEC;
diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h
index 0a824cc657..2a9778c3dd 100644
--- a/include/usb_pd_tcpm.h
+++ b/include/usb_pd_tcpm.h
@@ -100,6 +100,14 @@ static inline int cc_is_at_least_one_rd(int cc1, int cc2)
return cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD;
}
+/**
+ * Returns true if the port partner is presenting Rd on only one CC line.
+ */
+static inline int cc_is_only_one_rd(int cc1, int cc2)
+{
+ return cc_is_at_least_one_rd(cc1, cc2) && cc1 != cc2;
+}
+
struct tcpm_drv {
/**
* Initialize TCPM driver and wait for TCPC readiness.