Pullup is used by the usb framework in order to do software-controlled usb_gadget_connect() and usb_gadget_disconnect().
Implement pullup() for dwc2 using the SOFT_DISCONNECT bit in the dctl register: * when pullup is on, clear SOFT_DISCONNECT * when pullup is of, set SOFT_DISCONNECT This is especially useful when a gadget disconnection is initiated but no board_usb_cleanup() is called. Signed-off-by: Mattijs Korpershoek <mkorpersh...@baylibre.com> --- On some boards using the dwc2 controller, like the Khadas VIM3L, whenever usb_gadget_release() is called, the D+ and D- lines are in an unknown state. Because of that, the host can't detect usb disconnection. It was attempted to be be fixed with [1] but ended up doing the gadget disconnection too early, creating issues on NXP-based boards which use uuu [2]. By implementing pullup() in the controller driver, we ensure that the disconnection will only be done when the framework calls usb_gadget_disconnect(). [1] https://lore.kernel.org/all/20220728-reset-usb-controller-v2-1-ef7657ce7...@baylibre.com/ [2] https://lore.kernel.org/all/20230107164807.3597020-1-dario.binac...@amarulasolutions.com/ --- Changes in v2: - Simplified code to fix hungarian notation, appropriate type (u32) for register (Harald) - Use clrsetbits_le32() for register write (Marek) - Link to v1: https://lore.kernel.org/r/20230110-dwc2-pullup-v1-1-2bf9743e5...@baylibre.com --- drivers/usb/gadget/dwc2_udc_otg.c | 9 +++++++++ drivers/usb/gadget/dwc2_udc_otg_regs.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index 77988f78ab30..d0a9be49ad9c 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -236,6 +236,14 @@ static int udc_enable(struct dwc2_udc *dev) return 0; } +static int dwc2_gadget_pullup(struct usb_gadget *g, int is_on) +{ + clrsetbits_le32(®->dctl, SOFT_DISCONNECT, + (!is_on) << SOFT_DISCONNECT_BIT); + + return 0; +} + #if !CONFIG_IS_ENABLED(DM_USB_GADGET) /* Register entry point for the peripheral controller driver. @@ -805,6 +813,7 @@ static void dwc2_fifo_flush(struct usb_ep *_ep) } static const struct usb_gadget_ops dwc2_udc_ops = { + .pullup = dwc2_gadget_pullup, /* current versions must always be self-powered */ #if CONFIG_IS_ENABLED(DM_USB_GADGET) .udc_start = dwc2_gadget_start, diff --git a/drivers/usb/gadget/dwc2_udc_otg_regs.h b/drivers/usb/gadget/dwc2_udc_otg_regs.h index 9ca6f4237572..3749ee5eb053 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_regs.h +++ b/drivers/usb/gadget/dwc2_udc_otg_regs.h @@ -170,6 +170,7 @@ struct dwc2_usbotg_reg { /* DWC2_UDC_OTG_DCTL device control register */ #define NORMAL_OPERATION (0x1<<0) #define SOFT_DISCONNECT (0x1<<1) +#define SOFT_DISCONNECT_BIT (1) /* DWC2_UDC_OTG_DAINT device all endpoint interrupt register */ #define DAINT_OUT_BIT (16) --- base-commit: 81996adedf42e89de97c2ed5dcde62be4bb4e4e0 change-id: 20230110-dwc2-pullup-5b0f5a073d6b Best regards, -- Mattijs Korpershoek <mkorpersh...@baylibre.com>