Skip to content

Commit 5106dba

Browse files
Hsin-Te Yuangregkh
authored andcommitted
usb: typec: ucsi: Get connector status after enable notifications
Originally, the notification for connector change will be enabled after the first read of the connector status. Therefore, if the event happens during this window, it will be missing and make the status unsynced. Get the connector status only after enabling the notification for connector change to ensure the status is synced. Fixes: c1b0bc2 ("usb: typec: Add support for UCSI interface") Cc: stable <stable@kernel.org> Tested-by: Kenneth R. Crudup <kenny@panix.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Signed-off-by: Hsin-Te Yuan <yuanhsinte@chromium.org> Link: https://patch.msgid.link/20251218-ucsi-v7-1-aea83e83fb12@chromium.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0831269 commit 5106dba

1 file changed

Lines changed: 74 additions & 59 deletions

File tree

drivers/usb/typec/ucsi/ucsi.c

Lines changed: 74 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1624,11 +1624,71 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con)
16241624
return NULL;
16251625
}
16261626

1627+
static void ucsi_init_port(struct ucsi *ucsi, struct ucsi_connector *con)
1628+
{
1629+
enum usb_role u_role = USB_ROLE_NONE;
1630+
int ret;
1631+
1632+
/* Get the status */
1633+
ret = ucsi_get_connector_status(con, false);
1634+
if (ret) {
1635+
dev_err(ucsi->dev, "con%d: failed to get status\n", con->num);
1636+
return;
1637+
}
1638+
1639+
if (ucsi->ops->connector_status)
1640+
ucsi->ops->connector_status(con);
1641+
1642+
switch (UCSI_CONSTAT(con, PARTNER_TYPE)) {
1643+
case UCSI_CONSTAT_PARTNER_TYPE_UFP:
1644+
case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP:
1645+
u_role = USB_ROLE_HOST;
1646+
fallthrough;
1647+
case UCSI_CONSTAT_PARTNER_TYPE_CABLE:
1648+
typec_set_data_role(con->port, TYPEC_HOST);
1649+
break;
1650+
case UCSI_CONSTAT_PARTNER_TYPE_DFP:
1651+
u_role = USB_ROLE_DEVICE;
1652+
typec_set_data_role(con->port, TYPEC_DEVICE);
1653+
break;
1654+
default:
1655+
break;
1656+
}
1657+
1658+
/* Check if there is already something connected */
1659+
if (UCSI_CONSTAT(con, CONNECTED)) {
1660+
typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR));
1661+
ucsi_register_partner(con);
1662+
ucsi_pwr_opmode_change(con);
1663+
ucsi_orientation(con);
1664+
ucsi_port_psy_changed(con);
1665+
if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE)
1666+
ucsi_get_partner_identity(con);
1667+
if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS)
1668+
ucsi_check_cable(con);
1669+
}
1670+
1671+
/* Only notify USB controller if partner supports USB data */
1672+
if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB)))
1673+
u_role = USB_ROLE_NONE;
1674+
1675+
ret = usb_role_switch_set_role(con->usb_role_sw, u_role);
1676+
if (ret)
1677+
dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n",
1678+
con->num, u_role);
1679+
1680+
if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) {
1681+
ucsi_register_device_pdos(con);
1682+
ucsi_get_src_pdos(con);
1683+
ucsi_check_altmodes(con);
1684+
ucsi_check_connector_capability(con);
1685+
}
1686+
}
1687+
16271688
static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
16281689
{
16291690
struct typec_capability *cap = &con->typec_cap;
16301691
enum typec_accessory *accessory = cap->accessory;
1631-
enum usb_role u_role = USB_ROLE_NONE;
16321692
u64 command;
16331693
char *name;
16341694
int ret;
@@ -1729,63 +1789,6 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
17291789
goto out;
17301790
}
17311791

