linux-arm-msm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pavankumar Kondeti <pkondeti@codeaurora.org>
To: linux-usb@vger.kernel.org
Cc: linux-arm-msm@vger.kernel.org,
	Pavankumar Kondeti <pkondeti@codeaurora.org>
Subject: [RFC 2/5] USB: core: OTG Supplement Revision 2.0 updates
Date: Wed, 15 Dec 2010 16:44:11 +0530	[thread overview]
Message-ID: <1292411654-21382-3-git-send-email-pkondeti@codeaurora.org> (raw)
In-Reply-To: <1292411654-21382-1-git-send-email-pkondeti@codeaurora.org>

OTG supplement revision 2.0 spec introduces Attach Detection Protocol
(ADP) for detecting peripheral connection without applying power on
VBUS.  ADP is optional and is included in the OTG descriptor along with
SRP and HNP.

HNP polling is introduced for peripheral to notify its wish to become
host.  Host polls (GET_STATUS on DEVICE) peripheral for host_request
and suspend the bus when peripheral returns host_request TRUE.  The spec
insists the polling frequency to be in 1-2 sec range and bus should be
suspended with in 2 sec from host_request is set.

a_alt_hnp_support feature is obsolete and a_hnp_support feature is limited
to only legacy OTG B-device.  The newly introduced bcdOTG field in the OTG
descriptor is used for identifying the 2.0 compliant B-device.

Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
---
 drivers/usb/core/driver.c |   50 +++++++++++++++++++++++++++++++
 drivers/usb/core/hcd.c    |    3 ++
 drivers/usb/core/hub.c    |   71 ++++++++++++++++++++++++++++++++++++++------
 drivers/usb/core/usb.h    |    4 ++
 include/linux/usb.h       |    2 +
 include/linux/usb/ch9.h   |   11 ++++++-
 6 files changed, 129 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index b9278a1..38885b6 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1207,6 +1207,19 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 	 * and flush any outstanding URBs.
 	 */
 	} else {
+#ifdef CONFIG_USB_OTG
+		/* According to OTG supplement Rev 2.0 section 6.3
+		 * Unless an A-device enables b_hnp_enable before entering
+		 * suspend it shall also continue polling while the bus is
+		 * suspended.
+		 *
+		 * We don't have to perform HNP polling, as we are going to
+		 * enable b_hnp_enable before suspending.
+		 */
+		if (udev->bus->hnp_support &&
+			udev->portnum == udev->bus->otg_port)
+			cancel_delayed_work(&udev->bus->hnp_polling);
+#endif
 		udev->can_submit = 0;
 		for (i = 0; i < 16; ++i) {
 			usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
@@ -1270,6 +1283,43 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
 	return status;
 }
 
+#ifdef CONFIG_USB_OTG
+void usb_hnp_polling_work(struct work_struct *work)
+{
+	int ret;
+	struct usb_bus *bus =
+		container_of(work, struct usb_bus, hnp_polling.work);
+	struct usb_device *udev = bus->root_hub->children[bus->otg_port - 1];
+	u8 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+
+	if (!status)
+		return;
+
+	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE,
+		0, OTG_STATUS_SELECTOR, status, sizeof(*status),
+		USB_CTRL_GET_TIMEOUT);
+	if (ret < 0) {
+		/* Peripheral may not be supporting HNP polling */
+		dev_vdbg(&udev->dev, "HNP polling failed. status %d\n", ret);
+		goto out;
+	}
+
+	/* Spec says host must suspend the bus with in 2 sec. */
+	if (*status & (1 << HOST_REQUEST_FLAG)) {
+		do_unbind_rebind(udev, DO_UNBIND);
+		ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
+		if (ret)
+			dev_info(&udev->dev, "suspend failed\n");
+	} else {
+		schedule_delayed_work(&bus->hnp_polling,
+			msecs_to_jiffies(THOST_REQ_POLL));
+	}
+out:
+	kfree(status);
+}
+#endif
+
 static void choose_wakeup(struct usb_device *udev, pm_message_t msg)
 {
 	int	w;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e70aeaf..6bffd50 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -869,6 +869,9 @@ static void usb_bus_init (struct usb_bus *bus)
 	bus->bandwidth_isoc_reqs = 0;
 
 	INIT_LIST_HEAD (&bus->bus_list);
+#ifdef CONFIG_USB_OTG
+	INIT_DELAYED_WORK(&bus->hnp_polling, usb_hnp_polling_work);
+#endif
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b98efae..60705a1 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1581,6 +1581,13 @@ void usb_disconnect(struct usb_device **pdev)
 	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
 	dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
 
+#ifdef CONFIG_USB_OTG
+	if (udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) {
+		cancel_delayed_work_sync(&udev->bus->hnp_polling);
+		udev->bus->hnp_support = 0;
+	}
+#endif
+
 	usb_lock_device(udev);
 
 	/* Free up all the children before we remove this device */
@@ -1685,15 +1692,31 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
 					(port1 == bus->otg_port)
 						? "" : "non-");
 
