diff options
author | Scott <scollyer@chromium.org> | 2017-03-08 12:32:09 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-03-16 00:11:43 -0700 |
commit | d3cc4835bba84f8767480272cd3057c066922ae2 (patch) | |
tree | d429f6ca7718f03b6c3181e1bb1e8f55162de6bd /driver/tcpm | |
parent | e86a0dad240b6d672e87d2b05432d0c91288e35c (diff) | |
download | chrome-ec-d3cc4835bba84f8767480272cd3057c066922ae2.tar.gz |
tcpm: anx74xx: Only connect aux to sbu when DP mode is selected
The anx74xx tcpm driver for the usb_mux_set() function is always
connecting the DP aux lines to the SBU signals regardless of whether
the bit flag MUX_DP_ENABLED was set or not. For CCD opertation the sbu
lines are used to establish a USB connection to H1. This means that if
a PD port ever attaches to a sink debug accessory, usb_mux_set would
result in interrupting the USB connection being used for CCD.
In addition, the anx74xx_tcpm_mux_exit() function had a bug where the
value read from ANALOG_CTRL_5 was being masked by 0x09 and then
written to ANALOG_CTRL_2.
Added functions anx74xx_tcpm_mux_enter_safe_mode() and
anx74xx_tcpm_mux_exit_safe_mode() so that writes to the 3 CTRL
registers that are used to configure ALT_DP mode can be easily
bookended.
BUG=b:36007652
BRANCH=reef
TEST=Connected servo_v4 to port 0 of electro, verified that H1 console
access worked. Then initiated a data role swap so that port 0 on
electro was in DFP mode and the H1 console stayed connected.
- Tested with dingdong that could connect to a 4k monitor.
- Tested with USB3 flash drive.
- Tested Anker USBC -> USBA hub
Change-Id: I2d045134fbdd21b6b492bbeabc85ab23aef73b9a
Signed-off-by: Scott <scollyer@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/451837
Commit-Ready: Scott Collyer <scollyer@chromium.org>
Tested-by: Scott Collyer <scollyer@chromium.org>
Reviewed-by: S Wang <swang@analogix.corp-partner.google.com>
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Diffstat (limited to 'driver/tcpm')
-rw-r--r-- | driver/tcpm/anx74xx.c | 143 |
1 files changed, 105 insertions, 38 deletions
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c index 6cc5c65bb0..e3d7d081e7 100644 --- a/driver/tcpm/anx74xx.c +++ b/driver/tcpm/anx74xx.c @@ -41,8 +41,6 @@ struct anx_state { static struct anx_state anx[CONFIG_USB_PD_PORT_COUNT]; -static int anx74xx_set_mux(int port, int polarity); - /* Save the selected rp value */ static int selected_rp[CONFIG_USB_PD_PORT_COUNT]; @@ -151,56 +149,108 @@ static int anx74xx_tcpm_mux_init(int i2c_addr) return EC_SUCCESS; } +static int anx74xx_tcpm_mux_enter_safe_mode(int port) +{ + int reg; + + if (tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, ®)) + return EC_ERROR_UNKNOWN; + if (tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg | + ANX74XX_REG_MODE_TRANS)) + return EC_ERROR_UNKNOWN; + + + return EC_SUCCESS; +} + +static int anx74xx_tcpm_mux_exit_safe_mode(int port) +{ + int reg; + + if (tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, ®)) + return EC_ERROR_UNKNOWN; + if (tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg & + ~ANX74XX_REG_MODE_TRANS)) + return EC_ERROR_UNKNOWN; + + + return EC_SUCCESS; +} + static int anx74xx_tcpm_mux_exit(int port) { - int rv = EC_SUCCESS; - int reg = 0x0; + int reg; - rv = tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, ®); - if (rv) + /* + * Safe mode must be entered before any changes are made to the mux + * settings used to enable ALT_DP mode. This funciton is called either + * from anx74xx_tcpm_mux_set when TYPEC_MUX_NONE is selected as the new + * mux state, or when both cc lines are determined to be + * TYPEC_CC_VOLT_OPEN. Therefore, safe mode must be entered and exited + * here so that both entry paths are handled. + */ + if (anx74xx_tcpm_mux_enter_safe_mode(port)) return EC_ERROR_UNKNOWN; - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg | ANX74XX_REG_MODE_TRANS); - /* Clear Bit[7:0] R_SWITCH */ - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_1, 0x0); + /* Disconnect aux from sbu */ + if (tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, ®)) + return EC_ERROR_UNKNOWN; + if (tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg & 0xf)) + return EC_ERROR_UNKNOWN; + /* Clear Bit[7:0] R_SWITCH */ + if (tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_1, 0x0)) + return EC_ERROR_UNKNOWN; /* Clear Bit[7:4] R_SWITCH_H */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_5, ®); - if (rv) + if (tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_5, ®)) return EC_ERROR_UNKNOWN; - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_5, (reg & 0x0f)); - - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg & 0x09); - if (rv) + if (tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_5, reg & 0x0f)) return EC_ERROR_UNKNOWN; - return rv; + /* Exit safe mode */ + if (anx74xx_tcpm_mux_exit_safe_mode(port)) + return EC_ERROR_UNKNOWN; + return EC_SUCCESS; } -static int anx74xx_set_mux(int port, int polarity) +static int anx74xx_mux_aux_to_sbu(int port, int polarity, int enabled) { - int reg, rv = EC_SUCCESS; + int reg; + const int aux_mask = ANX74XX_REG_AUX_SWAP_SET_CC2 | + ANX74XX_REG_AUX_SWAP_SET_CC1; - rv = tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, ®); - if (rv) + /* + * Get the current value of analog_ctrl_2 register. Note, that safe mode + * is enabled and exited by the calling function, so only have to worry + * about setting the correct value for the upper 4 bits of analog_ctrl_2 + * here. + */ + if (tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_2, ®)) return EC_ERROR_UNKNOWN; - if (polarity) { - reg |= ANX74XX_REG_AUX_SWAP_SET_CC2; - reg &= ~ANX74XX_REG_AUX_SWAP_SET_CC1; - } else { - reg |= ANX74XX_REG_AUX_SWAP_SET_CC1; - reg &= ~ANX74XX_REG_AUX_SWAP_SET_CC2; + + /* Assume aux_p/n lines are not connected */ + reg &= ~aux_mask; + + if (enabled) { + /* If enabled, connect aux to sbu based on desired polarity */ + if (polarity) + reg |= ANX74XX_REG_AUX_SWAP_SET_CC2; + else + reg |= ANX74XX_REG_AUX_SWAP_SET_CC1; } - rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg); + /* Write new aux <-> sbu settings */ + if (tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_2, reg)) + return EC_ERROR_UNKNOWN; - return rv; + return EC_SUCCESS; } static int anx74xx_tcpm_mux_set(int i2c_addr, mux_state_t mux_state) { - int reg = 0, val = 0; + int reg; + int pin_cfg = 0; int rv; int port = i2c_addr; @@ -217,37 +267,54 @@ static int anx74xx_tcpm_mux_set(int i2c_addr, mux_state_t mux_state) if (mux_state & MUX_USB_ENABLED) { /* Set pin assignment D */ if (mux_state & MUX_POLARITY_INVERTED) { - val = ANX74XX_REG_MUX_DP_MODE_BDF_CC2; + pin_cfg = ANX74XX_REG_MUX_DP_MODE_BDF_CC2; reg |= ANX74XX_REG_MUX_SSTX_B; } else { - val = ANX74XX_REG_MUX_DP_MODE_BDF_CC1; + pin_cfg = ANX74XX_REG_MUX_DP_MODE_BDF_CC1; reg |= ANX74XX_REG_MUX_SSTX_A; } } else if (mux_state & MUX_DP_ENABLED) { /* Set pin assignment C */ if (mux_state & MUX_POLARITY_INVERTED) { - val = ANX74XX_REG_MUX_DP_MODE_ACE_CC2; + pin_cfg = ANX74XX_REG_MUX_DP_MODE_ACE_CC2; reg |= ANX74XX_REG_MUX_ML2_B; } else { - val = ANX74XX_REG_MUX_DP_MODE_ACE_CC1; + pin_cfg = ANX74XX_REG_MUX_DP_MODE_ACE_CC1; reg |= ANX74XX_REG_MUX_ML2_A; } - /* FIXME: disabling DP mode should disable SBU muxes */ - rv |= anx74xx_set_mux(port, mux_state & MUX_POLARITY_INVERTED); } else if (!mux_state) { return anx74xx_tcpm_mux_exit(port); } else { return EC_ERROR_UNIMPLEMENTED; } - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_1, val); + /* + * Safe mode must be entererd prior to any changes to the mux related to + * ALT_DP mode. Therefore, first enable safe mode prior to updating the + * values for analog_ctrl_1, analog_ctrl_5, and analog_ctrl_2. + */ + if (anx74xx_tcpm_mux_enter_safe_mode(port)) + return EC_ERROR_UNKNOWN; + + /* Write updated pin assignment */ + rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_1, pin_cfg); + /* Write Rswitch config bits */ rv |= tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_5, reg); + if (rv) + return EC_ERROR_UNKNOWN; - anx74xx_set_mux(port, mux_state & MUX_POLARITY_INVERTED ? 1 : 0); + /* Configure DP aux to sbu settings */ + if (anx74xx_mux_aux_to_sbu(port, mux_state & MUX_POLARITY_INVERTED, + mux_state & MUX_DP_ENABLED)) + return EC_ERROR_UNKNOWN; + + /* Exit safe mode */ + if (anx74xx_tcpm_mux_exit_safe_mode(port)) + return EC_ERROR_UNKNOWN; anx[port].mux_state = mux_state; - return rv; + return EC_SUCCESS; } /* current mux state */ |