diff options
author | Nikhil Badola <nikhil.badola@freescale.com> | 2014-04-08 11:10:51 (GMT) |
---|---|---|
committer | Xie Xiaobo <xiaobo.xie@nxp.com> | 2017-09-25 07:25:28 (GMT) |
commit | 2d1cc215eb927198cf4ebe3efaa0abbce4276bc0 (patch) | |
tree | e722edec3e7338bec71abb4c4fc87f80dab94bf6 /drivers | |
parent | a63a9b7c43098220c13361539b4642a8737d9fe9 (diff) | |
download | linux-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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/ehci-fsl.c | 42 |
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 |