-				/* enable HNP before suspend, it's simpler */
-				if (port1 == bus->otg_port)
-					bus->b_hnp_enable = 1;
+				/* a_alt_hnp_support is obsoleted */
+				if (port1 != bus->otg_port)
+					goto fail;
+
+				bus->hnp_support = 1;
+
+				/* a_hnp_support is not required for devices
+				 * compliant to revision 2.0 or subsequent
+				 * versions.
+				 */
+				if (desc->bLength == sizeof(*desc) &&
+					le16_to_cpu(desc->bcdOTG) >= 0x0200)
+					goto out;
+
+				/* Legacy B-device i.e compliant to spec
+				 * revision 1.3 expect A-device to set
+				 * a_hnp_support or b_hnp_enable before
+				 * selecting configuration. b_hnp_enable
+				 * is set before suspending the port.
+				 */
+
 				err = usb_control_msg(udev,
 					usb_sndctrlpipe(udev, 0),
 					USB_REQ_SET_FEATURE, 0,
-					bus->b_hnp_enable
-						? USB_DEVICE_B_HNP_ENABLE
-						: USB_DEVICE_A_ALT_HNP_SUPPORT,
+					USB_DEVICE_A_HNP_SUPPORT,
 					0, NULL, 0, USB_CTRL_SET_TIMEOUT);
 				if (err < 0) {
 					/* OTG MESSAGE: report errors here,
@@ -1702,24 +1725,32 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
 					dev_info(&udev->dev,
 						"can't set HNP mode: %d\n",
 						err);
-					bus->b_hnp_enable = 0;
+					bus->hnp_support = 0;
 				}
 			}
 		}
 	}
-
+out:
 	if (!is_targeted(udev)) {
 
 		/* Maybe it can talk to us, though we can't talk to it.
 		 * (Includes HNP test device.)
 		 */
-		if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
+		if (udev->bus->hnp_support) {
 			err = usb_port_suspend(udev, PMSG_SUSPEND);
 			if (err < 0)
 				dev_dbg(&udev->dev, "HNP fail, %d\n", err);
 		}
 		err = -ENOTSUPP;
-		goto fail;
+	} else if (udev->bus->hnp_support &&
+			udev->portnum == udev->bus->otg_port) {
+		/* HNP polling is introduced in OTG supplement Rev 2.0
+		 * and older devices does not support. Work is not
+		 * re-armed if device returns STALL. B-Host also performs
+		 * HNP polling.
+		 */
+		schedule_delayed_work(&udev->bus->hnp_polling,
+			msecs_to_jiffies(THOST_REQ_POLL));
 	}
 fail:
 #endif
@@ -2210,6 +2241,21 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 		}
 	}
 
+#ifdef CONFIG_USB_OTG
+	if (!udev->bus->is_b_host && udev->bus->hnp_support &&
+			udev->portnum == udev->bus->otg_port) {
+		status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+				USB_REQ_SET_FEATURE, 0,
+				USB_DEVICE_B_HNP_ENABLE,
+				0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+		if (status < 0)
+			dev_dbg(&udev->dev, "can't enable HNP on port %d, "
+					"status %d\n", port1, status);
+		else
+			udev->bus->b_hnp_enable = 1;
+	}
+#endif
+
 	/* see 7.1.7.6 */
 	status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
 	if (status) {
@@ -2353,6 +2399,11 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 	int		status;
 	u16		portchange, portstatus;
 
+#ifdef CONFIG_USB_OTG
+	if (!udev->bus->is_b_host && udev->bus->hnp_support &&
+			udev->portnum == udev->bus->otg_port)
+		udev->bus->b_hnp_enable = 0;
+#endif
 	/* Skip the initial Clear-Suspend step for a remote wakeup */
 	status = hub_port_status(hub, port1, &portstatus, &portchange);
 	if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND))
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index b975450..cd3cb45 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -72,6 +72,10 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 
 #endif
 
