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 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'drivers/usb/core/driver.c') 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; -- cgit v1.2.3 From 6f6f2e62d11652601b6dcce4ca521d1b3949d38d Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Fri, 16 Mar 2012 10:45:50 +0100 Subject: USB: Add support for USB OTG 2.0 OTG 2.0 support is provided in Kernel 3.0. Srp related modifications are done in ab8500-usb. ST-Ericsson ID: 401192 ST-Ericsson Linux next: NA ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-10054 Change-Id: I1bf52c8d6f6c4b0bedf5e51004dc72bf52a68020 Signed-off-by: Avinash Kumar Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/49006 Reviewed-by: QATOOLS Reviewed-by: Praveena NADAHALLY Conflicts: drivers/usb/otg/ab8500-usb.c --- drivers/usb/core/driver.c | 1 + drivers/usb/core/hub.c | 137 ++++++++++++++++++++++++++++++++----- drivers/usb/musb/musb_core.c | 7 +- drivers/usb/musb/musb_core.h | 6 +- drivers/usb/musb/musb_gadget.c | 2 + drivers/usb/musb/musb_gadget_ep0.c | 54 ++++++++++++--- drivers/usb/musb/musb_regs.h | 4 +- drivers/usb/musb/ux500.c | 9 ++- drivers/usb/otg/ab8500-usb.c | 22 ++++++ include/linux/usb/gadget.h | 5 ++ 10 files changed, 213 insertions(+), 34 deletions(-) (limited to 'drivers/usb/core/driver.c') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 3f1387e74bf..d0f967fbeb8 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1302,6 +1302,7 @@ void usb_hnp_polling_work(struct work_struct *work) if (ret < 0) { /* Peripheral may not be supporting HNP polling */ dev_vdbg(&udev->dev, "HNP polling failed. status %d\n", ret); + ret = usb_suspend_both(udev, PMSG_USER_SUSPEND); goto out; } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 394bb0eb8ce..8fd2e231770 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -614,7 +614,7 @@ static int hub_hub_status(struct usb_hub *hub, "%s failed (err = %d)\n", __func__, ret); else { *status = le16_to_cpu(hub->status->hub.wHubStatus); - *change = le16_to_cpu(hub->status->hub.wHubChange); + *change = le16_to_cpu(hub->status->hub.wHubChange); ret = 0; } mutex_unlock(&hub->status_mutex); @@ -1670,7 +1670,7 @@ void usb_disconnect(struct usb_device **pdev) dev_info(&udev->dev, "USB disconnect, device number %d\n", udev->devnum); -#ifdef CONFIG_USB_OTG +#ifdef CONFIG_USB_OTG_20 if (udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) { cancel_delayed_work_sync(&udev->bus->hnp_polling); udev->bus->hnp_support = 0; @@ -1754,11 +1754,13 @@ static inline void announce_device(struct usb_device *udev) { } * * Finish enumeration for On-The-Go devices */ + +#ifdef CONFIG_USB_OTG_20 + static int usb_enumerate_device_otg(struct usb_device *udev) { int err = 0; -#ifdef CONFIG_USB_OTG /* * 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 @@ -1782,6 +1784,10 @@ static int usb_enumerate_device_otg(struct usb_device *udev) (port1 == bus->otg_port) ? "" : "non-"); + if (port1 != bus->otg_port) + goto out; + bus->hnp_support = 1; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), USB_REQ_SET_FEATURE, 0, @@ -1811,8 +1817,6 @@ out: 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 @@ -1824,10 +1828,82 @@ out: msecs_to_jiffies(THOST_REQ_POLL)); } fail: + + return err; +} + +#else + +static int usb_enumerate_device_otg(struct usb_device *udev) +{ + int err = 0; + +#ifdef CONFIG_USB_OTG + /* + * 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 + * "host" to "peripheral". The OTG descriptor helps figure this out. + */ + if (!udev->bus->is_b_host + && udev->config + && udev->parent == udev->bus->root_hub) { + struct usb_otg_descriptor *desc = NULL; + struct usb_bus *bus = udev->bus; + + /* descriptor may appear anywhere in config */ + if (__usb_get_extra_descriptor(udev->rawdescriptors[0], + le16_to_cpu(udev->config[0].desc.wTotalLength), + USB_DT_OTG, (void **) &desc) == 0) { + if (desc->bmAttributes & USB_OTG_HNP) { + unsigned port1 = udev->portnum; + + dev_info(&udev->dev, + "Dual-Role OTG device on %sHNP port\n", + (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, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + if (err < 0) { + /* OTG MESSAGE: report errors here, + * customize to match your product. + */ + dev_info(&udev->dev, + "can't set HNP mode: %d\n", + err); + bus->b_hnp_enable = 0; + } + } + } + } + + 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) { + err = usb_port_suspend(udev, PMSG_SUSPEND); + if (err < 0) + dev_dbg(&udev->dev, "HNP fail, %d\n", err); + } + err = -ENOTSUPP; + goto fail; + } +fail: #endif return err; } +#endif /** * usb_enumerate_device - Read device configs/intfs/otg (usbcore-internal) @@ -2431,7 +2507,7 @@ 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 +#ifdef CONFIG_USB_OTG_20 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), @@ -2445,6 +2521,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) udev->bus->b_hnp_enable = 1; } #endif + /* see 7.1.7.6 */ if (hub_is_superspeed(hub->hdev)) status = set_port_feature(hub->hdev, @@ -2599,7 +2676,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) int status; u16 portchange, portstatus; -#ifdef CONFIG_USB_OTG +#ifdef CONFIG_USB_OTG_20 if (!udev->bus->is_b_host && udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) udev->bus->b_hnp_enable = 0; @@ -2796,7 +2873,7 @@ EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); * Between connect detection and reset signaling there must be a delay * of 100ms at least for debounce and power-settling. The corresponding * timer shall restart whenever the downstream port detects a disconnect. - * + * * Apparently there are some bluetooth and irda-dongles and a number of * low-speed devices for which this debounce period may last over a second. * Not covered by the spec - but easy to deal with. @@ -2994,7 +3071,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->tt = &hub->tt; udev->ttport = port1; } - + /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way? * Because device hardware and firmware is sometimes buggy in * this area, and this is how Linux has done it for ages. @@ -3138,7 +3215,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i); usb_ep0_reinit(udev); } - + retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); if (retval < (signed)sizeof(udev->descriptor)) { dev_err(&udev->dev, "device descriptor read/all, error %d\n", @@ -3423,7 +3500,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, goto loop_disable; } } - + /* check for devices running slower than they could */ if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200 && udev->speed == USB_SPEED_FULL @@ -3465,6 +3542,20 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, dev_dbg(hub_dev, "%dmA power budget left\n", status); #ifdef CONFIG_USB_OTG_20 + struct usb_otg_descriptor *desc = NULL; + int ret; + /* descriptor may appear anywhere in config */ + __usb_get_extra_descriptor(udev->rawdescriptors[0], + le16_to_cpu(udev->config[0].desc.wTotalLength), + USB_DT_OTG, (void **) &desc); + + ret = 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 (ret < 0) + dev_dbg(hub_dev, "set feature error\n"); u16 idVendor = le16_to_cpu(udev->descriptor.idVendor); if (idVendor == USB_OTG_TEST_MODE_VID) { @@ -3546,8 +3637,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, break; default: /* is_targeted() will take care for wrong PID */ - dev_dbg(&udev->dev, "OTG TEST_MODE:Wrong - PID %d\n" idProduct); + dev_dbg(&udev->dev, "OTG TEST_MODE:Wrong" + "PID %d\n", idProduct); break; } @@ -3576,7 +3667,7 @@ loop: !(hcd->driver->port_handed_over)(hcd, port1)) dev_err(hub_dev, "unable to enumerate USB device on port %d\n", port1); - + done: hub_port_disable(hub, port1, 1); if (hcd->driver->relinquish_port && !hub->hdev->parent) @@ -3702,7 +3793,7 @@ static void hub_events(void) * EM interference sometimes causes badly * shielded USB devices to be shutdown by * the hub, this hack enables them again. - * Works at least with mouse driver. + * Works at least with mouse driver. */ if (!(portstatus & USB_PORT_STAT_ENABLE) && !connect_change @@ -3740,7 +3831,7 @@ static void hub_events(void) "resume on port %d, status %d\n", i, ret); } - + if (portchange & USB_PORT_STAT_C_OVERCURRENT) { u16 status = 0; u16 unused; @@ -4063,7 +4154,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) if (ret < 0) goto re_enumerate; - + /* Device might have changed firmware (DFU or similar) */ if (descriptors_changed(udev, &descriptor)) { dev_info(&udev->dev, "device firmware changed\n"); @@ -4096,6 +4187,16 @@ static int usb_reset_and_verify_device(struct usb_device *udev) goto re_enumerate; } mutex_unlock(hcd->bandwidth_mutex); + +#ifdef CONFIG_USB_OTG_20 + ret = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, 0, + USB_DEVICE_A_HNP_SUPPORT, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0) + dev_err(&udev->dev, "set feature error\n"); +#endif usb_set_device_state(udev, USB_STATE_CONFIGURED); /* Put interfaces back into the same altsettings as before. @@ -4136,7 +4237,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) done: return 0; - + re_enumerate: hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 4dfb70ebaf6..a1e333dc14d 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -696,6 +696,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, b_host: musb->xceiv->state = OTG_STATE_B_HOST; hcd->self.is_b_host = 1; +#ifdef CONFIG_USB_OTG_20 + musb->g.otg_hnp_reqd = 0; +#endif musb->ignore_disconnect = 0; del_timer(&musb->otg_timer); break; @@ -1730,7 +1733,9 @@ musb_srp_store(struct device *dev, struct device_attribute *attr, { struct musb *musb = dev_to_musb(dev); unsigned short srp; - +#ifdef CONFIG_USB_OTG_20 + musb->xceiv->start_srp(musb->xceiv); +#endif if (sscanf(buf, "%hu", &srp) != 1 || (srp != 1)) { dev_err(dev, "SRP: Value must be 1\n"); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 73fca530aac..b03c486f7c0 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -153,7 +153,10 @@ enum musb_g_ep0_state { #define OTG_TIME_A_WAIT_BCON 1100 /* min 1 second */ #define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */ #define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */ - +#ifdef CONFIG_USB_OTG_20 +#define USB_SUSP_DET_DURATION 5 /* suspend time 5ms */ +#define TTST_SRP 3000 /* max 5 sec */ +#endif /*************************** REGISTER ACCESS ********************************/ @@ -432,7 +435,6 @@ struct musb { unsigned set_address:1; unsigned test_mode:1; unsigned softconnect:1; - u8 address; u8 test_mode_nr; u16 ackpend; /* ep0 */ diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 3cd59f2037a..4d15f74341a 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1662,7 +1662,9 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget) } spin_unlock_irqrestore(&musb->lock, flags); +#ifndef CONFIG_USB_OTG_20 otg_start_srp(musb->xceiv); +#endif spin_lock_irqsave(&musb->lock, flags); /* Block idling for at least 1s */ diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index e40d7647caf..631aab86240 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -45,6 +45,11 @@ /* ep0 is always musb->endpoints[0].ep_in */ #define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) +/* OTG 2.0 Specification 6.2.3 GetStatus commands */ +#ifdef CONFIG_USB_OTG_20 +#define OTG_STATUS_SELECT 0xF +#endif + /* * locking note: we use only the controller lock, for simpler correctness. * It's always held with IRQs blocked. @@ -80,21 +85,33 @@ static int service_tx_status_request( int handled = 1; u8 result[2], epnum = 0; const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; - +#ifdef CONFIG_USB_OTG_20 + unsigned int otg_recip = ctrlrequest->wIndex >> 12; +#endif result[1] = 0; switch (recip) { case USB_RECIP_DEVICE: - result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED; - result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; - if (musb->g.is_otg) { - result[0] |= musb->g.b_hnp_enable - << USB_DEVICE_B_HNP_ENABLE; - result[0] |= musb->g.a_alt_hnp_support - << USB_DEVICE_A_ALT_HNP_SUPPORT; - result[0] |= musb->g.a_hnp_support - << USB_DEVICE_A_HNP_SUPPORT; +#ifdef CONFIG_USB_OTG_20 + if (!(otg_recip == OTG_STATUS_SELECT)) { +#endif + result[0] = musb->is_self_powered << + USB_DEVICE_SELF_POWERED; + result[0] |= musb->may_wakeup << + USB_DEVICE_REMOTE_WAKEUP; + if (musb->g.is_otg) { + result[0] |= musb->g.b_hnp_enable + << USB_DEVICE_B_HNP_ENABLE; + result[0] |= musb->g.a_alt_hnp_support + << USB_DEVICE_A_ALT_HNP_SUPPORT; + result[0] |= musb->g.a_hnp_support + << USB_DEVICE_A_HNP_SUPPORT; + } +#ifdef CONFIG_USB_OTG_20 + } else { + result[0] = 1 & musb->g.otg_hnp_reqd; } +#endif break; case USB_RECIP_INTERFACE: @@ -356,7 +373,22 @@ __acquires(musb->lock) musb->test_mode_nr = MUSB_TEST_PACKET; break; - +#ifdef CONFIG_USB_OTG_20 + case 6: + if (!musb->g.is_otg) + goto stall; + musb->g.otg_srp_reqd = 1; + + mod_timer(&musb->otg_timer, + jiffies + + msecs_to_jiffies(TTST_SRP)); + break; + case 7: + if (!musb->g.is_otg) + goto stall; + musb->g.otg_hnp_reqd = 1; + break; +#endif case 0xc0: /* TEST_FORCE_HS */ pr_debug("TEST_FORCE_HS\n"); diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h index 03f2655af29..1c96cf60907 100644 --- a/drivers/usb/musb/musb_regs.h +++ b/drivers/usb/musb/musb_regs.h @@ -246,7 +246,9 @@ */ #define MUSB_DEVCTL 0x60 /* 8 bit */ - +#ifdef CONFIG_USB_OTG_20 +#define MUSB_MISC 0x61 /* 8 bit */ +#endif /* These are always controlled through the INDEX register */ #define MUSB_TXFIFOSZ 0x62 /* 8-bit (see masks) */ #define MUSB_RXFIFOSZ 0x63 /* 8-bit (see masks) */ diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 589a56f84d6..360131b337f 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -311,11 +311,18 @@ static void ux500_musb_set_vbus(struct musb *musb, int is_on) u8 devctl; unsigned long timeout = jiffies + msecs_to_jiffies(1000); int ret = 1; +#ifdef CONFIG_USB_OTG_20 + int val = 0; +#endif /* HDRC controls CPEN, but beware current surges during device * connect. They can trigger transient overcurrent conditions * that must be ignored. */ - +#ifdef CONFIG_USB_OTG_20 + val = musb_readb(musb->mregs, MUSB_MISC); + val |= 0x1C; + musb_writeb(musb->mregs, MUSB_MISC, val); +#endif devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c index cbb099d6f8e..ba0618cc067 100644 --- a/drivers/usb/otg/ab8500-usb.c +++ b/drivers/usb/otg/ab8500-usb.c @@ -484,6 +484,25 @@ static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) return mA; } +#ifdef CONFIG_USB_OTG_20 +static int ab8500_usb_start_srp(struct otg_transceiver *otg, unsigned mA) +{ + struct ab8500_usb *ab; + if (!otg) + return -ENODEV; + + ab = xceiv_to_ab(otg); + + atomic_notifier_call_chain(&ab->otg.notifier, + USB_EVENT_PREPARE, + &ab->vbus_draw); + + ab8500_usb_peri_phy_en(ab); + + return 0; +} +#endif + static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA) { struct ab8500_usb *ab; @@ -825,6 +844,9 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev) ab->otg.set_peripheral = ab8500_usb_set_peripheral; ab->otg.set_suspend = ab8500_usb_set_suspend; ab->otg.set_power = ab8500_usb_set_power; +#ifdef CONFIG_USB_OTG_20 + ab->otg.start_srp = ab8500_usb_start_srp; +#endif ab->sysfs_flag = true; platform_set_drvdata(pdev, ab); diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index e5c900a3d94..24015dc944a 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -536,6 +536,11 @@ struct usb_gadget { unsigned b_hnp_enable:1; unsigned a_hnp_support:1; unsigned a_alt_hnp_support:1; +#ifdef CONFIG_USB_OTG_20 + unsigned host_request:1; + unsigned otg_hnp_reqd:1; + unsigned otg_srp_reqd:1; +#endif const char *name; struct device dev; }; -- cgit v1.2.3 From 4163a312707d67ece0f787735ca1fdc859d0fa69 Mon Sep 17 00:00:00 2001 From: Sakethram Bommisetti Date: Wed, 29 Feb 2012 10:58:49 +0530 Subject: USB:Enabling autosuspend in Host audio Allowing to suspend the usb bus if the connected device is a USB Audio device. ST-Ericsson ID: 415876 Signed-off-by: Sakethram Bommisetti --- drivers/usb/core/driver.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers/usb/core/driver.c') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d0f967fbeb8..c7f37c0966e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1654,7 +1654,7 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume); /* Internal routine to check whether we may autosuspend a device. */ static int autosuspend_check(struct usb_device *udev) { - int w, i; + int w, i, audio_class = 0; struct usb_interface *intf; /* Fail if autosuspend is disabled, or any interfaces are in use, or @@ -1688,13 +1688,28 @@ static int autosuspend_check(struct usb_device *udev) intf->needs_remote_wakeup) return -EOPNOTSUPP; } + + if (intf->cur_altsetting->desc.bInterfaceClass + == USB_CLASS_AUDIO) { + dev_dbg(&udev->dev, + "audio interface class present\n"); + audio_class = 1; + } } + if (audio_class) { + dev_dbg(&udev->dev, + "disabling remote wakeup for audio class\n"); + udev->do_remote_wakeup = 0; + } else { + if (w && !device_can_wakeup(&udev->dev)) { + dev_dbg(&udev->dev, + "remote wakeup needed for autosuspend\n"); + return -EOPNOTSUPP; + } + udev->do_remote_wakeup = w; + } + } - if (w && !device_can_wakeup(&udev->dev)) { - dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n"); - return -EOPNOTSUPP; - } - udev->do_remote_wakeup = w; return 0; } -- cgit v1.2.3