@@ -1956,6 +1956,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
goto fail0;
}
+ pm_runtime_use_autosuspend(musb->controller);
+ pm_runtime_set_autosuspend_delay(musb->controller, 200);
+ pm_runtime_enable(musb->controller);
+
spin_lock_init(&musb->lock);
musb->board_mode = plat->mode;
musb->board_set_power = plat->set_power;
@@ -2091,6 +2095,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (status < 0)
goto fail3;
+ pm_runtime_put(musb->controller);
+
status = musb_init_debugfs(musb);
if (status < 0)
goto fail4;
@@ -2190,9 +2196,11 @@ static int __exit musb_remove(struct platform_device *pdev)
* - Peripheral mode: peripheral is deactivated (or never-activated)
* - OTG mode: both roles are deactivated (or never-activated)
*/
+ pm_runtime_get_sync(musb->controller);
musb_exit_debugfs(musb);
musb_shutdown(pdev);
+ pm_runtime_put(musb->controller);
musb_free(musb);
iounmap(ctrl_base);
device_init_wakeup(&pdev->dev, 0);
@@ -2378,9 +2386,41 @@ static int musb_resume_noirq(struct device *dev)
return 0;
}
+static int musb_runtime_suspend(struct device *dev)
+{
+ struct musb *musb = dev_to_musb(dev);
+
+ musb_save_context(musb);
+
+ return 0;
+}
+
+static int musb_runtime_resume(struct device *dev)
+{
+ struct musb *musb = dev_to_musb(dev);
+ static int first = 1;
+
+ /*
+ * When pm_runtime_get_sync called for the first time in driver
+ * init, some of the structure is still not initialized which is
+ * used in restore function. But clock needs to be
+ * enabled before any register access, so
+ * pm_runtime_get_sync has to be called.
+ * Also context restore without save does not make
+ * any sense
+ */
+ if (!first)
+ musb_restore_context(musb);
+ first = 0;
+
+ return 0;
+}
+
static const struct dev_pm_ops musb_dev_pm_ops = {
.suspend = musb_suspend,
.resume_noirq = musb_resume_noirq,
+ .runtime_suspend = musb_runtime_suspend,
+ .runtime_resume = musb_runtime_resume,
};
#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops)
@@ -1820,6 +1820,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
goto err0;
}
+ pm_runtime_get_sync(musb->controller);
+
DBG(3, "registering driver %s\n", driver->function);
if (musb->gadget_driver) {
@@ -1884,6 +1886,10 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
}
hcd->self.uses_pio_for_control = 1;
+
+ if (musb->xceiv->last_event == USB_EVENT_NONE)
+ pm_runtime_put(musb->controller);
+
}
return 0;
@@ -1960,6 +1966,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!musb->gadget_driver)
return -EINVAL;
+ if (musb->xceiv->last_event == USB_EVENT_NONE)
+ pm_runtime_get_sync(musb->controller);
+
/*
* REVISIT always use otg_set_peripheral() here too;
* this needs to shut down the OTG engine.
@@ -2001,6 +2010,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!is_otg_enabled(musb))
musb_stop(musb);
+ pm_runtime_put(musb->controller);
+
return 0;
}
EXPORT_SYMBOL(usb_gadget_unregister_driver);
@@ -244,6 +244,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
if (is_otg_enabled(musb)) {
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
if (musb->gadget_driver) {
+ pm_runtime_get_sync(musb->controller);
otg_init(musb->xceiv);
if (data->interface_type ==
@@ -253,6 +254,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
}
#endif
} else {
+ pm_runtime_get_sync(musb->controller);
otg_init(musb->xceiv);
if (data->interface_type ==
MUSB_INTERFACE_UTMI)
@@ -263,12 +265,24 @@ static int musb_otg_notifications(struct notifier_block *nb,
case USB_EVENT_VBUS:
DBG(4, "VBUS Connect\n");
+ if (musb->gadget_driver)
+ pm_runtime_get_sync(musb->controller);
+
otg_init(musb->xceiv);
break;
case USB_EVENT_NONE:
DBG(4, "VBUS Disconnect\n");
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+ if (is_otg_enabled(musb))
+ if (musb->gadget_driver)
+#endif
+ {
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
+ }
+
if (data->interface_type == MUSB_INTERFACE_UTMI) {
if (musb->xceiv->set_vbus)
otg_set_vbus(musb->xceiv, 0);
@@ -300,7 +314,12 @@ static int omap2430_musb_init(struct musb *musb)
return -ENODEV;
}
- omap2430_low_level_init(musb);
+ status = pm_runtime_get_sync(dev);
+ if (status < 0) {
+ dev_err(dev, "pm_runtime_get_sync FAILED");
+ pm_runtime_disable(dev);
+ return -EINVAL;
+ }
l = musb_readl(musb->mregs, OTG_INTERFSEL);
@@ -454,16 +473,9 @@ static int __init omap2430_probe(struct platform_device *pdev)
}
pm_runtime_enable(&pdev->dev);
- status = pm_runtime_get_sync(&pdev->dev);
- if (status < 0) {
- dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
- goto err3;
- }
return 0;
-err3:
- pm_runtime_disable(&pdev->dev);
err2:
platform_device_put(musb);
@@ -489,7 +501,7 @@ static int __exit omap2430_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
-static int omap2430_suspend(struct device *dev)
+static int omap2430_runtime_suspend(struct device *dev)
{
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
@@ -497,22 +509,14 @@ static int omap2430_suspend(struct device *dev)
omap2430_low_level_exit(musb);
otg_set_suspend(musb->xceiv, 1);
- if (!pm_runtime_suspended(dev) && dev->bus && dev->bus->pm &&
- dev->bus->pm->runtime_suspend)
- dev->bus->pm->runtime_suspend(dev);
-
return 0;
}
-static int omap2430_resume(struct device *dev)
+static int omap2430_runtime_resume(struct device *dev)
{
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- if (!pm_runtime_suspended(dev) && dev->bus && dev->bus->pm &&
- dev->bus->pm->runtime_resume)
- dev->bus->pm->runtime_resume(dev);
-
omap2430_low_level_init(musb);
otg_set_suspend(musb->xceiv, 0);
@@ -520,8 +524,8 @@ static int omap2430_resume(struct device *dev)
}
static struct dev_pm_ops omap2430_pm_ops = {
- .suspend = omap2430_suspend,
- .resume = omap2430_resume,
+ .runtime_suspend = omap2430_runtime_suspend,
+ .runtime_resume = omap2430_runtime_resume,
};
#define DEV_PM_OPS (&omap2430_pm_ops)