1732-
/* Get the status */
1733-
ret = ucsi_get_connector_status(con, false);
1734-
if (ret) {
1735-
dev_err(ucsi->dev, "con%d: failed to get status\n", con->num);
1736-
goto out;
1737-
}
1738-
1739-
if (ucsi->ops->connector_status)
1740-
ucsi->ops->connector_status(con);
1741-
1742-
switch (UCSI_CONSTAT(con, PARTNER_TYPE)) {
1743-
case UCSI_CONSTAT_PARTNER_TYPE_UFP:
1744-
case UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP:
1745-
u_role = USB_ROLE_HOST;
1746-
fallthrough;
1747-
case UCSI_CONSTAT_PARTNER_TYPE_CABLE:
1748-
typec_set_data_role(con->port, TYPEC_HOST);
1749-
break;
1750-
case UCSI_CONSTAT_PARTNER_TYPE_DFP:
1751-
u_role = USB_ROLE_DEVICE;
1752-
typec_set_data_role(con->port, TYPEC_DEVICE);
1753-
break;
1754-
default:
1755-
break;
1756-
}
1757-
1758-
/* Check if there is already something connected */
1759-
if (UCSI_CONSTAT(con, CONNECTED)) {
1760-
typec_set_pwr_role(con->port, UCSI_CONSTAT(con, PWR_DIR));
1761-
ucsi_register_partner(con);
1762-
ucsi_pwr_opmode_change(con);
1763-
ucsi_orientation(con);
1764-
ucsi_port_psy_changed(con);
1765-
if (con->ucsi->cap.features & UCSI_CAP_GET_PD_MESSAGE)
1766-
ucsi_get_partner_identity(con);
1767-
if (con->ucsi->cap.features & UCSI_CAP_CABLE_DETAILS)
1768-
ucsi_check_cable(con);
1769-
}
1770-
1771-
/* Only notify USB controller if partner supports USB data */
1772-
if (!(UCSI_CONSTAT(con, PARTNER_FLAG_USB)))
1773-
u_role = USB_ROLE_NONE;
1774-
1775-
ret = usb_role_switch_set_role(con->usb_role_sw, u_role);
1776-
if (ret) {
1777-
dev_err(ucsi->dev, "con:%d: failed to set usb role:%d\n",
1778-
con->num, u_role);
1779-
ret = 0;
1780-
}
1781-
1782-
if (con->partner && UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD) {
1783-
ucsi_register_device_pdos(con);
1784-
ucsi_get_src_pdos(con);
1785-
ucsi_check_altmodes(con);
1786-
ucsi_check_connector_capability(con);
1787-
}
1788-
17891792
trace_ucsi_register_port(con->num, con);
17901793

17911794
out:
@@ -1903,17 +1906,29 @@ static int ucsi_init(struct ucsi *ucsi)
19031906
goto err_unregister;
19041907
}
19051908

1909+
/* Delay other interactions with each connector until ucsi_init_port is done */
1910+
for (i = 0; i < ucsi->cap.num_connectors; i++)
1911+
mutex_lock(&connector[i].lock);
1912+
19061913
/* Enable all supported notifications */
19071914
ntfy = ucsi_get_supported_notifications(ucsi);
19081915
command = UCSI_SET_NOTIFICATION_ENABLE | ntfy;
19091916
ucsi->message_in_size = 0;
19101917
ret = ucsi_send_command(ucsi, command);
1911-
if (ret < 0)
1918+
if (ret < 0) {
1919+
for (i = 0; i < ucsi->cap.num_connectors; i++)
1920+
mutex_unlock(&connector[i].lock);
19121921
goto err_unregister;
1922+
}
19131923

19141924
ucsi->connector = connector;
19151925
ucsi->ntfy = ntfy;
19161926

1927+
for (i = 0; i < ucsi->cap.num_connectors; i++) {
1928+
ucsi_init_port(ucsi, &connector[i]);
1929+
mutex_unlock(&connector[i].lock);
1930+
}
1931+
19171932
mutex_lock(&ucsi->ppm_lock);
19181933
ret = ucsi->ops->read_cci(ucsi, &cci);
19191934
mutex_unlock(&ucsi->ppm_lock);

0 commit comments

Comments
 (0)