summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_pd_protocol.c5
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c9
-rw-r--r--driver/tcpm/nct38xx.c150
-rw-r--r--driver/tcpm/tcpm.h6
-rw-r--r--include/usb_pd.h9
-rw-r--r--include/usb_pd_tcpm.h24
6 files changed, 147 insertions, 56 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 2658ac9641..d248c67036 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -2668,11 +2668,6 @@ enum tcpc_cc_polarity pd_get_polarity(int port)
return pd[port].polarity;
}
-void pd_set_polarity(int port, enum tcpc_cc_polarity polarity)
-{
- pd[port].polarity = polarity;
-}
-
bool pd_get_partner_data_swap_capable(int port)
{
/* return data swap capable status of port partner */
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index 165be89450..5fd8d2727f 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -767,11 +767,6 @@ enum tcpc_cc_polarity pd_get_polarity(int port)
return tc[port].polarity;
}
-void pd_set_polarity(int port, enum tcpc_cc_polarity polarity)
-{
- tc[port].polarity = polarity;
-}
-
enum pd_data_role pd_get_data_role(int port)
{
return tc[port].data_role;
@@ -2888,7 +2883,7 @@ static void tc_drp_auto_toggle_run(const int port)
* the CC lines to what it is thinking is best or it goes
* directly back to unattached.
*/
- tcpm_auto_toggle_connection(port, cc1, cc2);
+ tcpm_drp_toggle_connection(port, cc1, cc2);
set_state_tc(port, TC_ATTACH_WAIT_SNK);
break;
case DRP_TC_UNATTACHED_SRC:
@@ -2898,7 +2893,7 @@ static void tc_drp_auto_toggle_run(const int port)
* the CC lines to what it is thinking is best or it goes
* directly back to unattached.
*/
- tcpm_auto_toggle_connection(port, cc1, cc2);
+ tcpm_drp_toggle_connection(port, cc1, cc2);
set_state_tc(port, TC_ATTACH_WAIT_SRC);
break;
case DRP_TC_DRP_AUTO_TOGGLE:
diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c
index 9c874f5e87..0f27661371 100644
--- a/driver/tcpm/nct38xx.c
+++ b/driver/tcpm/nct38xx.c
@@ -14,7 +14,6 @@
#include "task.h"
#include "tcpci.h"
#include "usb_common.h"
-#include "usb_pd.h"
#if !defined(CONFIG_USB_PD_TCPM_TCPCI)
#error "NCT38XX is using part of standard TCPCI control"
@@ -120,29 +119,140 @@ static void nct38xx_tcpc_alert(int port)
}
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
-static void nct38xx_auto_toggle_connection(int port,
+static void nct38xx_drp_toggle_connection(int port,
enum tcpc_cc_voltage_status cc1,
enum tcpc_cc_voltage_status cc2)
{
- int polarity;
+ int rv;
+ int role;
- /*
- * Get the current polarity so we can make sure the
- * PD stack will set the CC lines as we expect and
- * not to setting both CC lines the same due to
- * NO-POLARITY still being set in the cache. This
- * will cause this chip to go back to searching
- * auto toggle with an open on both CC lines.
- *
- * TODO(b/149415919): Consider trying to clear the DRP
- * mode instead of changing the polarity
- */
- if (cc_is_rp(cc1) || cc_is_rp(cc2))
- polarity = get_snk_polarity(cc1, cc2);
- else
- polarity = get_src_polarity(cc1, cc2);
+ /* Get the ROLE CONTROL value */
+ rv = tcpc_read(port, TCPC_REG_ROLE_CTRL, &role);
+ if (rv) {
+ CPRINTS("C%d: %s failed to read ROLE",
+ port, __func__);
+ return;
+ }
+
+ if (role & TCPC_REG_ROLE_CTRL_DRP_MASK) {
+ /* TODO(b/149593609) get an understanding from Nuvoton
+ * why this is the way it works.
+ *
+ * If DRP is set, the CC pins shall stay in
+ * Potential_Connect_as_Src or Potential_Connect_as_Sink
+ * until directed otherwise.
+ *
+ * From TCPCIr2 figure 4-20 DRP Connection Detection
+ * Determine CC & VCONN:
+ * Set RC.CC1 & RC.CC2 per potential connect decision
+ * Set RC.DRP=0
+ * Set TCPC_CONTROl.PlugOrientation
+ * Set PC.AutoDischargeDisconnect=1 & PC.EnableVconn
+ */
+ int ctrl;
+ enum tcpc_cc_polarity polarity;
+ enum tcpc_cc_voltage_status cc1_pull, cc2_pull;
+ enum tcpc_rp_value rp = TYPEC_RP_USB;
+
+ switch (cc1) {
+ case TYPEC_CC_VOLT_OPEN:
+ cc1_pull = TYPEC_CC_OPEN;
+ break;
+ case TYPEC_CC_VOLT_RA:
+ cc1_pull = TYPEC_CC_RA;
+ break;
+ case TYPEC_CC_VOLT_RD:
+ cc1_pull = TYPEC_CC_RD;
+ break;
+ case TYPEC_CC_VOLT_RP_DEF:
+ case TYPEC_CC_VOLT_RP_1_5:
+ case TYPEC_CC_VOLT_RP_3_0:
+ rp = cc1 - TYPEC_CC_VOLT_RP_DEF;
+ cc1_pull = TYPEC_CC_RP;
+ break;
+ default:
+ CPRINTS("C%d: %s Invalid CC1 Voltage presented",
+ port, __func__);
+ return;
+ }
+
+ switch (cc2) {
+ case TYPEC_CC_VOLT_OPEN:
+ cc2_pull = TYPEC_CC_OPEN;
+ break;
+ case TYPEC_CC_VOLT_RA:
+ cc2_pull = TYPEC_CC_RA;
+ break;
+ case TYPEC_CC_VOLT_RD:
+ cc2_pull = TYPEC_CC_RD;
+ break;
+ case TYPEC_CC_VOLT_RP_DEF:
+ case TYPEC_CC_VOLT_RP_1_5:
+ case TYPEC_CC_VOLT_RP_3_0:
+ rp = cc2 - TYPEC_CC_VOLT_RP_DEF;
+ cc2_pull = TYPEC_CC_RP;
+ break;
+ default:
+ CPRINTS("C%d: %s Invalid CC2 Voltage presented",
+ port, __func__);
+ return;
+ }
- pd_set_polarity(port, polarity);
+ /* Set the CC lines */
+ rv = tcpc_write(port, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(0,
+ rp, cc1_pull, cc2_pull));
+ if (rv) {
+ CPRINTS("C%d: %s failed to write ROLE",
+ port, __func__);
+ return;
+ }
+
+ /* Set the polarity */
+ if (cc_is_rp(cc1) || cc_is_rp(cc2))
+ polarity = get_snk_polarity(cc1, cc2);
+ else
+ polarity = get_src_polarity(cc1, cc2);
+ nct38xx_tcpm_drv.set_polarity(port, polarity);
+
+ /* Set/Clear auto discharge disconnect */
+ rv = tcpc_read(port, TCPC_REG_POWER_CTRL, &ctrl);
+ if (rv) {
+ CPRINTS("C%d: %s failed to read POWER_CTRL",
+ port, __func__);
+ return;
+ }
+
+ if (TCPC_REG_POWER_CTRL_VCONN(ctrl))
+ ctrl |= TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT;
+ else
+ ctrl &= ~TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT;
+
+ rv = tcpc_write(port,
+ TCPC_REG_POWER_CTRL,
+ ctrl);
+ if (rv) {
+ CPRINTS("C%d: %s failed to write POWER_CTRL",
+ port, __func__);
+ return;
+ }
+ } else {
+ /*
+ * We left auto-toggle and no longer have DRP set. This
+ * would happen if DRP was turned off and we did not have
+ * a connection. We have to manually turn off that we
+ * are looking for a connection.
+ */
+ rv = tcpc_update8(port,
+ TCPC_REG_TCPC_CTRL,
+ TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT,
+ MASK_CLR);
+ if (rv) {
+ CPRINTS("C%d: %s failed to clear Look4Connection",
+ port, __func__);
+ return;
+ }
+ }
}
#endif
@@ -169,7 +279,7 @@ const struct tcpm_drv nct38xx_tcpm_drv = {
&tcpci_tcpc_enable_auto_discharge_disconnect,
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
.drp_toggle = &tcpci_tcpc_drp_toggle,
- .tcpc_auto_toggle_connection = &nct38xx_auto_toggle_connection,
+ .drp_toggle_connection = &nct38xx_drp_toggle_connection,
#endif
#ifdef CONFIG_USBC_PPC
.set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl,
diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h
index 2b1368e483..61a3a0f8e3 100644
--- a/driver/tcpm/tcpm.h
+++ b/driver/tcpm/tcpm.h
@@ -258,14 +258,14 @@ static inline int tcpm_enable_drp_toggle(int port)
return tcpc_config[port].drv->drp_toggle(port);
}
-static inline void tcpm_auto_toggle_connection(int port,
+static inline void tcpm_drp_toggle_connection(int port,
enum tcpc_cc_voltage_status cc1,
enum tcpc_cc_voltage_status cc2)
{
const struct tcpm_drv *tcpc = tcpc_config[port].drv;
- if (tcpc->tcpc_auto_toggle_connection)
- tcpc->tcpc_auto_toggle_connection(port, cc1, cc2);
+ if (tcpc->drp_toggle_connection)
+ tcpc->drp_toggle_connection(port, cc1, cc2);
}
#endif
diff --git a/include/usb_pd.h b/include/usb_pd.h
index d17d071ebf..b6113b3236 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -2284,15 +2284,6 @@ void pd_transmit_complete(int port, int status);
enum tcpc_cc_polarity pd_get_polarity(int port);
/**
- * Set port polarity. This is cached by the PD stack and
- * some TCPCI events may need to alter this cached value.
- *
- * @param port USB-C port number
- * @param polarity current polarity
- */
-void pd_set_polarity(int port, enum tcpc_cc_polarity polarity);
-
-/**
* Get port partner data swap capable status
*
* @param port USB-C port number
diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h
index 9c9753ad90..d0953ab74e 100644
--- a/include/usb_pd_tcpm.h
+++ b/include/usb_pd_tcpm.h
@@ -327,6 +327,15 @@ struct tcpm_drv {
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
/**
+ * Enable TCPC auto DRP toggling.
+ *
+ * @param port Type-C port number
+ *
+ * @return EC_SUCCESS or error
+ */
+ int (*drp_toggle)(int port);
+
+ /**
* Auto Toggle Connection
* There is a connection while performing auto-toggle.
* Allow a driver to do any work required to leave the
@@ -336,18 +345,9 @@ struct tcpm_drv {
* @param cc1 enum tcpc_cc_pull of CC1
* @param cc2 enum tcpc_cc_pull of CC2
*/
- void (*tcpc_auto_toggle_connection)(int port,
- enum tcpc_cc_voltage_status cc1,
- enum tcpc_cc_voltage_status cc2);
-
- /**
- * Enable TCPC auto DRP toggling.
- *
- * @param port Type-C port number
- *
- * @return EC_SUCCESS or error
- */
- int (*drp_toggle)(int port);
+ void (*drp_toggle_connection)(int port,
+ enum tcpc_cc_voltage_status cc1,
+ enum tcpc_cc_voltage_status cc2);
#endif
/**