summaryrefslogtreecommitdiff
path: root/driver/tcpm/tcpci.c
diff options
context:
space:
mode:
authorDenis Brockus <dbrockus@google.com>2020-03-17 12:21:05 -0600
committerCommit Bot <commit-bot@chromium.org>2020-03-20 04:39:57 +0000
commit03f5a8686a6a2274c176ead7fb928571a3e7c1f5 (patch)
tree09f467e642ce635a4e135534dbbd2ce9c0edab5f /driver/tcpm/tcpci.c
parent024e5e7811ee09801b55b08f274cb95e63c741d2 (diff)
downloadchrome-ec-03f5a8686a6a2274c176ead7fb928571a3e7c1f5.tar.gz
tcpmv2: cleanup auto discharge disconnect
This CL is based on the inability to boot trembyle when a battery is not connected. The failure looks like it is always right after AutoDischargeDisconnect has been set. I asked Nuvoton if we could go back to using ForcedDischarge and veer away from AutoDischargeDisconnect and I was told no that it is now required. My first step was to determine how close the existing AutoDischargeDisconnect was to the spec and found enough difference that I wanted to get that in line before trying to pinpoint the issues causing this problem. BUG=none BRANCH=none TEST=get tcpmv2 to work without a battery attached Signed-off-by: Denis Brockus <dbrockus@google.com> Change-Id: I44b86ae5dfcf6b547c742c1af0228a0ed8e3520d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2105935 Tested-by: Denis Brockus <dbrockus@chromium.org> Reviewed-by: Edward Hill <ecgh@chromium.org> Reviewed-by: Keith Short <keithshort@chromium.org> Commit-Queue: Denis Brockus <dbrockus@chromium.org> Auto-Submit: Denis Brockus <dbrockus@chromium.org>
Diffstat (limited to 'driver/tcpm/tcpci.c')
-rw-r--r--driver/tcpm/tcpci.c149
1 files changed, 142 insertions, 7 deletions
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index dd64ebb157..95c8d9bb3e 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -16,6 +16,7 @@
#include "tcpm.h"
#include "timer.h"
#include "usb_charge.h"
+#include "usb_common.h"
#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_tcpc.h"
@@ -379,13 +380,147 @@ int tcpci_tcpc_drp_toggle(int port)
{
int rv;
- /* Set auto drp toggle */
+ /*
+ * Set auto drp toggle
+ * NOTE: This should be done according to the last connection
+ * that we are disconnecting from. TCPCI Rev 2 spec figures
+ * 4-21 and 4-22 show:
+ * SNK => DRP should set CC lines to Rd/Rd
+ * SRC => DRP should set CC lines to Rp/Rp
+ * The function tcpci_tcpc_set_connection performs this action
+ * and it may be wise as chips can use this to make this the
+ * standard and remove this set_role_ctrl call.
+ */
rv = tcpci_set_role_ctrl(port, 1, TYPEC_RP_USB, TYPEC_CC_RD);
+ if (rv)
+ return rv;
+
+ /* Set up to catch LOOK4CONNECTION alerts */
+ rv = tcpc_update8(port,
+ TCPC_REG_TCPC_CTRL,
+ TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT,
+ MASK_SET);
+ if (rv)
+ return rv;
/* Set Look4Connection command */
- rv |= tcpc_write(port, TCPC_REG_COMMAND,
- TCPC_REG_COMMAND_LOOK4CONNECTION);
+ rv = tcpc_write(port, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_LOOK4CONNECTION);
+
+ return rv;
+}
+
+int tcpci_tcpc_set_connection(int port,
+ enum tcpc_cc_pull pull,
+ int connect)
+{
+ int rv;
+ int role;
+
+ /*
+ * Disconnecting will set the following and then return
+ * Set RC.DRP=1b (DRP)
+ * Set RC.RpValue=00b (smallest Rp to save power)
+ * Set RC.CC1=pull (Rd or Rp)
+ * Set RC.CC2=pull (Rd or Rp)
+ */
+ if (!connect) {
+ tcpci_set_role_ctrl(port, 1, TYPEC_RP_USB, pull);
+ return EC_SUCCESS;
+ }
+
+ /* Get the ROLE CONTROL value */
+ rv = tcpc_read(port, TCPC_REG_ROLE_CTRL, &role);
+ if (rv)
+ return rv;
+
+ if (role & TCPC_REG_ROLE_CTRL_DRP_MASK) {
+ enum tcpc_cc_pull cc1_pull, cc2_pull;
+ enum tcpc_cc_voltage_status cc1, cc2;
+
+ enum tcpc_cc_polarity polarity;
+ /*
+ * If DRP is set, the CC pins shall stay in
+ * Potential_Connect_as_Src or Potential_Connect_as_Sink
+ * until directed otherwise.
+ *
+ * Set RC.CC1 & RC.CC2 per potential decision
+ * Set RC.DRP=0
+ */
+ rv = tcpm_get_cc(port, &cc1, &cc2);
+ if (rv)
+ return rv;
+
+ 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_RP;
+ break;
+ case TYPEC_CC_VOLT_RP_DEF:
+ case TYPEC_CC_VOLT_RP_1_5:
+ case TYPEC_CC_VOLT_RP_3_0:
+ cc1_pull = TYPEC_CC_RD;
+ break;
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+
+ 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_RP;
+ break;
+ case TYPEC_CC_VOLT_RP_DEF:
+ case TYPEC_CC_VOLT_RP_1_5:
+ case TYPEC_CC_VOLT_RP_3_0:
+ cc2_pull = TYPEC_CC_RD;
+ break;
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+
+ /* Set the CC lines */
+ rv = tcpc_write(port, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(0,
+ CONFIG_USB_PD_PULLUP,
+ cc1_pull, cc2_pull));
+ if (rv)
+ return rv;
+
+ /* Set TCPC_CONTROl.PlugOrientation */
+ if (pull == TYPEC_CC_RD)
+ polarity = polarity_rm_dts(
+ get_snk_polarity(cc1, cc2));
+ else
+ polarity = get_src_polarity(cc1, cc2);
+
+ rv = tcpc_update8(port, TCPC_REG_TCPC_CTRL,
+ TCPC_REG_TCPC_CTRL_SET(1),
+ (polarity == POLARITY_CC1) ? MASK_CLR
+ : MASK_SET);
+ } else {
+ /*
+ * DRP is not set. This would happen if DRP is not enabled or
+ * was turned off and we did not have a connection. We have
+ * to manually turn off that we are looking for a connection
+ * and set both CC lines to the pull value.
+ */
+ rv = tcpc_update8(port,
+ TCPC_REG_TCPC_CTRL,
+ TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT,
+ MASK_CLR);
+ }
return rv;
}
#endif
@@ -852,6 +987,7 @@ void tcpci_tcpc_alert(int port)
int fault;
if (tcpci_get_fault(port, &fault) == EC_SUCCESS &&
+ fault != 0 &&
tcpci_handle_fault(port, fault) == EC_SUCCESS &&
tcpci_clear_fault(port, fault) == EC_SUCCESS)
CPRINTS("C%d FAULT 0x%02X handled", port, fault);
@@ -1030,7 +1166,6 @@ int tcpci_tcpm_init(int port)
int error;
int power_status;
int tries = TCPM_INIT_TRIES;
- int regval;
/* Start with an unknown connection */
tcpci_set_cached_pull(port, TYPEC_CC_OPEN);
@@ -1058,9 +1193,9 @@ int tcpci_tcpm_init(int port)
* Alert assertion when CC_STATUS.Looking4Connection changes state.
*/
if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) {
- error = tcpc_read(port, TCPC_REG_TCPC_CTRL, &regval);
- regval |= TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT;
- error |= tcpc_write(port, TCPC_REG_TCPC_CTRL, regval);
+ error = tcpc_update8(port, TCPC_REG_TCPC_CTRL,
+ TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT,
+ MASK_SET);
if (error)
CPRINTS("C%d: Failed to init TCPC_CTRL!", port);
}