Hello Amelie,
thank you for this patch - I am hoping that it will help us on Amlogic
Meson8, Meson8b, Meson8m2 and GXBB SoCs as well.
On these SoCs the ID detection is performed by the PHY IP and needs to
be polled.
I think usb_role_switch is the perfect framework for this on dwc2 side.
For the PHY driver I'm going to implement the cable state using the
extcon framework and then having a new usb-conn-extcon driver. This is
just to give you an overview why I'm interested in this.
[...]
+static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)due to this spin_lock_irqsave() ...
+{
+ÂÂÂÂ struct dwc2_hsotg *hsotg = usb_role_switch_get_drvdata(sw);
+ÂÂÂÂ unsigned long flags;
+
+ÂÂÂÂ /* Skip session not in line with dr_mode */
+ÂÂÂÂ if ((role == USB_ROLE_DEVICE && hsotg->dr_mode == USB_DR_MODE_HOST) ||
+ÂÂÂÂÂÂÂÂ (role == USB_ROLE_HOST && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
+ÂÂÂÂÂÂÂÂÂÂÂÂ return -EINVAL;
+
+ÂÂÂÂ /* Skip session if core is in test mode */
+ÂÂÂÂ if (role == USB_ROLE_NONE && hsotg->test_mode) {
+ÂÂÂÂÂÂÂÂÂÂÂÂ dev_dbg(hsotg->dev, "Core is in test mode\n");
+ÂÂÂÂÂÂÂÂÂÂÂÂ return -EBUSY;
+ÂÂÂÂ }
+
+ÂÂÂÂ spin_lock_irqsave(&hsotg->lock, flags);
+ÂÂÂÂ if (role == USB_ROLE_HOST) {... we cannot sleep in here. the call flow is:
+ÂÂÂÂÂÂÂÂÂÂÂÂ if (dwc2_ovr_avalid(hsotg, true))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ goto unlock;
+
+ÂÂÂÂÂÂÂÂÂÂÂÂ if (hsotg->dr_mode == USB_DR_MODE_OTG)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ /*
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ * This will raise a Connector ID Status Change
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ * Interrupt - connID A
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ */
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ dwc2_force_mode(hsotg, true);
dwc2_drd_role_sw_set
 spin_lock_irqsave
 dwc2_force_mode
ÂÂÂ dwc2_wait_for_mode
ÂÂÂÂÂ usleep_range
+ÂÂÂÂ } else if (role == USB_ROLE_DEVICE) {(same sleeping issue here)
+ÂÂÂÂÂÂÂÂÂÂÂÂ if (dwc2_ovr_bvalid(hsotg, true))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ goto unlock;
+
+ÂÂÂÂÂÂÂÂÂÂÂÂ if (hsotg->dr_mode == USB_DR_MODE_OTG)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ /*
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ * This will raise a Connector ID Status Change
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ * Interrupt - connID B
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ */
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ dwc2_force_mode(hsotg, false);
[...]
+int dwc2_drd_init(struct dwc2_hsotg *hsotg)
+{
+ÂÂÂÂÂÂ struct usb_role_switch_desc role_sw_desc = {0};
+ÂÂÂÂÂÂ struct usb_role_switch *role_sw;
+ÂÂÂÂÂÂ int ret;
+
+ÂÂÂÂÂÂ if (!device_property_read_bool(hsotg->dev, "usb-role-switch"))
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ return 0;
should we also return early here if dr_mode != "otg"?
[...]
@@ -532,6 +534,13 @@ static int dwc2_driver_probe(struct platform_device *dev)
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ dwc2_writel(hsotg, ggpio, GGPIO);
ÂÂÂÂÂÂÂÂ }
+ÂÂÂÂÂÂ retval = dwc2_drd_init(hsotg);
+ÂÂÂÂÂÂ if (retval) {
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ if (retval != -EPROBE_DEFER)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ dev_err(hsotg->dev, "failed to initialize dual-role\n");
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ goto error_init;
+ÂÂÂÂÂÂ }
+
ÂÂÂÂÂÂÂÂ if (hsotg->dr_mode != USB_DR_MODE_HOST) {
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ retval = dwc2_gadget_init(hsotg);
ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ if (retval)
I think dwc2_driver_probe() needs a new label (for example named
error_drd) which then calls dwc2_drd_exit. See [0] which I have
submitted as a patch for Linux 5.8, so it's not in usb-next yet.
Also in general I think you need to submit a dt-bindings patch that
documents the usb-role-switch property. Personally I would use
Documentation/devicetree/bindings/usb/renesas,usb3-peri.yaml as
reference for that.
Can you please keep me Cc'ed on a v2 because I'm not subscribed to the
linux-usb mailing list?
I am going to test this on Amlogic SoCs - once I made "everything else"
work I can give my Tested-by as well.
Thank you!
Martin
[0] https://patchwork.kernel.org/patch/11642957/