From: Zixun LI Date: Mon, 2 Jun 2025 15:45:08 +0000 (+0200) Subject: usb: gadget: atmel: reliably generate disconnect by disabling controller X-Git-Tag: v2025.10-rc1~118^2~14^2 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ca036308a513759e3e4cbe9f8191861c3232c611;p=pandora-u-boot.git usb: gadget: atmel: reliably generate disconnect by disabling controller Contrary to the datasheet, setting both DETACH and PULLD_DIS bits to 1 does not always drive the DP and DM lines to high-impedance. This prevents the host from reliably detecting a USB disconnect and subsequent reconnect. The symptom is that the first gadget command (e.g., dhcp) succeeds, while subsequent commands (e.g., nfs) fail. Disabling and re-enabling the controller entirely, instead of toggling the PULLD_DIS bit, reliably generates a disconnect event. The Linux driver works correctly because gadget_disconnect/gadget_connect are always followed by gadget_udc_start/gadget_udc_stop. In U-Boot pullup() is used solely. This behavior has been observed on the SAM9X60-Curiosity and AT91SAM9G25-EK boards and has been reported to Microchip. Signed-off-by: Zixun LI Link: https://lore.kernel.org/r/20250602-pullup-v1-1-edcde5a050dd@hifiphile.com [mkorpershoek: reworded commit title + comment to usba_udc_pullup()] Signed-off-by: Mattijs Korpershoek --- diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index f9326f0a7e7..72f68dba3a7 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -521,16 +521,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) static int usba_udc_pullup(struct usb_gadget *gadget, int is_on) { struct usba_udc *udc = to_usba_udc(gadget); - u32 ctrl; - - ctrl = usba_readl(udc, CTRL); + /* + * Some chips don't reliably drive DP/DM lines to high impedance when + * using the DETACH/PULLD_DIS bits. + * To ensure a reliable disconnect, power cycle the controller instead + */ if (is_on) - ctrl &= ~USBA_DETACH; + usba_writel(udc, CTRL, USBA_ENABLE_MASK); else - ctrl |= USBA_DETACH; - - usba_writel(udc, CTRL, ctrl); + usba_writel(udc, CTRL, USBA_DISABLE_MASK); return 0; }