diff options
Diffstat (limited to 'drivers/usb/core/generic.c')
-rw-r--r-- | drivers/usb/core/generic.c | 38 |
1 files changed, 34 insertions, 4 deletions
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 30ecac3af15a..66e8a424c9f4 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -20,6 +20,8 @@ #include <linux/usb.h> #include "usb.h" #include "hcd.h" +#include <linux/io.h> +#include <linux/fsl_devices.h> static inline const char *plural(int n) { @@ -190,20 +192,40 @@ static void generic_disconnect(struct usb_device *udev) #ifdef CONFIG_PM +extern void usb_host_set_wakeup(struct device *wkup_dev, bool para); static int generic_suspend(struct usb_device *udev, pm_message_t msg) { int rc; + u32 temp; /* Normal USB devices suspend through their upstream port. * Root hubs don't have upstream ports to suspend, * so we have to shut down their downstream HC-to-USB * interfaces manually by doing a bus (or "global") suspend. */ - if (!udev->parent) + if (!udev->parent) { + struct usb_hcd *hcd = + container_of(udev->bus, struct usb_hcd, self); + struct fsl_usb2_platform_data *pdata; + pdata = hcd->self.controller->platform_data; + rc = hcd_bus_suspend(udev, msg); + if (device_may_wakeup(hcd->self.controller)) { + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + /* enable remote wake up irq */ + usb_host_set_wakeup(hcd->self.controller, true); + + /* Put PHY into low power mode */ + temp = readl(hcd->regs + 0x184); + writel(temp | (1 << 23), (hcd->regs + 0x184)); + + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(false); + } /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ - else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + } else if (msg.event == PM_EVENT_FREEZE || + msg.event == PM_EVENT_PRETHAW) rc = 0; else rc = usb_port_suspend(udev, msg); @@ -214,15 +236,23 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) static int generic_resume(struct usb_device *udev, pm_message_t msg) { int rc; + u32 temp; /* Normal USB devices resume/reset through their upstream port. * Root hubs don't have upstream ports to resume or reset, * so we have to start up their downstream HC-to-USB * interfaces manually by doing a bus (or "global") resume. */ - if (!udev->parent) + if (!udev->parent) { + struct usb_hcd *hcd = + container_of(udev->bus, struct usb_hcd, self); + + if (device_may_wakeup(hcd->self.controller)) { + temp = readl(hcd->regs + 0x184); + writel(temp & (~(1 << 23)), (hcd->regs + 0x184)); + } rc = hcd_bus_resume(udev, msg); - else + } else rc = usb_port_resume(udev, msg); return rc; } |