On Tue, Oct 07, 2025 at 12:00:07AM +0000, Jameson Thies wrote: > From: Abhishek Pandit-Subedi > > Power role swaps initiated by the host system doesn't generate > connection status change notifications. > > From UCSIv3.0 spec, section 6.5.10 Set Power Direction Role: > > The execution of this command might require PPM to initiate a power > role swap. If the power role swap fails for any reason, the command > returns, and error and the power direction should remain unchanged. > Note that if the execution of the command resulted in a successful > power role swap, it should not result in a connector status change > notification. > > Signed-off-by: Abhishek Pandit-Subedi > Signed-off-by: Jameson Thies Reviewed-by: Benson Leung > --- > drivers/usb/typec/ucsi/ucsi.c | 30 +++++++++++++++++++++++++----- > 1 file changed, 25 insertions(+), 5 deletions(-) > > diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c > index 1a7d850b11ea..6e3797d7a144 100644 > --- a/drivers/usb/typec/ucsi/ucsi.c > +++ b/drivers/usb/typec/ucsi/ucsi.c > @@ -1526,20 +1526,40 @@ static int ucsi_pr_swap(struct typec_port *port, enum typec_role role) > if (ret < 0) > goto out_unlock; > > - mutex_unlock(&con->lock); > + command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); > + ret = ucsi_send_command(con->ucsi, command, &con->status, sizeof(con->status)); > + if (ret < 0) > + goto out_unlock; > > - if (!wait_for_completion_timeout(&con->complete, > - msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) > - return -ETIMEDOUT; > + cur_role = !!UCSI_CONSTAT(con, PWR_DIR); > > - mutex_lock(&con->lock); > + /* Execution of SET_PDR should not result in connector status > + * notifications. However, some legacy implementations may still defer > + * the actual role swap and return immediately. Thus, check the > + * connector status in case it immediately succeeded or wait for a later > + * connector status change. > + */ > + if (cur_role != role) { > + mutex_unlock(&con->lock); > + > + if (!wait_for_completion_timeout( > + &con->complete, > + msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) > + return -ETIMEDOUT; > + > + mutex_lock(&con->lock); > + } > > /* Something has gone wrong while swapping the role */ > if (UCSI_CONSTAT(con, PWR_OPMODE) != UCSI_CONSTAT_PWR_OPMODE_PD) { > ucsi_reset_connector(con, true); > ret = -EPROTO; > + goto out_unlock; > } > > + /* Indicate successful power role swap */ > + typec_set_pwr_role(con->port, role); > + > out_unlock: > mutex_unlock(&con->lock); > > -- > 2.51.0.618.g983fd99d29-goog >