Merge "USB: core: Add support for OTG automated compliance tests" into msm-3.0
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 */
};
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 583ceb8..60decb6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -322,6 +322,13 @@
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 */
+ unsigned quick_hnp:1; /* OTG: Indiacates if hnp is required
+ irrespective of host_request flag
+ */
+ unsigned otg_vbus_off:1; /* OTG: OTG test device feature bit that
+ * tells A-device to turn off VBUS after
+ * B-device is disconnected.
+ */
struct delayed_work hnp_polling;/* OTG: HNP polling work */
unsigned sg_tablesize; /* 0 or largest number of sg list entries */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index e4ee15c..ea49aa1 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -133,6 +133,12 @@
#define TEST_PACKET 4
#define TEST_FORCE_EN 5
+/* OTG test mode feature bits
+ * See ECN OTG2.0 spec Table 6-8
+ */
+#define TEST_OTG_SRP_REQD 6
+#define TEST_OTG_HNP_REQD 7
+
/*
* New Feature Selectors as added by USB 3.0
* See USB 3.0 spec Table 9-6
@@ -146,9 +152,12 @@
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
-#define OTG_STATUS_SELECTOR 0xF000
+#define OTG_STATUS_SELECTOR 0xF000
+#define HOST_REQUEST_FLAG 0
#define THOST_REQ_POLL 1500 /* msec (1000 - 2000) */
-#define HOST_REQUEST_FLAG 0
+#define OTG_TTST_SUSP 70 /* msec (0 - 100) */
+
+#define OTG_TTST_VBUS_OFF 1
/* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
#define USB_DEV_STAT_U1_ENABLED 2 /* transition into U1 state */
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index a9c1b6a..35c9cd1 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -453,6 +453,9 @@
* only supports HNP on a different root port.
* @b_hnp_enable: OTG device feature flag, indicating that the A-Host
* enabled HNP support.
+ * @host_request: A flag set by user when wishes to take up host role.
+ * @otg_srp_reqd: OTG test mode feature to initiate SRP after the end of
+ * current session.
* @name: Identifies the controller hardware type. Used in diagnostics
* and sometimes configuration.
* @dev: Driver model state for this abstract device.
@@ -488,6 +491,7 @@
unsigned a_hnp_support:1;
unsigned a_alt_hnp_support:1;
unsigned host_request:1;
+ unsigned otg_srp_reqd:1;
const char *name;
struct device dev;
};
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 3e93de7..fb1ca8c 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -30,4 +30,6 @@
descriptor */
#define USB_QUIRK_DELAY_INIT 0x00000040
+#define USB_QUIRK_OTG_PET 0x00000080
+
#endif /* __LINUX_USB_QUIRKS_H */