summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorDanny Segal <dsegal@codeaurora.org>2014-05-22 16:11:58 +0300
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 11:06:34 -0700
commit8f171cb53fed821bdd304a1547692879e40a06c3 (patch)
treef6b780b25a29cf58aa8c416e6b68fd29ff3190b7 /drivers/usb
parent9e134dbb1b211ec1633c0cb000d30e5ed1b1333d (diff)
usb: dwc: add support for super-speed function suspend
The USB 3.0 specification defines a new 'Function Suspend' feature. This feature enables the USB host to put inactive composite device functions in a suspended state even when the device itself is not suspended. This patch extends the existing framework of USB dwc driver to properly support the 'Function Resume' and 'Function Remote Wakeup' related features. Change-Id: If7bbfa7d6a4ff70d4b44ede5fc258370b890df47 Signed-off-by: Danny Segal <dsegal@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/dwc3/ep0.c29
-rw-r--r--drivers/usb/dwc3/gadget.c18
2 files changed, 36 insertions, 11 deletions
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index e6bcbf11b872..4e06e4f3c2da 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -344,12 +344,24 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)
{
}
+
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ int ret;
+
+ spin_unlock(&dwc->lock);
+ ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+ spin_lock(&dwc->lock);
+ return ret;
+}
+
/*
* ch 9.4.5
*/
static int dwc3_ep0_handle_status(struct dwc3 *dwc,
struct usb_ctrlrequest *ctrl)
{
+ int ret;
struct dwc3_ep *dep;
u32 recip;
u32 reg;
@@ -379,6 +391,10 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
* Function Remote Wake Capable D0
* Function Remote Wakeup D1
*/
+
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ if (ret)
+ return ret;
break;
case USB_RECIP_ENDPOINT:
@@ -491,6 +507,9 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
/* XXX enable remote wakeup */
;
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ if (ret)
+ return ret;
break;
default:
return -EINVAL;
@@ -552,16 +571,6 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return 0;
}
-static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
-{
- int ret;
-
- spin_unlock(&dwc->lock);
- ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
- spin_lock(&dwc->lock);
- return ret;
-}
-
static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
enum usb_device_state state = dwc->gadget.state;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index a0a957da619f..5ef6401b3918 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -657,7 +657,8 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
int ret;
if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
- pr_debug("dwc3: invalid parameters\n");
+ pr_debug("dwc3: invalid parameters. ep=%p, desc=%p, DT=%d\n",
+ ep, desc, desc ? desc->bDescriptorType : 0);
return -EINVAL;
}
@@ -1514,6 +1515,20 @@ out:
return ret;
}
+static int dwc_gadget_func_wakeup(struct usb_gadget *g, int interface_id)
+{
+ int ret = 0;
+ struct dwc3 *dwc = gadget_to_dwc(g);
+
+ if (!g || (g->speed != USB_SPEED_SUPER))
+ return -ENOTSUPP;
+
+ ret = dwc3_send_gadget_generic_command(dwc,
+ DWC3_DGCMD_XMIT_FUNCTION, interface_id);
+
+ return ret;
+}
+
static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
int is_selfpowered)
{
@@ -1806,6 +1821,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g)
static const struct usb_gadget_ops dwc3_gadget_ops = {
.get_frame = dwc3_gadget_get_frame,
.wakeup = dwc3_gadget_wakeup,
+ .func_wakeup = dwc_gadget_func_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,