summaryrefslogtreecommitdiff
path: root/drivers/usb/core/generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/generic.c')
-rw-r--r--drivers/usb/core/generic.c38
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;
}