diff options
-rw-r--r-- | common/mock/tcpc_mock.c | 12 | ||||
-rw-r--r-- | common/usbc/usb_tc_drp_acc_trysrc_sm.c | 21 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 13 | ||||
-rw-r--r-- | include/usb_pd.h | 4 | ||||
-rw-r--r-- | include/usb_pd_tcpm.h | 11 |
5 files changed, 51 insertions, 10 deletions
diff --git a/common/mock/tcpc_mock.c b/common/mock/tcpc_mock.c index 64a1ce01cf..457868c96a 100644 --- a/common/mock/tcpc_mock.c +++ b/common/mock/tcpc_mock.c @@ -8,6 +8,7 @@ #include "console.h" #include "memory.h" #include "mock/tcpc_mock.h" +#include "test_util.h" #include "tests/enum_strings.h" #include "timer.h" #include "usb_pd_tcpm.h" @@ -51,8 +52,17 @@ static bool mock_check_vbus_level(int port, enum vbus_level level) { if (level == VBUS_PRESENT) return mock_tcpc.vbus_level; - else + else if (level == VBUS_SAFE0V || level == VBUS_REMOVED) return !mock_tcpc.vbus_level; + + /* + * Unknown vbus_level was added, force a failure. + * Note that TCPC drivers and pd_check_vbus_level() implementations + * should be carefully checked on new level additions in case they + * need updated. + */ + ccprints("[TCPC] Unhandled Vbus check %d", level); + TEST_ASSERT(0); } static int mock_select_rp_value(int port, int rp) diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c index 2a5ac25944..45d28687a0 100644 --- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c +++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c @@ -2271,6 +2271,19 @@ static void tc_attached_snk_run(const int port) } /* + * From 4.5.2.2.5.2 Exiting from Attached.SNK State: + * + * "A port that is not a Vconn-Powered USB Device and is not in the + * process of a USB PD PR_Swap or a USB PD Hard Reset or a USB PD + * FR_Swap shall transition to Unattached.SNK within tSinkDisconnect + * when Vbus falls below vSinkDisconnect for Vbus operating at or + * below 5 V or below vSinkDisconnectPD when negotiated by USB PD + * to operate above 5 V." + * + * TODO(b/149530538): Use vSinkDisconnectPD when above 5V + */ + + /* * Debounce Vbus before we drop that we are doing a PR_Swap */ if (TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS) && @@ -2284,7 +2297,7 @@ static void tc_attached_snk_run(const int port) * with the swap and should have Vbus, so re-enable * AutoDischargeDisconnect. */ - if (pd_is_vbus_present(port)) + if (!pd_check_vbus_level(port, VBUS_REMOVED)) tcpm_enable_auto_discharge_disconnect(port, 1); } @@ -2297,7 +2310,7 @@ static void tc_attached_snk_run(const int port) /* * Detach detection */ - if (!pd_is_vbus_present(port)) { + if (pd_check_vbus_level(port, VBUS_REMOVED)) { if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) { pd_dfp_exit_mode(port, TCPC_TX_SOP, 0, 0); pd_dfp_exit_mode(port, TCPC_TX_SOP_PRIME, 0, 0); @@ -2396,7 +2409,7 @@ static void tc_attached_snk_run(const int port) #else /* CONFIG_USB_PE_SM */ /* Detach detection */ - if (!pd_is_vbus_present(port)) { + if (pd_check_vbus_level(port, VBUS_REMOVED)) { set_state_tc(port, TC_UNATTACHED_SNK); return; } @@ -3331,7 +3344,7 @@ static void tc_ct_attached_snk_run(int port) * transition to CTUnattached.SNK within tSinkDisconnect when VBUS * falls below vSinkDisconnect */ - if (!pd_is_vbus_present(port)) { + if (pd_check_vbus_level(port, VBUS_REMOVED)) { set_state_tc(port, TC_CT_UNATTACHED_SNK); return; } diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index 5af5fe0151..fd6a5906a5 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -100,7 +100,14 @@ STATIC_IF(DEBUG_GET_CC) * Last reported VBus Level * * BIT(VBUS_SAFE0V) will indicate if in SAFE0V - * BIT(VBUS_PRESENT) will indicate if in PRESENT + * BIT(VBUS_PRESENT) will indicate if in PRESENT in the TCPCI POWER_STATUS + * + * Note that VBUS_REMOVED cannot be distinguished from !VBUS_PRESENT with + * this interface, but the trigger thresholds for Vbus Present should allow the + * same bit to be used safely for both. + * + * TODO(b/149530538): Some TCPCs may be able to implement + * VBUS_SINK_DISCONNECT_THRESHOLD to support vSinkDisconnectPD */ static int tcpc_vbus[CONFIG_USB_PD_PORT_MAX_COUNT]; @@ -718,8 +725,10 @@ bool tcpci_tcpm_check_vbus_level(int port, enum vbus_level level) { if (level == VBUS_SAFE0V) return !!(tcpc_vbus[port] & BIT(VBUS_SAFE0V)); - else + else if (level == VBUS_PRESENT) return !!(tcpc_vbus[port] & BIT(VBUS_PRESENT)); + else + return !(tcpc_vbus[port] & BIT(VBUS_PRESENT)); } #endif diff --git a/include/usb_pd.h b/include/usb_pd.h index c42afd2b28..40b24aa79f 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -254,6 +254,10 @@ enum pd_rx_errors { #define PD_V_SAFE0V_MAX 800 #define PD_V_SAFE5V_MIN 4750 +/* USB Type-C voltages in mV (Table 4-3, USB Type-C Release 2.0 Spec) */ +#define PD_V_SINK_DISCONNECT_MAX 3670 +/* TODO(b/149530538): Add equation for vSinkDisconnectPD */ + /* function table for entered mode */ struct amode_fx { int (*status)(int port, uint32_t *payload); diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h index d6f89553fc..9044942171 100644 --- a/include/usb_pd_tcpm.h +++ b/include/usb_pd_tcpm.h @@ -104,10 +104,15 @@ enum tcpc_transmit_complete { TCPC_TX_COMPLETE_FAILED = 2, }; -/* USB-C PD Vbus levels */ +/* + * USB-C PD Vbus levels + * + * Return true on Vbus check if Vbus is... + */ enum vbus_level { - VBUS_SAFE0V, - VBUS_PRESENT, + VBUS_SAFE0V, /* less than vSafe0V max */ + VBUS_PRESENT, /* at least vSafe5V min */ + VBUS_REMOVED, /* less than vSinkDisconnect max */ }; /** |