On Mon, Aug 31, 2020 at 07:59:16PM -0700, Badhri Jagan Sridharan wrote: > ROLE_CONTROL register would not have the actual CC terminations > unless the port does not set ROLE_CONTROL.DRP. For DRP ports, > CC_STATUS.cc1/cc2 indicates the final terminations applied > when TCPC enters potential_connect_as_source/_sink. > For DRP ports, infer port role from CC_STATUS and set corresponding > CC terminations before setting the orientation. > > Signed-off-by: Badhri Jagan Sridharan <badhri@xxxxxxxxxx> Reviewed-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > --- > Changes since v1: > - Changing patch version to v6 to fix version number confusion. > --- > drivers/usb/typec/tcpm/tcpci.c | 37 +++++++++++++++++++++++++++++++++- > 1 file changed, 36 insertions(+), 1 deletion(-) > > diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c > index 7d36d5e2d3f7..7d9491ba62fb 100644 > --- a/drivers/usb/typec/tcpm/tcpci.c > +++ b/drivers/usb/typec/tcpm/tcpci.c > @@ -191,12 +191,47 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc, > struct tcpci *tcpci = tcpc_to_tcpci(tcpc); > unsigned int reg; > int ret; > + enum typec_cc_status cc1, cc2; > > - /* Keep the disconnect cc line open */ > + /* Obtain Rp setting from role control */ > ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, ®); > if (ret < 0) > return ret; > > + ret = tcpci_get_cc(tcpc, &cc1, &cc2); > + if (ret < 0) > + return ret; > + > + /* > + * When port has drp toggling enabled, ROLE_CONTROL would only have the initial > + * terminations for the toggling and does not indicate the final cc > + * terminations when ConnectionResult is 0 i.e. drp toggling stops and > + * the connection is resolbed. Infer port role from TCPC_CC_STATUS based on the > + * terminations seen. The port role is then used to set the cc terminations. > + */ > + if (reg & TCPC_ROLE_CTRL_DRP) { > + /* Disable DRP for the OPEN setting to take effect */ > + reg = reg & ~TCPC_ROLE_CTRL_DRP; > + > + if (polarity == TYPEC_POLARITY_CC2) { > + reg &= ~(TCPC_ROLE_CTRL_CC2_MASK << TCPC_ROLE_CTRL_CC2_SHIFT); > + /* Local port is source */ > + if (cc2 == TYPEC_CC_RD) > + /* Role control would have the Rp setting when DRP was enabled */ > + reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT; > + else > + reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT; > + } else { > + reg &= ~(TCPC_ROLE_CTRL_CC1_MASK << TCPC_ROLE_CTRL_CC1_SHIFT); > + /* Local port is source */ > + if (cc1 == TYPEC_CC_RD) > + /* Role control would have the Rp setting when DRP was enabled */ > + reg |= TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT; > + else > + reg |= TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT; > + } > + } > + > if (polarity == TYPEC_POLARITY_CC2) > reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT; > else > -- > 2.28.0.402.g5ffc5be6b7-goog -- heikki