From 2e537ca82aed85a5355c52c8fe709eaa19da5a28 Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Mon, 13 Jul 2020 18:23:25 -0700 Subject: [PATCH] dwc3: Add USB function suspend/resume related handling Currently dwc3 driver doesn't hand over USB function suspend/resume request to composite layer as those are supposed to be handle by USB function driver. This change adds support for it. It also adds function remote wakeup functionality which is needed by USB function suspended interface to perform remote wakeup towards USB host for resume interface related functionality. Change-Id: I1f9ecc60346e16fad87439cc12c551e05b4f3491 Signed-off-by: Mayank Rana --- drivers/usb/dwc3/ep0.c | 7 ++++++- drivers/usb/dwc3/gadget.c | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index bce34a0b6d0e..0763dd3ba8aa 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -30,6 +30,8 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, dma_addr_t buf_dma, u32 len, u32 type, bool chain) @@ -352,7 +354,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + return dwc3_ep0_delegate_req(dwc, ctrl); case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -507,6 +509,9 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, * For now, we're not doing anything, just making sure we return * 0 so USB Command Verifier tests pass without any errors. */ + ret = dwc3_ep0_delegate_req(dwc, ctrl); + if (ret) + return ret; break; default: ret = -EINVAL; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b09e35cb206e..dc2b4cdd588a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2116,6 +2116,28 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) return 0; } +#ifdef CONFIG_USB_FUNC_WAKEUP_SUPPORTED +static int dwc_gadget_func_wakeup(struct usb_gadget *g, int interface_id) +{ + int ret = 0; + struct dwc3 *dwc = gadget_to_dwc(g); + + if (dwc3_gadget_is_suspended(dwc)) { + dev_dbg(dwc->dev, "USB bus is suspended, scheduling wakeup\n"); + dwc3_gadget_wakeup(&dwc->gadget); + return -EAGAIN; + } + + ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_XMIT_DEV, + 0x1 | (interface_id << 4)); + if (ret) + dev_err(dwc->dev, "Function wakeup HW command failed, ret %d\n", + ret); + + return ret; +} +#endif + static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, int is_selfpowered) { @@ -2770,6 +2792,9 @@ static void __maybe_unused dwc3_gadget_set_speed(struct usb_gadget *g, static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, +#ifdef CONFIG_USB_FUNC_WAKEUP_SUPPORTED + .func_wakeup = dwc_gadget_func_wakeup, +#endif .set_selfpowered = dwc3_gadget_set_selfpowered, .vbus_session = dwc3_gadget_vbus_session, .vbus_draw = dwc3_gadget_vbus_draw,