+#ifdef CONFIG_USB_OTG
+extern void usb_hnp_polling_work(struct work_struct *work);
+#endif
+
 #ifdef CONFIG_USB_SUSPEND
 
 extern void usb_autosuspend_device(struct usb_device *udev);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 5ee2223..4ddb8d1 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -317,6 +317,8 @@ struct usb_bus {
 	u8 otg_port;			/* 0, or number of OTG/HNP port */
 	unsigned is_b_host:1;		/* true during some HNP roleswitches */
 	unsigned b_hnp_enable:1;	/* OTG: did A-Host enable HNP? */
+	unsigned hnp_support:1;         /* OTG: HNP is supported on OTG port */
+	struct delayed_work hnp_polling;/* OTG: HNP polling work */
 	unsigned sg_tablesize;		/* 0 or largest number of sg list entries */
 
 	int devnum_next;		/* Next open device number in
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index ab46194..504f8b5 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -151,6 +151,11 @@
 #define USB_DEV_STAT_U2_ENABLED		3	/* transition into U2 state */
 #define USB_DEV_STAT_LTM_ENABLED	4	/* Latency tolerance messages */
 
+/* OTG 2.0 spec 6.2 and 6.3 sections */
+#define OTG_STATUS_SELECTOR		0xF000
+#define THOST_REQ_POLL			1500    /* 1000 - 2000 msec */
+#define HOST_REQUEST_FLAG		0
+
 /**
  * struct usb_ctrlrequest - SETUP data for a USB device control request
  * @bRequestType: matches the USB bmRequestType field
@@ -605,17 +610,19 @@ struct usb_qualifier_descriptor {
 
 /*-------------------------------------------------------------------------*/
 
-/* USB_DT_OTG (from OTG 1.0a supplement) */
+/* USB_DT_OTG (from OTG 2.0 supplement) */
 struct usb_otg_descriptor {
 	__u8  bLength;
 	__u8  bDescriptorType;
 
-	__u8  bmAttributes;	/* support for HNP, SRP, etc */
+	__u8  bmAttributes;	/* support for HNP, SRP, ADP etc */
+	__le16 bcdOTG;
 } __attribute__ ((packed));
 
 /* from usb_otg_descriptor.bmAttributes */
 #define USB_OTG_SRP		(1 << 0)
 #define USB_OTG_HNP		(1 << 1)	/* swap host/device roles */
+#define USB_OTG_ADP		(1 << 2)	/* Attach detection protocol */
 
 /*-------------------------------------------------------------------------*/
 
-- 
1.7.1

--
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

  parent reply	other threads:[~2010-12-15 11:14 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-15 11:14 [RFC 0/5] USB core changes for supporting OTG on MSM SoC Pavankumar Kondeti
2010-12-15 11:14 ` [RFC 1/5] USB: core: Add input prompt and help text for USB_OTG config Pavankumar Kondeti
2010-12-15 12:35   ` Sergei Shtylyov
2010-12-15 21:52   ` Greg KH
2010-12-16  8:53     ` Pavan Kondeti
2010-12-15 11:14 ` Pavankumar Kondeti [this message]
2010-12-15 12:16   ` [RFC 2/5] USB: core: OTG Supplement Revision 2.0 updates Felipe Balbi
2010-12-15 21:39     ` Alan Stern
2010-12-16  8:10       ` Felipe Balbi
2010-12-16  8:54     ` Pavan Kondeti
2010-12-16  9:11       ` Felipe Balbi
2010-12-15 21:29   ` Alan Stern
2010-12-16  8:54     ` Pavan Kondeti
2010-12-15 21:53   ` Greg KH
2010-12-16  8:54     ` Pavan Kondeti
2010-12-15 11:14 ` [RFC 3/5] USB: gadget: OTG supplement revision " Pavankumar Kondeti
2010-12-15 12:18   ` Felipe Balbi
2010-12-16  8:54     ` Pavan Kondeti
2010-12-15 11:14 ` [RFC 4/5] USB: EHCI: Notify HCD about HNP enabled port suspend Pavankumar Kondeti
2010-12-15 12:19   ` Felipe Balbi
2010-12-16  8:54     ` Pavan Kondeti
2010-12-15 11:14 ` [RFC 5/5] USB: Eliminate delays involved in root hub initialization during HNP Pavankumar Kondeti
2010-12-15 12:21   ` Felipe Balbi
2010-12-16 11:26     ` Pavan Kondeti
2010-12-16 12:15       ` Felipe Balbi
2010-12-16 12:53         ` Pavan Kondeti
2010-12-15 21:52   ` Greg KH
2010-12-15 21:38 ` [RFC 0/5] USB core changes for supporting OTG on MSM SoC Alan Stern
2010-12-16  8:55   ` Pavan Kondeti

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1292411654-21382-3-git-send-email-pkondeti@codeaurora.org \
    --to=pkondeti@codeaurora.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).