diff options
author | Jingoo Han <jg1.han@samsung.com> | 2011-11-28 10:56:06 +0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-11-30 15:08:26 +0400 |
commit | b870defebde40d01d951c9affd86c59841757c31 (patch) | |
tree | d9ca825f43d319ddfae2d369471d5862cfd7ae23 /drivers/usb/host/ohci-s3c2410.c | |
parent | cc27c96c2bee93068bfc60ea6b09611d88cef429 (diff) | |
download | linux-b870defebde40d01d951c9affd86c59841757c31.tar.xz |
USB: ohci-s3c2410: add PM support
This patch adds power management support such as suspend and resume
functions.
Signed-off-by: Jingoo Han <jg1.han@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-s3c2410.c')
-rw-r--r-- | drivers/usb/host/ohci-s3c2410.c | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index a1877c47601e..56dcf069246d 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -486,15 +486,66 @@ static int __devexit ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int ohci_hcd_s3c2410_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ohci_hcd *ohci = hcd_to_ohci(hcd); + struct platform_device *pdev = to_platform_device(dev); + unsigned long flags; + int 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. + */ + spin_lock_irqsave(&ohci->lock, flags); + if (ohci->rh_state != OHCI_RH_SUSPENDED) { + rc = -EINVAL; + goto bail; + } + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + s3c2410_stop_hc(pdev); +bail: + spin_unlock_irqrestore(&ohci->lock, flags); + + return rc; +} + +static int ohci_hcd_s3c2410_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + + s3c2410_start_hc(pdev, hcd); + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + ohci_finish_controller_resume(hcd); + + return 0; +} +#else +#define ohci_hcd_s3c2410_drv_suspend NULL +#define ohci_hcd_s3c2410_drv_resume NULL +#endif + +static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = { + .suspend = ohci_hcd_s3c2410_drv_suspend, + .resume = ohci_hcd_s3c2410_drv_resume, +}; + static struct platform_driver ohci_hcd_s3c2410_driver = { .probe = ohci_hcd_s3c2410_drv_probe, .remove = __devexit_p(ohci_hcd_s3c2410_drv_remove), .shutdown = usb_hcd_platform_shutdown, - /*.suspend = ohci_hcd_s3c2410_drv_suspend, */ - /*.resume = ohci_hcd_s3c2410_drv_resume, */ .driver = { .owner = THIS_MODULE, .name = "s3c2410-ohci", + .pm = &ohci_hcd_s3c2410_pm_ops, }, }; |