summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorEric Yilun Lin <yllin@chromium.org>2020-09-25 16:21:27 +0800
committerCommit Bot <commit-bot@chromium.org>2020-10-08 06:00:54 +0000
commit853e6337629e3ef27e430075b7f3276f3832fa03 (patch)
treec6d1b50a55c1440f65c43a3e40d04c19df494467 /common
parent5b62424750cd8b486966d851a5a4d34bfe430d39 (diff)
downloadchrome-ec-853e6337629e3ef27e430075b7f3276f3832fa03.tar.gz
usbc_ppc: inform the PPC of the power role of the connected device
On some of the PPC (e.g. syv682) that support manually force discharge function doesn't automatically turn off discharge FET when VBUS meets vSafe0V. The original flow is disabling discharge on pd_set_power_supply_ready and enabling discharge on pd_power_supply_reset, and since there is no automatic turning off the discharge circuit, the FET will still be on when a SNK device connected. We fix this by informing the PPC on a device is connected or disconnected so that PPC can control the FET by requests. BUG=b:160548079, b:148870148, b:163143427 TEST=make buildall TEST=TCPMv2: on asurada C0/C1(syv682) and volteer C0(sn5s330)/C1(syv682) port, and enable force discharge mode (CL:2423665), plug sink and source device and ensure Vconn and Vbus are off within tVconnOff and tVBusOff respectively. Plug a DRP hub and then plug adapter in it, and it meets tVconnOff and tVbusOff. TEST=TCPMv1: tested the same steps as above on Asurada. BRANCH=NONE Change-Id: I8ed0e18fce2d402ff24fce6bab393cc618dfac09 Signed-off-by: Eric Yilun Lin <yllin@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2434590 Reviewed-by: Abe Levkoy <alevkoy@chromium.org> Tested-by: Eric Herrmann <eherrmann@chromium.org>
Diffstat (limited to 'common')
-rw-r--r--common/usb_pd_protocol.c14
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c15
-rw-r--r--common/usbc_ppc.c28
3 files changed, 41 insertions, 16 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 1fe963f1fc..5b2b344e4d 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -718,7 +718,7 @@ static inline void set_state(int port, enum pd_states next_state)
#if defined(CONFIG_USBC_PPC) && defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE)
/* If we're entering DRP_AUTO_TOGGLE, there is no sink connected. */
if (next_state == PD_STATE_DRP_AUTO_TOGGLE) {
- ppc_sink_is_connected(port, 0);
+ ppc_dev_is_connected(port, PPC_DEV_DISCONNECTED);
/*
* Clear the overcurrent event counter
* since we've detected a disconnect.
@@ -754,10 +754,10 @@ static inline void set_state(int port, enum pd_states next_state)
tcpm_get_cc(port, &cc1, &cc2);
/*
* Neither a debug accessory nor UFP attached.
- * Tell the PPC module that there is no sink connected.
+ * Tell the PPC module that there is no device connected.
*/
if (!cc_is_at_least_one_rd(cc1, cc2)) {
- ppc_sink_is_connected(port, 0);
+ ppc_dev_is_connected(port, PPC_DEV_DISCONNECTED);
/*
* Clear the overcurrent event counter
* since we've detected a disconnect.
@@ -3349,7 +3349,7 @@ void pd_task(void *u)
new_cc_state == PD_CC_UFP_DEBUG_ACC) {
#ifdef CONFIG_USBC_PPC
/* Inform PPC that a sink is connected. */
- ppc_sink_is_connected(port, 1);
+ ppc_dev_is_connected(port, PPC_DEV_SNK);
#endif /* CONFIG_USBC_PPC */
if (new_cc_state == PD_CC_UFP_DEBUG_ACC) {
pd[port].polarity =
@@ -4026,6 +4026,12 @@ void pd_task(void *u)
typec_set_input_current_limit(
port, typec_curr, TYPE_C_VOLTAGE);
#endif
+
+#ifdef CONFIG_USBC_PPC
+ /* Inform PPC that a source is connected. */
+ ppc_dev_is_connected(port, PPC_DEV_SRC);
+#endif /* CONFIG_USBC_PPC */
+
/* If PD comm is enabled, enable TCPC RX */
if (pd_comm_is_enabled(port))
tcpm_set_rx_enable(port, 1);
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index 1756f39c4a..270c7f5f51 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -1985,6 +1985,9 @@ static void tc_unattached_snk_entry(const int port)
charge_manager_update_dualrole(port, CAP_UNKNOWN);
if (IS_ENABLED(CONFIG_USBC_PPC)) {
+ /* There is no source connected. */
+ ppc_dev_is_connected(port, PPC_DEV_DISCONNECTED);
+
/*
* Clear the overcurrent event counter
* since we've detected a disconnect.
@@ -2185,6 +2188,10 @@ static void tc_attached_snk_entry(const int port)
*/
typec_select_pull(port, TYPEC_CC_RD);
+ /* Inform PPC that a source is connected. */
+ if (IS_ENABLED(CONFIG_USBC_PPC))
+ ppc_dev_is_connected(port, PPC_DEV_SRC);
+
#ifdef CONFIG_USB_PE_SM
if (TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS)) {
/* Flipping power role - Disable AutoDischargeDisconnect */
@@ -2479,7 +2486,7 @@ static void tc_unattached_src_entry(const int port)
if (IS_ENABLED(CONFIG_USBC_PPC)) {
/* There is no sink connected. */
- ppc_sink_is_connected(port, 0);
+ ppc_dev_is_connected(port, PPC_DEV_DISCONNECTED);
/*
* Clear the overcurrent event counter
@@ -2752,7 +2759,7 @@ static void tc_attached_src_entry(const int port)
/* Inform PPC that a sink is connected. */
if (IS_ENABLED(CONFIG_USBC_PPC))
- ppc_sink_is_connected(port, 1);
+ ppc_dev_is_connected(port, PPC_DEV_SNK);
/*
* Only notify if we're not performing a power role swap. During a
@@ -3421,8 +3428,8 @@ static void tc_cc_open_entry(const int port)
typec_update_cc(port);
if (IS_ENABLED(CONFIG_USBC_PPC)) {
- /* There is no sink connected. */
- ppc_sink_is_connected(port, 0);
+ /* There is no device connected. */
+ ppc_dev_is_connected(port, PPC_DEV_DISCONNECTED);
/*
* Clear the overcurrent event counter
diff --git a/common/usbc_ppc.c b/common/usbc_ppc.c
index 7a334ae439..6724d75abf 100644
--- a/common/usbc_ppc.c
+++ b/common/usbc_ppc.c
@@ -10,6 +10,7 @@
#include "console.h"
#include "hooks.h"
#include "timer.h"
+#include "usb_pd.h"
#include "usbc_ppc.h"
#include "util.h"
@@ -46,7 +47,8 @@ int ppc_err_prints(const char *string, int port, int error)
*/
static uint8_t oc_event_cnt_tbl[CONFIG_USB_PD_PORT_MAX_COUNT];
-static uint32_t connected_ports;
+/* A flag for ports with sink device connected. */
+static uint32_t snk_connected_ports;
/* Simple wrappers to dispatch to the drivers. */
@@ -82,7 +84,7 @@ int ppc_add_oc_event(int port)
oc_event_cnt_tbl[port]++;
/* The port overcurrented, so don't clear it's OC events. */
- deprecated_atomic_clear_bits(&connected_ports, 1 << port);
+ deprecated_atomic_clear_bits(&snk_connected_ports, 1 << port);
if (oc_event_cnt_tbl[port] >= PPC_OC_CNT_THRESH)
ppc_prints("OC event limit reached! "
@@ -100,7 +102,7 @@ static void clear_oc_tbl(void)
* Only clear the table if the port partner is no longer
* attached after debouncing.
*/
- if ((!(BIT(port) & connected_ports)) &&
+ if ((!(BIT(port) & snk_connected_ports)) &&
oc_event_cnt_tbl[port]) {
oc_event_cnt_tbl[port] = 0;
ppc_prints("OC events cleared", port);
@@ -256,17 +258,27 @@ int ppc_set_vconn(int port, int enable)
}
#endif
-void ppc_sink_is_connected(int port, int is_connected)
+int ppc_dev_is_connected(int port, enum ppc_device_role dev)
{
+ int rv = EC_SUCCESS;
+ const struct ppc_config_t *ppc;
+
if ((port < 0) || (port >= ppc_cnt)) {
CPRINTS("%s(%d) Invalid port!", __func__, port);
- return;
+ return EC_ERROR_INVAL;
}
- if (is_connected)
- deprecated_atomic_or(&connected_ports, 1 << port);
+ if (dev == PPC_DEV_SNK)
+ deprecated_atomic_or(&snk_connected_ports, 1 << port);
else
- deprecated_atomic_clear_bits(&connected_ports, 1 << port);
+ /* clear flag if it transitions to SRC or disconnected */
+ deprecated_atomic_clear_bits(&snk_connected_ports, 1 << port);
+
+ ppc = &ppc_chips[port];
+ if (ppc->drv->dev_is_connected)
+ rv = ppc->drv->dev_is_connected(port, dev);
+
+ return rv;
}
int ppc_vbus_sink_enable(int port, int enable)