diff options
author | Scott <scollyer@chromium.org> | 2016-07-19 14:37:35 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-07-26 17:32:30 -0700 |
commit | c358ee77a0b884d3959373153946f52b1a27b386 (patch) | |
tree | 1fd434b965530c75ad4075cadfaf274ae7c11a87 /driver | |
parent | 7a9ba2bae9a7d1f23a0d70ab2ec299dc6f461e17 (diff) | |
download | chrome-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>
Diffstat (limited to 'driver')
-rw-r--r-- | driver/tcpm/fusb302.c | 160 |
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, ®); - - 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 */ |