Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 018884fe authored by Danny Segal's avatar Danny Segal Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarDanny Segal <dsegal@codeaurora.org>
parent 44583bda
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -332,12 +332,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;
@@ -367,6 +379,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:
@@ -483,6 +499,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;
@@ -543,16 +562,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;
+17 −1
Original line number Diff line number Diff line
@@ -737,7 +737,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;
	}

@@ -1591,6 +1592,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)
{
@@ -1971,6 +1986,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,
	.vbus_session		= dwc3_gadget_vbus_session,
	.vbus_draw		= dwc3_gadget_vbus_draw,