USB: core: Add support for OTG automated compliance tests

1. Add OTG PET device to TPL. OTG device shall support this
device for allowing compliance automated testing.

2. Add otg_srp_reqd filed to gadget. OTG B-device shall enable
this flag when OTG PET (Protocol and Electrical Tester) that
acts as A-device sends Set Feature TEST_MODE with wIndex high
byte value = 0x06.  OTG PET expects B-device to initiate SRP
after the end of current session.

3. Add otg_vbus_off to usb_bus.  USB core enables this flag
when OTG PET enumerates with bcdDevice[0] field in its Device
Descriptor is equal to 1.  OTG PET expects A-device to turn off
the VBUS with in 5 sec of its disconnection which allows it to
initiate SRP.

3. Add support to identify OTG PET and start HNP quickly.

Change-Id: Ib1f4d835d00ca29ff8f980c94d75a3890507dedc
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 97c5690..5cd6bb1 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1285,10 +1285,20 @@
 	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);
+	u8 *status = NULL;
 
+	/*
+	 * The OTG-B device must hand back the host role to OTG PET
+	 * within 100 msec irrespective of host_request flag.
+	 */
+	if (bus->quick_hnp) {
+		bus->quick_hnp = 0;
+		goto start_hnp;
+	}
+
+	status = kmalloc(sizeof(*status), GFP_KERNEL);
 	if (!status)
-		return;
+		goto reschedule;
 
 	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
 		USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE,
@@ -1300,17 +1310,20 @@
 		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);
-		udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
-		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));
-	}
+	if (!(*status & (1 << HOST_REQUEST_FLAG)))
+		goto reschedule;
+
+start_hnp:
+	do_unbind_rebind(udev, DO_UNBIND);
+	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+	ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
+	if (ret)
+		dev_info(&udev->dev, "suspend failed\n");
+	goto out;
+
+reschedule:
+	schedule_delayed_work(&bus->hnp_polling,
+		msecs_to_jiffies(THOST_REQ_POLL));
 out:
 	kfree(status);
 }
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 4a37dc2..7347c3d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1778,6 +1778,7 @@
 	int err = 0;
 
 #ifdef	CONFIG_USB_OTG
+	bool old_otg = false;
 	/*
 	 * OTG-aware devices on OTG-capable root hubs may be able to use SRP,
 	 * to wake us after we've powered off VBUS; and HNP, switching roles
@@ -1822,6 +1823,7 @@
 				 * a_hnp_support or b_hnp_enable before
 				 * selecting configuration.
 				 */
+				old_otg = true;
 
 				/* enable HNP before suspend, it's simpler */
 				err = usb_control_msg(udev,
@@ -1842,6 +1844,14 @@
 		}
 	}
 out:
+	if ((udev->quirks & USB_QUIRK_OTG_PET)) {
+		if (le16_to_cpu(udev->descriptor.bcdDevice) &
+			OTG_TTST_VBUS_OFF)
+			udev->bus->otg_vbus_off = 1;
+		if (udev->bus->is_b_host || old_otg)
+			udev->bus->quick_hnp = 1;
+	}
+
 	if (!is_targeted(udev)) {
 
 		otg_send_event(OTG_EVENT_DEV_NOT_SUPPORTED);
@@ -1862,8 +1872,12 @@
 		 * re-armed if device returns STALL. B-Host also perform
 		 * HNP polling.
 		 */
-		schedule_delayed_work(&udev->bus->hnp_polling,
-			msecs_to_jiffies(THOST_REQ_POLL));
+		if (udev->bus->quick_hnp)
+			schedule_delayed_work(&udev->bus->hnp_polling,
+				msecs_to_jiffies(OTG_TTST_SUSP));
+		else
+			schedule_delayed_work(&udev->bus->hnp_polling,
+				msecs_to_jiffies(THOST_REQ_POLL));
 	}
 #endif
 	return err;
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index cec4167..7bb6747 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -59,6 +59,11 @@
 	     le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
 		return 0;
 
+	/* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */
+	if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+	     le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
+		return 1;
+
 	/* NOTE: can't use usb_match_id() since interface caches
 	 * aren't set up yet. this is cut/paste from that code.
 	 */
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 81ce6a8..d5a29b3 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -96,6 +96,9 @@
 	/* INTEL VALUE SSD */
 	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Protocol and OTG Electrical Test Device */
+	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_OTG_PET },
+
 	{ }  /* terminating entry must be last */
 };