Loading drivers/usb/dwc3/gadget.c +76 −19 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ #include <linux/io.h> #include <linux/list.h> #include <linux/dma-mapping.h> #include <linux/vmalloc.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> Loading @@ -60,6 +61,13 @@ static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend); static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend); static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc); static void _dwc3_gadget_wakeup(struct dwc3 *dwc); struct dwc3_usb_gadget { struct work_struct wakeup_work; struct dwc3 *dwc; }; /** * dwc3_gadget_set_test_mode - Enables USB2 Test Modes Loading Loading @@ -1317,6 +1325,33 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) return 0; } static int dwc3_gadget_wakeup(struct usb_gadget *g) { struct dwc3_usb_gadget *dwc3_gadget = g->private; struct dwc3 *dwc = dwc3_gadget->dwc; unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); if (atomic_read(&dwc->in_lpm)) { spin_unlock_irqrestore(&dwc->lock, flags); schedule_work(&dwc3_gadget->wakeup_work); return -EBUSY; } else { _dwc3_gadget_wakeup(dwc); } spin_unlock_irqrestore(&dwc->lock, flags); return 0; } static inline enum dwc3_link_state dwc3_get_link_state(struct dwc3 *dwc) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_DSTS); return DWC3_DSTS_USBLNKST(reg); } static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags) { Loading Loading @@ -1508,22 +1543,37 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) reg = dwc3_readl(dwc->regs, DWC3_DSTS); return DWC3_DSTS_SOFFN(reg); } static int dwc3_gadget_wakeup(struct usb_gadget *g) static void dwc3_gadget_wakeup_work(struct work_struct *w) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long timeout; struct dwc3_usb_gadget *dwc3_gadget; struct dwc3 *dwc; unsigned long flags; bool link_recover_only = false; u32 reg; dwc3_gadget = container_of(w, struct dwc3_usb_gadget, wakeup_work); dwc = dwc3_gadget->dwc; int ret = 0; u8 link_state; spin_lock_irqsave(&dwc->lock, flags); if (atomic_read(&dwc->in_lpm)) { spin_unlock_irqrestore(&dwc->lock, flags); pm_runtime_get_sync(dwc->dev); spin_lock_irqsave(&dwc->lock, flags); } _dwc3_gadget_wakeup(dwc); spin_unlock_irqrestore(&dwc->lock, flags); } static void _dwc3_gadget_wakeup(struct dwc3 *dwc) { u32 timeout = 0; bool link_recover_only = false; u32 reg; int ret = 0; u8 link_state; /* * According to the Databook Remote wakeup request should Loading @@ -1531,9 +1581,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) * * We can check that via USB Link State bits in DSTS register. */ reg = dwc3_readl(dwc->regs, DWC3_DSTS); link_state = DWC3_DSTS_USBLNKST(reg); link_state = dwc3_get_link_state(dwc); switch (link_state) { case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ Loading Loading @@ -1567,17 +1615,16 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) } /* poll until Link State changes to ON */ timeout = jiffies + msecs_to_jiffies(100); spin_unlock_irqrestore(&dwc->lock, flags); while (!time_after(jiffies, timeout)) { do { reg = dwc3_readl(dwc->regs, DWC3_DSTS); /* in HS, means ON */ if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0) break; } spin_lock_irqsave(&dwc->lock, flags); udelay(10); timeout++; } while (timeout < 10000); if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { dev_err(dwc->dev, "failed to send remote wakeup\n"); Loading @@ -1594,9 +1641,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) if (!link_recover_only) dwc3_gadget_wakeup_interrupt(dwc); out: spin_unlock_irqrestore(&dwc->lock, flags); return ret; return; } static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, Loading Loading @@ -3121,6 +3167,15 @@ int dwc3_gadget_init(struct dwc3 *dwc) { u32 reg; int ret; struct dwc3_usb_gadget *dwc3_gadget; dwc3_gadget = vzalloc(sizeof(*dwc3_gadget)); if (!dwc3_gadget) { dev_err(dwc->dev, "failed to allocate dwc3_gadget\n"); return -ENOMEM; } dwc3_gadget->dwc = dwc; INIT_WORK(&dwc3_gadget->wakeup_work, dwc3_gadget_wakeup_work); dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), &dwc->ctrl_req_addr, GFP_KERNEL); Loading Loading @@ -3163,6 +3218,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; dwc->gadget.name = "dwc3-gadget"; dwc->gadget.private = dwc3_gadget; /* * REVISIT: Here we should clear all pending IRQs to be Loading Loading @@ -3229,6 +3285,7 @@ err1: dwc->ctrl_req, dwc->ctrl_req_addr); err0: vfree(dwc3_gadget); return ret; } Loading include/linux/usb/gadget.h +1 −0 Original line number Diff line number Diff line Loading @@ -562,6 +562,7 @@ struct usb_gadget { u8 usb_core_id; bool streaming_enabled; bool remote_wakeup; void *private; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) Loading Loading
drivers/usb/dwc3/gadget.c +76 −19 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ #include <linux/io.h> #include <linux/list.h> #include <linux/dma-mapping.h> #include <linux/vmalloc.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> Loading @@ -60,6 +61,13 @@ static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend); static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend); static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc); static void _dwc3_gadget_wakeup(struct dwc3 *dwc); struct dwc3_usb_gadget { struct work_struct wakeup_work; struct dwc3 *dwc; }; /** * dwc3_gadget_set_test_mode - Enables USB2 Test Modes Loading Loading @@ -1317,6 +1325,33 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) return 0; } static int dwc3_gadget_wakeup(struct usb_gadget *g) { struct dwc3_usb_gadget *dwc3_gadget = g->private; struct dwc3 *dwc = dwc3_gadget->dwc; unsigned long flags; spin_lock_irqsave(&dwc->lock, flags); if (atomic_read(&dwc->in_lpm)) { spin_unlock_irqrestore(&dwc->lock, flags); schedule_work(&dwc3_gadget->wakeup_work); return -EBUSY; } else { _dwc3_gadget_wakeup(dwc); } spin_unlock_irqrestore(&dwc->lock, flags); return 0; } static inline enum dwc3_link_state dwc3_get_link_state(struct dwc3 *dwc) { u32 reg; reg = dwc3_readl(dwc->regs, DWC3_DSTS); return DWC3_DSTS_USBLNKST(reg); } static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, gfp_t gfp_flags) { Loading Loading @@ -1508,22 +1543,37 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) reg = dwc3_readl(dwc->regs, DWC3_DSTS); return DWC3_DSTS_SOFFN(reg); } static int dwc3_gadget_wakeup(struct usb_gadget *g) static void dwc3_gadget_wakeup_work(struct work_struct *w) { struct dwc3 *dwc = gadget_to_dwc(g); unsigned long timeout; struct dwc3_usb_gadget *dwc3_gadget; struct dwc3 *dwc; unsigned long flags; bool link_recover_only = false; u32 reg; dwc3_gadget = container_of(w, struct dwc3_usb_gadget, wakeup_work); dwc = dwc3_gadget->dwc; int ret = 0; u8 link_state; spin_lock_irqsave(&dwc->lock, flags); if (atomic_read(&dwc->in_lpm)) { spin_unlock_irqrestore(&dwc->lock, flags); pm_runtime_get_sync(dwc->dev); spin_lock_irqsave(&dwc->lock, flags); } _dwc3_gadget_wakeup(dwc); spin_unlock_irqrestore(&dwc->lock, flags); } static void _dwc3_gadget_wakeup(struct dwc3 *dwc) { u32 timeout = 0; bool link_recover_only = false; u32 reg; int ret = 0; u8 link_state; /* * According to the Databook Remote wakeup request should Loading @@ -1531,9 +1581,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) * * We can check that via USB Link State bits in DSTS register. */ reg = dwc3_readl(dwc->regs, DWC3_DSTS); link_state = DWC3_DSTS_USBLNKST(reg); link_state = dwc3_get_link_state(dwc); switch (link_state) { case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */ Loading Loading @@ -1567,17 +1615,16 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) } /* poll until Link State changes to ON */ timeout = jiffies + msecs_to_jiffies(100); spin_unlock_irqrestore(&dwc->lock, flags); while (!time_after(jiffies, timeout)) { do { reg = dwc3_readl(dwc->regs, DWC3_DSTS); /* in HS, means ON */ if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0) break; } spin_lock_irqsave(&dwc->lock, flags); udelay(10); timeout++; } while (timeout < 10000); if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { dev_err(dwc->dev, "failed to send remote wakeup\n"); Loading @@ -1594,9 +1641,8 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) if (!link_recover_only) dwc3_gadget_wakeup_interrupt(dwc); out: spin_unlock_irqrestore(&dwc->lock, flags); return ret; return; } static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, Loading Loading @@ -3121,6 +3167,15 @@ int dwc3_gadget_init(struct dwc3 *dwc) { u32 reg; int ret; struct dwc3_usb_gadget *dwc3_gadget; dwc3_gadget = vzalloc(sizeof(*dwc3_gadget)); if (!dwc3_gadget) { dev_err(dwc->dev, "failed to allocate dwc3_gadget\n"); return -ENOMEM; } dwc3_gadget->dwc = dwc; INIT_WORK(&dwc3_gadget->wakeup_work, dwc3_gadget_wakeup_work); dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req), &dwc->ctrl_req_addr, GFP_KERNEL); Loading Loading @@ -3163,6 +3218,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.sg_supported = true; dwc->gadget.name = "dwc3-gadget"; dwc->gadget.private = dwc3_gadget; /* * REVISIT: Here we should clear all pending IRQs to be Loading Loading @@ -3229,6 +3285,7 @@ err1: dwc->ctrl_req, dwc->ctrl_req_addr); err0: vfree(dwc3_gadget); return ret; } Loading
include/linux/usb/gadget.h +1 −0 Original line number Diff line number Diff line Loading @@ -562,6 +562,7 @@ struct usb_gadget { u8 usb_core_id; bool streaming_enabled; bool remote_wakeup; void *private; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) Loading