From f1d94b27b542b35f5c4dac600cea5cdd01214ccb Mon Sep 17 00:00:00 2001 From: Thirupathi Chippakurthy Date: Fri, 2 Sep 2011 17:45:15 +0530 Subject: ux500: usb: core: USB Hub support musb host USB Hub support musb host ST-Ericsson ID: CR 279072 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Signed-off-by: Change-Id: I22ded0d7cadc8d83996336cfe3917e345c48bd45 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/30052 Reviewed-by: Praveena NADAHALLY --- drivers/usb/core/usb.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/usb/core/usb.h') diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 45e8479c377..72c96c376e1 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -1,5 +1,9 @@ #include +#ifdef CONFIG_ARCH_U8500 +extern int usb_device_count; +#endif + /* Functions local to drivers/usb/core/ */ extern int usb_create_sysfs_dev_files(struct usb_device *dev); -- cgit v1.2.3 From d307524e8aae018b18d4b50d0ec82eec71027b7a Mon Sep 17 00:00:00 2001 From: Avinash Kumar Date: Mon, 13 Feb 2012 18:48:47 +0530 Subject: USB: core: OTG Supplement Revision 2.0 updates 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. ST-Ericsson ID: 401192 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: NA Change-Id: I01ea82656e3ea0302613562354521ed4fae5ac5e Signed-off-by: Pavankumar Kondeti Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/48747 Reviewed-by: Praveena NADAHALLY Reviewed-by: QATOOLS Reviewed-by: QABUILD --- drivers/usb/core/driver.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/core/hcd.c | 3 +++ drivers/usb/core/hub.c | 47 ++++++++++++++++++++++++++++++++++++-------- drivers/usb/core/usb.h | 4 +++- include/linux/usb.h | 4 ++++ include/linux/usb/ch9.h | 12 ++++++++++-- 6 files changed, 109 insertions(+), 11 deletions(-) (limited to 'drivers/usb/core/usb.h') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d40ff956881..3f1387e74bf 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 e1282328fc2..ab0d055fe0e 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -897,6 +897,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 0c2bc00cc12..664ab453ea4 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1670,6 +1670,12 @@ void usb_disconnect(struct usb_device **pdev) dev_info(&udev->dev, "USB disconnect, device number %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 */ @@ -1776,15 +1782,10 @@ 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; 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, @@ -1793,24 +1794,34 @@ 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 @@ -2420,6 +2431,20 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); +#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 */ if (hub_is_superspeed(hub->hdev)) status = set_port_feature(hub->hdev, @@ -2574,6 +2599,12 @@ 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 && !port_is_suspended(hub, portstatus)) diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 72c96c376e1..8966c64b7c4 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -77,7 +77,9 @@ 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 25c1cbf75d8..d5f6a763568 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -331,6 +331,10 @@ 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? */ +#ifdef CONFIG_USB_OTG + unsigned hnp_support:1; /* OTG: HNP is supported on OTG port */ + struct delayed_work hnp_polling;/* OTG: HNP polling work */ +#endif 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 3b6f628880f..ed2f6e9a94e 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -152,6 +152,12 @@ #define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */ +#ifdef CONFIG_USB_OTG +/* 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 +#endif /* Bit array elements as returned by the USB_REQ_GET_STATUS request. */ #define USB_DEV_STAT_U1_ENABLED 2 /* transition into U1 state */ #define USB_DEV_STAT_U2_ENABLED 3 /* transition into U2 state */ @@ -651,8 +657,10 @@ struct usb_qualifier_descriptor { struct usb_otg_descriptor { __u8 bLength; __u8 bDescriptorType; - - __u8 bmAttributes; /* support for HNP, SRP, etc */ +#ifdef CONFIG_USB_OTG + __u8 bmAttributes; /* support for HNP, SRP, ADP etc */ + __le16 bcdOTG; +#endif } __attribute__ ((packed)); /* from usb_otg_descriptor.bmAttributes */ -- cgit v1.2.3