summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott <scollyer@chromium.org>2016-07-19 14:37:35 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-07-26 17:32:30 -0700
commitc358ee77a0b884d3959373153946f52b1a27b386 (patch)
tree1fd434b965530c75ad4075cadfaf274ae7c11a87
parent7a9ba2bae9a7d1f23a0d70ab2ec299dc6f461e17 (diff)
downloadchrome-ec-c358ee77a0b884d3959373153946f52b1a27b386.tar.gz
tcpm: fusb302: Changed get_cc to use full manual mode for revB
The FUSB302A had silicon limitation that required using its autodetect logic when presenting as a SRC. While testing on Kevin/Gru and connecting PD dongles, observed issues where following successful connects, the USB PD state machine would remain in SRC_DISCONNECTED state after removing the dongle. Flipping the connector (to reverse polarity) will recover from this stuck state. In order to resolve this problem and to make the tcpm_get_cc() FUSB302 driver function more consistent with the USB PD protocol state machine while acting as a source, the autodetect feature is now only used when a revA silicon device is detected. If it's not revA, then full manual mode is utilized for tcpm_get_cc. In addition, a new measure_cc_pin_source funciton was added that consolidates the operations that are shared between both autodetect and manual modes. BUG=chrome-os-partner:55429 BRANCH=None TEST=Manual Connected display adapter dongles and TypeC hub dongle repeatedly and verified that each connect attempt resulted in the USB PD state machine getting to SRC_READY state. Never observed the error state described above which previously could be repeated within ~ < 10 connection attempts. Change-Id: I3c8c6990129e0f1555a6698574adc603d6b7b45b Signed-off-by: Scott <scollyer@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/361617 Commit-Ready: Scott Collyer <scollyer@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Guenter Roeck <groeck@chromium.org> Reviewed-by: Joe Bauman <joe.bauman@fairchildsemi.com> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--driver/tcpm/fusb302.c160
1 files changed, 82 insertions, 78 deletions
diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c
index 9439fdc396..56ec303f04 100644
--- a/driver/tcpm/fusb302.c
+++ b/driver/tcpm/fusb302.c
@@ -95,98 +95,95 @@ static int convert_bc_lvl(int port, int bc_lvl)
return ret;
}
-/* Determine cc pin state for source */
-static void detect_cc_pin_source(int port, int *cc1_lvl, int *cc2_lvl)
+static int measure_cc_pin_source(int port, int cc_measure)
{
+ int switches0_reg;
int reg;
+ int cc_lvl;
+ int bc_lvl;
- *cc1_lvl = TYPEC_CC_VOLT_OPEN;
- *cc2_lvl = TYPEC_CC_VOLT_OPEN;
-
- if (state[port].togdone_pullup_cc1 == 1) {
- /* Measure CC1 */
- reg = TCPC_REG_SWITCHES0_CC1_PU_EN |
- TCPC_REG_SWITCHES0_MEAS_CC1;
-
- reg |= state[port].vconn_enabled ?
- TCPC_REG_SWITCHES0_VCONN_CC2 : 0;
- reg |= state[port].device_id != FUSB302_DEVID_302A ?
- TCPC_REG_SWITCHES0_CC2_PU_EN : 0;
-
- /* Enable CC1 measurement switch and pullup(s) */
- tcpc_write(port, TCPC_REG_SWITCHES0, reg);
-
- /* Set MDAC Value to High (1.6V). MDAC Reg is 5:0 */
- tcpc_write(port, TCPC_REG_MEASURE, 0x26);
-
- /* CC1 is now being measured by FUSB302. */
-
- /* Wait on measurement */
- usleep(250);
-
- /* Read status register */
- tcpc_read(port, TCPC_REG_STATUS0, &reg);
-
- if (reg & TCPC_REG_STATUS0_COMP) {
- *cc1_lvl = TYPEC_CC_VOLT_OPEN;
- } else {
+ /* Read status register */
+ tcpc_read(port, TCPC_REG_SWITCHES0, &reg);
+ /* Save current value */
+ switches0_reg = reg;
+ /* Clear pull-up register settings and measure bits */
+ reg &= ~(TCPC_REG_SWITCHES0_MEAS_CC1 | TCPC_REG_SWITCHES0_MEAS_CC2);
+ /* Set desired pullup register bit */
+ if (cc_measure == TCPC_REG_SWITCHES0_MEAS_CC1)
+ reg |= TCPC_REG_SWITCHES0_CC1_PU_EN;
+ else
+ reg |= TCPC_REG_SWITCHES0_CC2_PU_EN;
+ /* Set CC measure bit */
+ reg |= cc_measure;
- /* Set MDAC Value to Low (200 mV). MDAC Reg is 5:0 */
- tcpc_write(port, TCPC_REG_MEASURE, 0x05);
+ /* Set measurement switch */
+ tcpc_write(port, TCPC_REG_SWITCHES0, reg);
- /* Wait on measurement */
- usleep(250);
+ /* Set MDAC for Open vs Rd/Ra comparison (~1.6V) */
+ tcpc_write(port, TCPC_REG_MEASURE, 0x26);
- /* Read status register */
- tcpc_read(port, TCPC_REG_STATUS0, &reg);
+ /* Wait on measurement */
+ usleep(250);
- if (reg & TCPC_REG_STATUS0_COMP)
- *cc1_lvl = TYPEC_CC_VOLT_RD;
- else
- *cc1_lvl = TYPEC_CC_VOLT_RA;
- }
- } else if (state[port].togdone_pullup_cc2 == 1) {
- /* Measure CC2 */
- reg = TCPC_REG_SWITCHES0_CC2_PU_EN |
- TCPC_REG_SWITCHES0_MEAS_CC2;
+ /* Read status register */
+ tcpc_read(port, TCPC_REG_STATUS0, &reg);
- reg |= state[port].vconn_enabled ?
- TCPC_REG_SWITCHES0_VCONN_CC1 : 0;
- reg |= state[port].device_id != FUSB302_DEVID_302A ?
- TCPC_REG_SWITCHES0_CC1_PU_EN : 0;
+ /* Assume open */
+ cc_lvl = TYPEC_CC_VOLT_OPEN;
- /* Enable CC2 measurement switch and pullup */
- tcpc_write(port, TCPC_REG_SWITCHES0, reg);
+ if ((reg & TCPC_REG_STATUS0_COMP) == 0) {
+ /*
+ * CC line is < 1.6V, now need to determine if Rd or Ra is
+ * attached. The Ra threshold is < 200 mV and so can use the
+ * bc_lvl field of STATUS0 register.
+ */
+ bc_lvl = reg & (TCPC_REG_STATUS0_BC_LVL1 |
+ TCPC_REG_STATUS0_BC_LVL0);
- /* Set MDAC Value to High (~1.6V). MDAC Reg is 5:0 */
- tcpc_write(port, TCPC_REG_MEASURE, 0x26);
+ cc_lvl = bc_lvl ? TYPEC_CC_VOLT_RD : TYPEC_CC_VOLT_RA;
+ }
- /* CC2 is now being measured by FUSB302. */
+ /* Restore SWITCHES0 register to its value prior */
+ tcpc_write(port, TCPC_REG_SWITCHES0, switches0_reg);
- /* Wait on measurement */
- usleep(250);
+ return cc_lvl;
+}
- /* Read status register */
- tcpc_read(port, TCPC_REG_STATUS0, &reg);
+/* Determine cc pin state for source when in manual detect mode */
+static void detect_cc_pin_source_manual(int port, int *cc1_lvl, int *cc2_lvl)
+{
+ int cc1_measure = TCPC_REG_SWITCHES0_MEAS_CC1;
+ int cc2_measure = TCPC_REG_SWITCHES0_MEAS_CC2;
- if (reg & TCPC_REG_STATUS0_COMP) {
- *cc2_lvl = TYPEC_CC_VOLT_OPEN;
- } else {
+ if (state[port].vconn_enabled) {
+ /* If VCONN enabled, measure cc_pin that matches polarity */
+ if (state[port].cc_polarity)
+ *cc2_lvl = measure_cc_pin_source(port, cc2_measure);
+ else
+ *cc1_lvl = measure_cc_pin_source(port, cc1_measure);
+ } else {
+ /* If VCONN not enabled, measure both cc1 and cc2 */
+ *cc1_lvl = measure_cc_pin_source(port, cc1_measure);
+ *cc2_lvl = measure_cc_pin_source(port, cc2_measure);
+ }
- /* Set MDAC Value to Low (~200mV). MDAC Reg is 5:0 */
- tcpc_write(port, TCPC_REG_MEASURE, 0x05);
+}
- /* Wait on measurement */
- usleep(250);
+/* Determine cc pin state for source when autotoggle feature is enabled */
+static void detect_cc_pin_source_auto(int port, int *cc1_lvl, int *cc2_lvl)
+{
+ *cc1_lvl = TYPEC_CC_VOLT_OPEN;
+ *cc2_lvl = TYPEC_CC_VOLT_OPEN;
- /* Read status register */
- tcpc_read(port, TCPC_REG_STATUS0, &reg);
+ if (state[port].togdone_pullup_cc1 == 1) {
+ /* Measure CC1 */
+ *cc1_lvl = measure_cc_pin_source(port,
+ TCPC_REG_SWITCHES0_MEAS_CC1);
- if (reg & TCPC_REG_STATUS0_COMP)
- *cc2_lvl = TYPEC_CC_VOLT_RD;
- else
- *cc2_lvl = TYPEC_CC_VOLT_RA;
- }
+ } else if (state[port].togdone_pullup_cc2 == 1) {
+ /* Measure CC2 */
+ *cc2_lvl = measure_cc_pin_source(port,
+ TCPC_REG_SWITCHES0_MEAS_CC2);
}
}
@@ -378,8 +375,10 @@ static int fusb302_tcpm_init(int port)
tcpc_write(port, TCPC_REG_MASK, reg);
reg = 0xFF;
- /* informs of attaches */
- reg &= ~TCPC_REG_MASKA_TOGDONE;
+ /* Only use autodetect feature for revA silicon */
+ if (state[port].device_id == FUSB302_DEVID_302A)
+ /* informs of attaches */
+ reg &= ~TCPC_REG_MASKA_TOGDONE;
/* when all pd message retries fail... */
reg &= ~TCPC_REG_MASKA_RETRYFAIL;
/* when fusb302 send a hard reset. */
@@ -428,7 +427,10 @@ static int fusb302_tcpm_get_cc(int port, int *cc1, int *cc2)
if (state[port].pulling_up) {
/* Source mode? */
- detect_cc_pin_source(port, cc1, cc2);
+ if (state[port].device_id == FUSB302_DEVID_302A)
+ detect_cc_pin_source_auto(port, cc1, cc2);
+ else
+ detect_cc_pin_source_manual(port, cc1, cc2);
} else {
/* Sink mode? */
detect_cc_pin_sink(port, cc1, cc2);
@@ -456,8 +458,10 @@ static int fusb302_tcpm_set_cc(int port, int pull)
switch (pull) {
case TYPEC_CC_RP:
+ /* Only use autodetect feature for revA silicon */
/* if fusb302 hasn't figured anything out yet */
- if (!state[port].togdone_pullup_cc1 &&
+ if ((state[port].device_id == FUSB302_DEVID_302A) &&
+ !state[port].togdone_pullup_cc1 &&
!state[port].togdone_pullup_cc2) {
/* Enable DFP Toggle Mode */