summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/mock/tcpc_mock.c12
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c21
-rw-r--r--driver/tcpm/tcpci.c13
-rw-r--r--include/usb_pd.h4
-rw-r--r--include/usb_pd_tcpm.h11
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 */
};
/**