diff options
author | Manuel Lauss <mano@roarinelk.homelinux.net> | 2008-06-23 09:09:37 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-07-21 15:16:44 -0700 |
commit | 42bfc7b44f724fb5ce838fc2f552a3eb8cd768ec (patch) | |
tree | d97b0ca257dbadd4fafc6c55cef742d877d78d07 /drivers/usb/host/ohci-au1xxx.c | |
parent | 53c81a348fa1d21dd042d9c9a9f91795f83fed66 (diff) |
USB: Au1xxx-usb: suspend/resume support.
Copy the OHCI/EHCI PM callbacks of the PCI implementation since
they work equally well on Au1xxx hardware.
Tested on Au1200.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-au1xxx.c')
-rw-r--r-- | drivers/usb/host/ohci-au1xxx.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 29c970ad487..c0948008fe3 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -248,27 +248,68 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev) return 0; } - /*TBD*/ -/*static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *dev) +#ifdef CONFIG_PM +static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *pdev, + pm_message_t message) { - struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + unsigned long flags; + int rc; + + rc = 0; + + /* Root hub was already suspended. Disable irq emission and + * mark HW unaccessible, bail out if RH has been resumed. Use + * the spinlock to properly synchronize with possible pending + * RH suspend or resume activity. + * + * This is still racy as hcd->state is manipulated outside of + * any locks =P But that will be a different fix. + */ + spin_lock_irqsave(&ohci->lock, flags); + if (hcd->state != HC_STATE_SUSPENDED) { + rc = -EINVAL; + goto bail; + } + ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); + (void)ohci_readl(ohci, &ohci->regs->intrdisable); - return 0; + /* make sure snapshot being resumed re-enumerates everything */ + if (message.event == PM_EVENT_PRETHAW) + ohci_usb_reset(ohci); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + au1xxx_stop_ohc(); +bail: + spin_unlock_irqrestore(&ohci->lock, flags); + + return rc; } -static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev) + +static int ohci_hcd_au1xxx_drv_resume(struct platform_device *pdev) { - struct usb_hcd *hcd = platform_get_drvdata(dev); + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + au1xxx_start_ohc(); + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + ohci_finish_controller_resume(hcd); return 0; } -*/ +#else +#define ohci_hcd_au1xxx_drv_suspend NULL +#define ohci_hcd_au1xxx_drv_resume NULL +#endif static struct platform_driver ohci_hcd_au1xxx_driver = { .probe = ohci_hcd_au1xxx_drv_probe, .remove = ohci_hcd_au1xxx_drv_remove, .shutdown = usb_hcd_platform_shutdown, - /*.suspend = ohci_hcd_au1xxx_drv_suspend, */ - /*.resume = ohci_hcd_au1xxx_drv_resume, */ + .suspend = ohci_hcd_au1xxx_drv_suspend, + .resume = ohci_hcd_au1xxx_drv_resume, .driver = { .name = "au1xxx-ohci", .owner = THIS_MODULE, |