summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikhil Badola <nikhil.badola@freescale.com>2014-04-08 11:10:51 (GMT)
committerXie Xiaobo <xiaobo.xie@nxp.com>2017-09-25 07:25:28 (GMT)
commit2d1cc215eb927198cf4ebe3efaa0abbce4276bc0 (patch)
treee722edec3e7338bec71abb4c4fc87f80dab94bf6
parenta63a9b7c43098220c13361539b4642a8737d9fe9 (diff)
downloadlinux-2d1cc215eb927198cf4ebe3efaa0abbce4276bc0.tar.xz
usb: host: Add Deep Sleep support for USB drv
Saves and Restores USB register context when the system goes to deep sleep and resumes from it. This is required only when USB controller and phys are OFF during Deep Sleep Signed-off-by: Nikhil Badola <nikhil.badola@freescale.com> Signed-off-by: Ramneek Mehresh <ramneek.mehresh@freescale.com> Signed-off-by: yinbo.zhu <yinbo.zhu@nxp.com>
-rw-r--r--drivers/usb/host/ehci-fsl.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index b15263b..dd9a965 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -505,7 +505,43 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
return retval;
}
+
+
+
#ifdef CONFIG_PM
+/* save usb registers */
+static int ehci_fsl_save_context(struct usb_hcd *hcd)
+{
+ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ void __iomem *non_ehci = hcd->regs;
+
+ ehci_fsl->saved_regs = kzalloc(sizeof(struct ehci_regs), GFP_KERNEL);
+ if (!ehci_fsl->saved_regs)
+ return -ENOMEM;
+ _memcpy_fromio(ehci_fsl->saved_regs, ehci->regs,
+ sizeof(struct ehci_regs));
+ ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ return 0;
+
+}
+
+/*Restore usb registers */
+static int ehci_fsl_restore_context(struct usb_hcd *hcd)
+{
+ struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ void __iomem *non_ehci = hcd->regs;
+
+ if (ehci_fsl->saved_regs) {
+ _memcpy_toio(ehci->regs, ehci_fsl->saved_regs,
+ sizeof(struct ehci_regs));
+ out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl);
+ kfree(ehci_fsl->saved_regs);
+ ehci_fsl->saved_regs = NULL;
+ }
+ return 0;
+}
#ifdef CONFIG_PPC_MPC512x
static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)
@@ -680,6 +716,9 @@ static int ehci_fsl_drv_suspend(struct device *dev)
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
device_may_wakeup(dev));
+
+ ehci_fsl_save_context(hcd);
+
if (!fsl_deep_sleep())
return 0;
@@ -693,6 +732,9 @@ static int ehci_fsl_drv_resume(struct device *dev)
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
+
+ ehci_fsl_restore_context(hcd);
+
#if defined(CONFIG_FSL_USB2_OTG) || defined(CONFIG_FSL_USB2_OTG_MODULE)
struct usb_bus host = hcd->self;
#endif