usb: typec: ucsi: Clear UCSI_CCI_RESET_COMPLETE before reset

Check the UCSI_CCI_RESET_COMPLETE complete flag before starting
another reset. Use a UCSI_SET_NOTIFICATION_ENABLE command to clear
the flag if it is set.

Signed-off-by: Christian A. Ehrhardt <lk@c--e.de>
Cc: stable <stable@kernel.org>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on SM8550-QRD
Link: https://lore.kernel.org/r/20240320073927.1641788-6-lk@c--e.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Christian A. Ehrhardt 2024-03-20 08:39:26 +01:00 committed by Greg Kroah-Hartman
parent 6aaceb7d9c
commit 3de4f996a0

View File

@ -1264,13 +1264,47 @@ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard)
static int ucsi_reset_ppm(struct ucsi *ucsi)
{
u64 command = UCSI_PPM_RESET;
u64 command;
unsigned long tmo;
u32 cci;
int ret;
mutex_lock(&ucsi->ppm_lock);
ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci));
if (ret < 0)
goto out;
/*
* If UCSI_CCI_RESET_COMPLETE is already set we must clear
* the flag before we start another reset. Send a
* UCSI_SET_NOTIFICATION_ENABLE command to achieve this.
* Ignore a timeout and try the reset anyway if this fails.
*/
if (cci & UCSI_CCI_RESET_COMPLETE) {
command = UCSI_SET_NOTIFICATION_ENABLE;
ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
sizeof(command));
if (ret < 0)
goto out;
tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS);
do {
ret = ucsi->ops->read(ucsi, UCSI_CCI,
&cci, sizeof(cci));
if (ret < 0)
goto out;
if (cci & UCSI_CCI_COMMAND_COMPLETE)
break;
if (time_is_before_jiffies(tmo))
break;
msleep(20);
} while (1);
WARN_ON(cci & UCSI_CCI_RESET_COMPLETE);
}
command = UCSI_PPM_RESET;
ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command,
sizeof(command));
if (ret < 0)