diff options
Diffstat (limited to 'drivers/usb/host/ehci-omap.c')
-rw-r--r-- | drivers/usb/host/ehci-omap.c | 92 |
1 files changed, 76 insertions, 16 deletions
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 028c572..aa63365 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -39,8 +39,13 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/usb/ulpi.h> -#include <plat/usb.h> #include <linux/regulator/consumer.h> +#include <linux/pm_runtime.h> +#include <linux/clk.h> + +#include <plat/omap_hwmod.h> +#include <plat/usb.h> +#include <plat/clock.h> /* EHCI Register Set */ #define EHCI_INSNREG04 (0xA0) @@ -178,11 +183,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) } } - ret = omap_usbhs_enable(dev); - if (ret) { - dev_err(dev, "failed to start usbhs with err %d\n", ret); - goto err_enable; - } + pm_runtime_get_sync(dev->parent); /* * An undocumented "feature" in the OMAP3 EHCI controller, @@ -228,10 +229,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) return 0; err_add_hcd: - omap_usbhs_disable(dev); - -err_enable: - usb_put_hcd(hcd); + pm_runtime_put_sync(dev->parent); err_io: return ret; @@ -252,25 +250,87 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev) struct usb_hcd *hcd = dev_get_drvdata(dev); usb_remove_hcd(hcd); - omap_usbhs_disable(dev); + pm_runtime_put_sync(dev->parent); usb_put_hcd(hcd); return 0; } static void ehci_hcd_omap_shutdown(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); - if (hcd->driver->shutdown) + if (hcd->driver->shutdown) { + pm_runtime_get_sync(dev->parent); hcd->driver->shutdown(hcd); + pm_runtime_put(dev->parent); + } +} + +static int ehci_omap_bus_suspend(struct usb_hcd *hcd) +{ + struct device *dev = hcd->self.controller; + struct ehci_hcd_omap_platform_data *pdata; + struct omap_hwmod *oh; + struct clk *clk; + int ret = 0; + int i; + + dev_dbg(dev, "ehci_omap_bus_suspend\n"); + + ret = ehci_bus_suspend(hcd); + + if (ret != 0) { + dev_dbg(dev, "ehci_omap_bus_suspend failed %d\n", ret); + return ret; + } + + oh = omap_hwmod_lookup(USBHS_EHCI_HWMODNAME); + + omap_hwmod_enable_ioring_wakeup(oh); + + if (dev->parent) + pm_runtime_put_sync(dev->parent); + + /* At the end, disable any external transceiver clocks */ + pdata = dev->platform_data; + for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { + clk = pdata->transceiver_clk[i]; + if (clk) + clk_disable(clk); + } + + return ret; +} + +static int ehci_omap_bus_resume(struct usb_hcd *hcd) +{ + struct device *dev = hcd->self.controller; + struct ehci_hcd_omap_platform_data *pdata; + struct clk *clk; + int i; + + dev_dbg(dev, "ehci_omap_bus_resume\n"); + + /* Re-enable any external transceiver clocks first */ + pdata = dev->platform_data; + for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { + clk = pdata->transceiver_clk[i]; + if (clk) + clk_enable(clk); + } + + if (dev->parent) { + pm_runtime_get_sync(dev->parent); + } + + return ehci_bus_resume(hcd); } static struct platform_driver ehci_hcd_omap_driver = { .probe = ehci_hcd_omap_probe, .remove = ehci_hcd_omap_remove, .shutdown = ehci_hcd_omap_shutdown, - /*.suspend = ehci_hcd_omap_suspend, */ - /*.resume = ehci_hcd_omap_resume, */ .driver = { .name = "ehci-omap", } @@ -315,8 +375,8 @@ static const struct hc_driver ehci_omap_hc_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, + .bus_suspend = ehci_omap_bus_suspend, + .bus_resume = ehci_omap_bus_resume, .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; |