From c358ee77a0b884d3959373153946f52b1a27b386 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 19 Jul 2016 14:37:35 -0700 Subject: 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 Reviewed-on: https://chromium-review.googlesource.com/361617 Commit-Ready: Scott Collyer Tested-by: Scott Collyer Reviewed-by: Guenter Roeck Reviewed-by: Joe Bauman Reviewed-by: Shawn N --- driver/tcpm/fusb302.c | 160 ++++++++++++++++++++++++++------------------------ 1 file changed, 82 insertions(+), 78 deletions(-) (limited to 'driver/tcpm/fusb302.c') 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, ®); - - if (reg & TCPC_REG_STATUS0_COMP) { - *cc1_lvl = TYPEC_CC_VOLT_OPEN; - } else { + /* Read status register */ + tcpc_read(port, TCPC_REG_SWITCHES0, ®); + /* 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, ®); + /* 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 |= 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, ®); +/* 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, ®); + 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 */ -- cgit v1.2.1