summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2016-08-12 16:31:01 +0200
committerchrome-bot <chrome-bot@chromium.org>2016-08-22 05:03:26 -0700
commit1b9096116c9a82d9ab0beb5d5d983f9f12a14274 (patch)
tree5911164e510afd2a7ee87f086a26ddab8df4d89e
parentecd98091c1d2571c0e95f6d3965882fa403d7101 (diff)
downloadchrome-ec-1b9096116c9a82d9ab0beb5d5d983f9f12a14274.tar.gz
pd: support Rp/Rp debug accessories
Support Rp/Rp debug accessories in the USB PD state machine including detecting the polarity and the available type-C current. Signed-off-by: Vincent Palatin <vpalatin@chromium.org> BRANCH=none BUG=chrome-os-partner:52592 TEST=manual, plug a Suzy-Q reworked with Rp3A0/Rp1A5 resistors on a Kevin, and see the PD state machine is going to PD_STATE_SNK_ACCESSORY (and leaving it on unplug). Re-verify a few existing accessories (Rd/Rd SuzyQ, legacy RpUSB cable, Rp3A0 power supply). Change-Id: Icef6c90027105d7c633f2785210ab9dae74fc33c Reviewed-on: https://chromium-review.googlesource.com/368700 Commit-Ready: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Mary Ruthven <mruthven@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--common/usb_pd_protocol.c134
-rw-r--r--include/usb_pd.h1
2 files changed, 105 insertions, 30 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 7682030291..ca2588517f 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -173,7 +173,7 @@ static const char * const pd_state_names[] = {
"DISABLED", "SUSPENDED",
#ifdef CONFIG_USB_PD_DUAL_ROLE
"SNK_DISCONNECTED", "SNK_DISCONNECTED_DEBOUNCE",
- "SNK_HARD_RESET_RECOVER",
+ "SNK_ACCESSORY", "SNK_HARD_RESET_RECOVER",
"SNK_DISCOVERY", "SNK_REQUESTED", "SNK_TRANSITION", "SNK_READY",
"SNK_SWAP_INIT", "SNK_SWAP_SNK_DISABLE",
"SNK_SWAP_SRC_DISABLE", "SNK_SWAP_STANDBY", "SNK_SWAP_COMPLETE",
@@ -261,7 +261,8 @@ static int pd_debug_acc_plugged(int port)
{
#if defined(CONFIG_CASE_CLOSED_DEBUG) || \
defined(CONFIG_CASE_CLOSED_DEBUG_EXTERNAL)
- return pd[port].task_state == PD_STATE_SRC_ACCESSORY;
+ return pd[port].task_state == PD_STATE_SRC_ACCESSORY ||
+ pd[port].task_state == PD_STATE_SNK_ACCESSORY;
#else
/* Debug accessories not supported */
return 0;
@@ -1361,16 +1362,52 @@ void pd_ping_enable(int port, int enable)
pd[port].flags &= ~PD_FLAGS_PING_ENABLED;
}
+/**
+ * Returns whether the sink has detected a Rp resistor on the other side.
+ */
+static inline int cc_is_rp(int cc)
+{
+ return (cc == TYPEC_CC_VOLT_SNK_DEF) || (cc == TYPEC_CC_VOLT_SNK_1_5) ||
+ (cc == TYPEC_CC_VOLT_SNK_3_0);
+}
+
+/*
+ * CC values for regular sources and Debug sources (aka DTS)
+ *
+ * Source type Mode of Operation CC1 CC2
+ * ---------------------------------------------
+ * Regular Default USB Power RpUSB Open
+ * Regular USB-C @ 1.5 A Rp1A5 Open
+ * Regular USB-C @ 3 A Rp3A0 Open
+ * DTS Default USB Power Rp3A0 Rp1A5
+ * DTS USB-C @ 1.5 A Rp1A5 RpUSB
+ * DTS USB-C @ 3 A Rp3A0 RpUSB
+*/
+
+/**
+ * Returns the polarity of a Sink.
+ */
+static inline int get_snk_polarity(int cc1, int cc2)
+{
+ /* the following assumes:
+ * TYPEC_CC_VOLT_SNK_3_0 > TYPEC_CC_VOLT_SNK_1_5
+ * TYPEC_CC_VOLT_SNK_1_5 > TYPEC_CC_VOLT_SNK_DEF
+ * TYPEC_CC_VOLT_SNK_DEF > TYPEC_CC_VOLT_OPEN
+ */
+ return (cc2 > cc1);
+}
+
#ifdef CONFIG_CHARGE_MANAGER
/**
* Returns type C current limit (mA) based upon cc_voltage (mV).
*/
-static inline int get_typec_current_limit(int cc)
+static inline int get_typec_current_limit(int polarity, int cc1, int cc2)
{
int charge;
+ int cc = polarity ? cc2 : cc1;
+ int cc_alt = polarity ? cc1 : cc2;
- /* Detect type C charger current limit based upon vbus voltage. */
- if (cc == TYPEC_CC_VOLT_SNK_3_0)
+ if (cc == TYPEC_CC_VOLT_SNK_3_0 && cc_alt != TYPEC_CC_VOLT_SNK_1_5)
charge = 3000;
else if (cc == TYPEC_CC_VOLT_SNK_1_5)
charge = 1500;
@@ -1673,10 +1710,6 @@ void pd_task(void)
ccd_set_mode(system_is_locked() ?
CCD_MODE_PARTIAL :
CCD_MODE_ENABLED);
- typec_set_input_current_limit(
- port, 3000, TYPE_C_VOLTAGE);
- charge_manager_update_dualrole(
- port, CAP_DEDICATED);
}
#endif
set_state(port, PD_STATE_SRC_ACCESSORY);
@@ -2014,7 +2047,7 @@ void pd_task(void)
cc2 != TYPEC_CC_VOLT_OPEN) {
pd[port].cc_state = PD_CC_NONE;
hard_reset_count = 0;
- new_cc_state = PD_CC_DFP_ATTACHED;
+ new_cc_state = PD_CC_NONE;
pd[port].cc_debounce = get_time().val +
PD_T_CC_DEBOUNCE;
set_state(port,
@@ -2055,8 +2088,13 @@ void pd_task(void)
break;
case PD_STATE_SNK_DISCONNECTED_DEBOUNCE:
tcpm_get_cc(port, &cc1, &cc2);
- if (cc1 == TYPEC_CC_VOLT_OPEN &&
- cc2 == TYPEC_CC_VOLT_OPEN) {
+
+ if (cc_is_rp(cc1) && cc_is_rp(cc2)) {
+ /* Debug accessory */
+ new_cc_state = PD_CC_DEBUG_ACC;
+ } else if (cc_is_rp(cc1) || cc_is_rp(cc2)) {
+ new_cc_state = PD_CC_DFP_ATTACHED;
+ } else {
/* No connection any more */
set_state(port, PD_STATE_SNK_DISCONNECTED);
timeout = 5*MSEC;
@@ -2065,6 +2103,13 @@ void pd_task(void)
timeout = 20*MSEC;
+ /* Debounce the cc state */
+ if (new_cc_state != pd[port].cc_state) {
+ pd[port].cc_debounce = get_time().val +
+ PD_T_CC_DEBOUNCE;
+ pd[port].cc_state = new_cc_state;
+ break;
+ }
/* Wait for CC debounce and VBUS present */
if (get_time().val < pd[port].cc_debounce ||
!pd_is_vbus_present(port))
@@ -2089,15 +2134,15 @@ void pd_task(void)
}
/* We are attached */
- pd[port].polarity = (cc2 != TYPEC_CC_VOLT_OPEN);
+ pd[port].polarity = get_snk_polarity(cc1, cc2);
tcpm_set_polarity(port, pd[port].polarity);
/* reset message ID on connection */
pd[port].msg_id = 0;
/* initial data role for sink is UFP */
pd_set_data_role(port, PD_ROLE_UFP);
#ifdef CONFIG_CHARGE_MANAGER
- typec_curr = get_typec_current_limit(
- pd[port].polarity ? cc2 : cc1);
+ typec_curr = get_typec_current_limit(pd[port].polarity,
+ cc1, cc2);
typec_set_input_current_limit(
port, typec_curr, TYPE_C_VOLTAGE);
#endif
@@ -2105,17 +2150,47 @@ void pd_task(void)
if (pd_comm_enabled)
tcpm_set_rx_enable(port, 1);
- /*
- * fake set data role swapped flag so we send
- * discover identity when we enter SRC_READY
- */
- pd[port].flags |= PD_FLAGS_CHECK_PR_ROLE |
- PD_FLAGS_CHECK_DR_ROLE |
- PD_FLAGS_DATA_SWAPPED;
- set_state(port, PD_STATE_SNK_DISCOVERY);
- timeout = 10*MSEC;
- hook_call_deferred(&pd_usb_billboard_deferred_data,
- PD_T_AME);
+ /* DFP is attached */
+ if (new_cc_state == PD_CC_DFP_ATTACHED) {
+ /*
+ * fake set data role swapped flag so we send
+ * discover identity when we enter SRC_READY
+ */
+ pd[port].flags |= PD_FLAGS_CHECK_PR_ROLE |
+ PD_FLAGS_CHECK_DR_ROLE |
+ PD_FLAGS_DATA_SWAPPED;
+ set_state(port, PD_STATE_SNK_DISCOVERY);
+ timeout = 10*MSEC;
+ hook_call_deferred(
+ &pd_usb_billboard_deferred_data,
+ PD_T_AME);
+ }
+#if defined(CONFIG_CASE_CLOSED_DEBUG) || \
+defined(CONFIG_CASE_CLOSED_DEBUG_EXTERNAL)
+ else if (new_cc_state == PD_CC_DEBUG_ACC) {
+#ifdef CONFIG_CASE_CLOSED_DEBUG
+ ccd_set_mode(system_is_locked() ?
+ CCD_MODE_PARTIAL :
+ CCD_MODE_ENABLED);
+#endif
+ set_state(port, PD_STATE_SNK_ACCESSORY);
+ }
+ break;
+ case PD_STATE_SNK_ACCESSORY:
+ /* debug accessory state */
+ timeout = 100*MSEC;
+
+ tcpm_get_cc(port, &cc1, &cc2);
+
+ /* If accessory becomes detached */
+ if (!cc_is_rp(cc1) || !cc_is_rp(cc2)) {
+ set_state(port, PD_STATE_SNK_DISCONNECTED);
+#ifdef CONFIG_CASE_CLOSED_DEBUG
+ ccd_set_mode(CCD_MODE_DISABLED);
+#endif
+ timeout = 10*MSEC;
+ }
+#endif
break;
case PD_STATE_SNK_HARD_RESET_RECOVER:
if (pd[port].last_state != pd[port].task_state)
@@ -2227,14 +2302,13 @@ void pd_task(void)
/* Check if CC pull-up has changed */
tcpm_get_cc(port, &cc1, &cc2);
- if (pd[port].polarity)
- cc1 = cc2;
- if (typec_curr != get_typec_current_limit(cc1)) {
+ if (typec_curr != get_typec_current_limit(
+ pd[port].polarity, cc1, cc2)) {
/* debounce signal by requiring two reads */
if (typec_curr_change) {
/* set new input current limit */
typec_curr = get_typec_current_limit(
- cc1);
+ pd[port].polarity, cc1, cc2);
typec_set_input_current_limit(
port, typec_curr, TYPE_C_VOLTAGE);
} else {
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 7d125051fa..00b149475b 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -634,6 +634,7 @@ enum pd_states {
#ifdef CONFIG_USB_PD_DUAL_ROLE
PD_STATE_SNK_DISCONNECTED,
PD_STATE_SNK_DISCONNECTED_DEBOUNCE,
+ PD_STATE_SNK_ACCESSORY,
PD_STATE_SNK_HARD_RESET_RECOVER,
PD_STATE_SNK_DISCOVERY,
PD_STATE_SNK_REQUESTED,