Re: [PATCH v5 6/9] usb: misc: qcom_eud: add role-based EUD control
Peter Chen <[email protected]> Mon, 3 Aug 2026 02:50:12 -0700
| Newsgroups | org.kernel.vger.linux-usb,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 26-08-02 20:15:31, Elson Serrao wrote: > EUD functions by presenting itself as a USB device to the host PC and is > therefore only applicable when the port operates in device role. Keeping > EUD enabled in other roles provides no benefit and unnecessarily keeps > the associated PHY resources enabled. Furthermore, enabling EUD in host > role can cause the USB controller to misbehave because the EUD hub > supports only a single upstream-facing port. > > Address this by treating EUD as usable only in device role. The > role-switch callback enables or disables EUD as the port enters or > leaves device role. A sysfs enable request made outside device role is > recorded and honored when the port subsequently switches to device role. > > Signed-off-by: Elson Serrao <[email protected]> Reviewed-by: Peter Chen <[email protected]> Peter > --- > drivers/usb/misc/qcom_eud.c | 46 ++++++++++++++++++++++++++++++++++++- > 1 file changed, 45 insertions(+), 1 deletion(-) > > diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c > index e83a4402e4b8..538e070cc140 100644 > --- a/drivers/usb/misc/qcom_eud.c > +++ b/drivers/usb/misc/qcom_eud.c > @@ -15,6 +15,7 @@ > #include <linux/phy/phy.h> > #include <linux/platform_device.h> > #include <linux/slab.h> > +#include <linux/string_choices.h> > #include <linux/sysfs.h> > #include <linux/usb/role.h> > #include <linux/firmware/qcom/qcom_scm.h> > @@ -55,6 +56,8 @@ struct eud_chip { > struct device *dev; > void __iomem *base; > struct eud_path *paths[EUD_MAX_PORTS]; > + /* serializes EUD control operations */ > + struct mutex state_lock; > phys_addr_t mode_mgr; > unsigned int int_status; > int irq; > @@ -156,17 +159,33 @@ static ssize_t enable_store(struct device *dev, > const char *buf, size_t count) > { > struct eud_chip *chip = dev_get_drvdata(dev); > + struct eud_path *path; > bool enable; > int ret; > > if (kstrtobool(buf, &enable)) > return -EINVAL; > > + guard(mutex)(&chip->state_lock); > + > /* Skip operation if already in desired state */ > if (chip->enabled == enable) > return count; > > if (enable) { > + path = chip->paths[chip->port_idx]; > + > + /* > + * If not yet in device role, honor the userspace request and defer > + * EUD enablement until the port transitions to device role in the > + * set_role callback. > + */ > + if (path->curr_role != USB_ROLE_DEVICE) { > + dev_info(chip->dev, "Deferring EUD enable until port enters device mode\n"); > + chip->enabled = enable; > + return count; > + } > + > ret = enable_eud(chip); > if (ret) { > dev_err(chip->dev, "failed to enable eud\n"); > @@ -304,7 +323,30 @@ static irqreturn_t handle_eud_irq_thread(int irq, void *data) > static int eud_role_switch_set(struct usb_role_switch *sw, enum usb_role role) > { > struct eud_path *path = usb_role_switch_get_drvdata(sw); > - int ret; > + struct eud_chip *chip = path->chip; > + int ret = 0; > + > + guard(mutex)(&chip->state_lock); > + > + /* > + * EUD is usable only in device role. Power it down for every other > + * role to avoid keeping an unusable module 'ON'. chip->enabled > + * preserves user's sysfs configuration and is not modified across > + * role transitions. > + */ > + if (chip->enabled && path->num == chip->port_idx && role != path->curr_role) { > + if (role == USB_ROLE_DEVICE) > + ret = enable_eud(chip); > + else if (path->curr_role == USB_ROLE_DEVICE) > + ret = disable_eud(chip); > + > + if (ret) { > + dev_err(chip->dev, "failed to %s EUD for role %s: %d\n", > + str_enable_disable(role == USB_ROLE_DEVICE), > + usb_role_string(role), ret); > + return ret; > + } > + } > > /* Forward the role request to the USB controller */ > ret = usb_role_switch_set_role(path->controller_sw, role); > @@ -431,6 +473,8 @@ static int eud_probe(struct platform_device *pdev) > > chip->dev = &pdev->dev; > > + mutex_init(&chip->state_lock); > + > for_each_child_of_node_scoped(np, child) { > ret = eud_init_path(chip, child); > if (ret) > -- > 2.34.1 > -- Thanks, Peter Chen