Hi, On Tue, Nov 03, 2026 at 03:21:26PM +0400, Alexey Charkov wrote: > Let TCPM discover e-marked cables through the FUSB302 and learn their > current and speed ratings. > > Receive SOP' only while sourcing VCONN with PD reception on. Only the > VCONN Source talks to the cable plug, and acking the traffic between the > partner and the plug would collide with their own GoodCRC. > > Switch SOP' reception off before VCONN or PD reception goes off and on > only once both are on. If that fails, log it instead of failing the > switch TCPM asked for: SOP' reception left off only costs cable > discovery, and left on with VCONN off makes the port ack the partner's > traffic with the cable plug until PD reception goes off, which beats > keeping VCONN or PD reception in a state TCPM did not request. > > Tested on a FUSB302B as source with an e-marked 5A EPR cable. The > datasheet documents the auto-GoodCRC header bits for SOP only, but the > cable plug took the chip's acks to its SOP' replies without retrying. > > Signed-off-by: Alexey Charkov > --- Reviewed-by: Sebastian Reichel Greetings, -- Sebastian > drivers/usb/typec/tcpm/fusb302.c | 37 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 37 insertions(+) > > diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c > index 8b3a2e095ef8..10f2dabf3318 100644 > --- a/drivers/usb/typec/tcpm/fusb302.c > +++ b/drivers/usb/typec/tcpm/fusb302.c > @@ -725,6 +725,27 @@ static int tcpm_set_polarity(struct tcpc_dev *dev, > return 0; > } > > +/* > + * Without VCONN from us, SOP' traffic is between the partner and the cable > + * plug, and our GoodCRC would collide with theirs. So stop receiving SOP' > + * before VCONN or PD reception goes off, and start only once both are on. > + * Neither is worth failing the VCONN or PD reception switch over. > + */ > +static void fusb302_pd_set_sop_prime(struct fusb302_chip *chip, bool on) > +{ > + int ret; > + > + if (on) > + ret = fusb302_i2c_set_bits(chip, FUSB_REG_CONTROL1, > + FUSB_REG_CONTROL1_ENSOP1); > + else > + ret = fusb302_i2c_clear_bits(chip, FUSB_REG_CONTROL1, > + FUSB_REG_CONTROL1_ENSOP1); > + if (ret < 0) > + fusb302_log(chip, "cannot turn SOP' rx %s, ret=%d", > + str_on_off(on), ret); > +} > + > static int tcpm_set_vconn(struct tcpc_dev *dev, bool on) > { > struct fusb302_chip *chip = container_of(dev, struct fusb302_chip, > @@ -743,6 +764,8 @@ static int tcpm_set_vconn(struct tcpc_dev *dev, bool on) > switches0_data = (chip->cc_polarity == TYPEC_POLARITY_CC1) ? > FUSB_REG_SWITCHES0_VCONN_CC2 : > FUSB_REG_SWITCHES0_VCONN_CC1; > + } else { > + fusb302_pd_set_sop_prime(chip, false); > } > ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0, > switches0_mask, switches0_data); > @@ -750,6 +773,9 @@ static int tcpm_set_vconn(struct tcpc_dev *dev, bool on) > goto done; > chip->vconn_on = on; > fusb302_log(chip, "vconn := %s", str_on_off(on)); > + > + if (on && chip->pd_rx_on) > + fusb302_pd_set_sop_prime(chip, true); > done: > mutex_unlock(&chip->lock); > > @@ -848,6 +874,8 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) > goto done; > } > > + if (!on) > + fusb302_pd_set_sop_prime(chip, false); > ret = fusb302_pd_rx_flush(chip); > if (ret < 0) { > fusb302_log(chip, "cannot flush pd rx buffer, ret=%d", ret); > @@ -873,6 +901,9 @@ static int tcpm_set_pd_rx(struct tcpc_dev *dev, bool on) > > chip->pd_rx_on = on; > fusb302_log(chip, "pd := %s", str_on_off(on)); > + > + if (on && chip->vconn_on) > + fusb302_pd_set_sop_prime(chip, true); > done: > mutex_unlock(&chip->lock); > > @@ -1136,6 +1167,11 @@ static void fusb302_bc_lvl_handler_work(struct work_struct *work) > mutex_unlock(&chip->lock); > } > > +static bool tcpm_cable_comm_capable(struct tcpc_dev *dev) > +{ > + return true; > +} > + > static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev) > { > fusb302_tcpc_dev->init = tcpm_init; > @@ -1150,6 +1186,7 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev) > fusb302_tcpc_dev->set_roles = tcpm_set_roles; > fusb302_tcpc_dev->start_toggling = tcpm_start_toggling; > fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit; > + fusb302_tcpc_dev->cable_comm_capable = tcpm_cable_comm_capable; > } > > static const char * const cc_polarity_name[] = { > > -- > 2.56.0 >