Commit 3c162511 authored by Linyu Yuan's avatar Linyu Yuan Committed by Greg Kroah-Hartman

usb: typec: ucsi: Wait for the USB role switches

When role switch module probe late than ucsi module,
fwnode_usb_role_switch_get() will return -EPROBE_DEFER,
it is better to restart ucsi init work to find
it again every 100ms, total wait time is 10 second.

It also means change ucsi init work to delayed_work.
Reviewed-by: default avatarHeikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: default avatarLinyu Yuan <quic_linyyuan@quicinc.com>
Link: https://lore.kernel.org/r/1650881886-25530-3-git-send-email-quic_linyyuan@quicinc.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 87d0e2f4
...@@ -1053,6 +1053,14 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ...@@ -1053,6 +1053,14 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
con->num = index + 1; con->num = index + 1;
con->ucsi = ucsi; con->ucsi = ucsi;
cap->fwnode = ucsi_find_fwnode(con);
con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
if (IS_ERR(con->usb_role_sw)) {
dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
con->num);
return PTR_ERR(con->usb_role_sw);
}
/* Delay other interactions with the con until registration is complete */ /* Delay other interactions with the con until registration is complete */
mutex_lock(&con->lock); mutex_lock(&con->lock);
...@@ -1088,7 +1096,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ...@@ -1088,7 +1096,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY) if (con->cap.op_mode & UCSI_CONCAP_OPMODE_DEBUG_ACCESSORY)
*accessory = TYPEC_ACCESSORY_DEBUG; *accessory = TYPEC_ACCESSORY_DEBUG;
cap->fwnode = ucsi_find_fwnode(con);
cap->driver_data = con; cap->driver_data = con;
cap->ops = &ucsi_ops; cap->ops = &ucsi_ops;
...@@ -1146,13 +1153,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) ...@@ -1146,13 +1153,6 @@ static int ucsi_register_port(struct ucsi *ucsi, int index)
ucsi_port_psy_changed(con); ucsi_port_psy_changed(con);
} }
con->usb_role_sw = fwnode_usb_role_switch_get(cap->fwnode);
if (IS_ERR(con->usb_role_sw)) {
dev_err(ucsi->dev, "con%d: failed to get usb role switch\n",
con->num);
con->usb_role_sw = NULL;
}
/* Only notify USB controller if partner supports USB data */ /* Only notify USB controller if partner supports USB data */
if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB)) if (!(UCSI_CONSTAT_PARTNER_FLAGS(con->status.flags) & UCSI_CONSTAT_PARTNER_FLAG_USB))
u_role = USB_ROLE_NONE; u_role = USB_ROLE_NONE;
...@@ -1285,12 +1285,20 @@ static int ucsi_init(struct ucsi *ucsi) ...@@ -1285,12 +1285,20 @@ static int ucsi_init(struct ucsi *ucsi)
static void ucsi_init_work(struct work_struct *work) static void ucsi_init_work(struct work_struct *work)
{ {
struct ucsi *ucsi = container_of(work, struct ucsi, work); struct ucsi *ucsi = container_of(work, struct ucsi, work.work);
int ret; int ret;
ret = ucsi_init(ucsi); ret = ucsi_init(ucsi);
if (ret) if (ret)
dev_err(ucsi->dev, "PPM init failed (%d)\n", ret); dev_err(ucsi->dev, "PPM init failed (%d)\n", ret);
if (ret == -EPROBE_DEFER) {
if (ucsi->work_count++ > UCSI_ROLE_SWITCH_WAIT_COUNT)
return;
queue_delayed_work(system_long_wq, &ucsi->work,
UCSI_ROLE_SWITCH_INTERVAL);
}
} }
/** /**
...@@ -1330,7 +1338,7 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops) ...@@ -1330,7 +1338,7 @@ struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops)
if (!ucsi) if (!ucsi)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
INIT_WORK(&ucsi->work, ucsi_init_work); INIT_DELAYED_WORK(&ucsi->work, ucsi_init_work);
mutex_init(&ucsi->ppm_lock); mutex_init(&ucsi->ppm_lock);
ucsi->dev = dev; ucsi->dev = dev;
ucsi->ops = ops; ucsi->ops = ops;
...@@ -1365,7 +1373,7 @@ int ucsi_register(struct ucsi *ucsi) ...@@ -1365,7 +1373,7 @@ int ucsi_register(struct ucsi *ucsi)
if (!ucsi->version) if (!ucsi->version)
return -ENODEV; return -ENODEV;
queue_work(system_long_wq, &ucsi->work); queue_delayed_work(system_long_wq, &ucsi->work, 0);
return 0; return 0;
} }
...@@ -1382,7 +1390,7 @@ void ucsi_unregister(struct ucsi *ucsi) ...@@ -1382,7 +1390,7 @@ void ucsi_unregister(struct ucsi *ucsi)
u64 cmd = UCSI_SET_NOTIFICATION_ENABLE; u64 cmd = UCSI_SET_NOTIFICATION_ENABLE;
/* Make sure that we are not in the middle of driver initialization */ /* Make sure that we are not in the middle of driver initialization */
cancel_work_sync(&ucsi->work); cancel_delayed_work_sync(&ucsi->work);
/* Disable notifications */ /* Disable notifications */
ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd));
......
...@@ -287,7 +287,11 @@ struct ucsi { ...@@ -287,7 +287,11 @@ struct ucsi {
struct ucsi_capability cap; struct ucsi_capability cap;
struct ucsi_connector *connector; struct ucsi_connector *connector;
struct work_struct work; struct delayed_work work;
int work_count;
#define UCSI_ROLE_SWITCH_RETRY_PER_HZ 10
#define UCSI_ROLE_SWITCH_INTERVAL (HZ / UCSI_ROLE_SWITCH_RETRY_PER_HZ)
#define UCSI_ROLE_SWITCH_WAIT_COUNT (10 * UCSI_ROLE_SWITCH_RETRY_PER_HZ)
/* PPM Communication lock */ /* PPM Communication lock */
struct mutex ppm_lock; struct mutex ppm_lock;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment