aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/musb/omap2430.c
diff options
context:
space:
mode:
authorHema HK <hemahk@ti.com>2011-02-28 14:19:34 +0530
committerFelipe Balbi <balbi@ti.com>2011-03-01 11:35:12 +0200
commit7acc6197b76edd0b932a7cbcc6cfad0a8a87f026 (patch)
treea8d2d259791cf0cb236eab4a1c9c17ce19a85bac /drivers/usb/musb/omap2430.c
parentda68ccec210c45eb99e461ad31b499b4e7043c41 (diff)
downloadkernel_samsung_smdk4412-7acc6197b76edd0b932a7cbcc6cfad0a8a87f026.zip
kernel_samsung_smdk4412-7acc6197b76edd0b932a7cbcc6cfad0a8a87f026.tar.gz
kernel_samsung_smdk4412-7acc6197b76edd0b932a7cbcc6cfad0a8a87f026.tar.bz2
usb: musb: Idle path retention and offmode support for OMAP3
This patch supports the retention and offmode support in the idle path for musb driver using runtime pm APIs. This is restricted to support offmode and retention only when device not connected.When device/cable connected with gadget driver loaded,configured to no idle/standby which will not allow the core transition to retention or off. There is no context save/restore done by hardware for musb in OMAP3 and OMAP4,driver has to take care of saving and restoring the context during offmode. Musb has a requirement of configuring sysconfig register to force idle/standby mode and set the ENFORCE bit in module STANDBY register for retention and offmode support. Runtime pm and hwmod frameworks will take care of configuring to force idle/standby when pm_runtime_put_sync is called and back to no idle/standby when pm_runeime_get_sync is called. Compile, boot tested and also tested the retention in the idle path on OMAP3630Zoom3. And tested the global suspend/resume with offmode enabled. Usb basic functionality tested on OMAP4430SDP. There is some problem with idle path offmode in mainline, I could not test with offmode. But I have tested this patch with resetting the controller in the idle path when wakeup from retention just to make sure that the context is lost, and restore path is working fine. Removed .suspend/.resume fnction pointers and functions because there is no need of having these functions as all required work is done at runtime in the driver. There is no need to call the runtime pm api with glue driver device as glue layer device is the parent of musb core device, when runtime apis are called for the child, parent device runtime functionality will be invoked. Design overview: pm_runtime_get_sync: When called with musb core device takes care of enabling the clock, calling runtime callback function of omap2430 glue layer, runtime call back of musb driver and configure the musb sysconfig to no idle/standby pm_runtime_put: Takes care of calling runtime callback function of omap2430 glue layer, runtime call back of musb driver, Configure the musb sysconfig to force idle/standby and disable the clock. During musb driver load: Call pm_runtime_get_sync. End of musb driver load: Call pm_runtime_put During gadget driver load: Call pm_runtime_get_sync, End of gadget driver load: Call pm_runtime_put if there is no device or cable is connected. During unload of the gadget driver:Call pm_runtime_get_sync if cable/device is not connected. End of the gadget driver unload : pm_runtime_put During unload of musb driver : Call pm_runtime_get_sync End of unload: Call pm_runtime_put On connect of usb cable/device -> transceiver notification(VBUS and ID-GND): pm_runtime_get_sync only if the gadget driver loaded. On disconnect of the cable/device -> Disconnect Notification: pm_runtime_put if the gadget driver is loaded. Signed-off-by: Hema HK <hemahk@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/musb/omap2430.c')
-rw-r--r--drivers/usb/musb/omap2430.c49
1 files changed, 27 insertions, 22 deletions
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index b6dcc7e..4726798 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -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,11 @@ 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");
+ goto err1;
+ }
l = musb_readl(musb->mregs, OTG_INTERFSEL);
@@ -331,6 +349,10 @@ static int omap2430_musb_init(struct musb *musb)
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
return 0;
+
+err1:
+ pm_runtime_disable(dev);
+ return status;
}
static void omap2430_musb_enable(struct musb *musb)
@@ -407,8 +429,6 @@ static int __init omap2430_probe(struct platform_device *pdev)
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
struct omap2430_glue *glue;
- int status = 0;
-
int ret = -ENOMEM;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
@@ -454,16 +474,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 +502,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 +510,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 +525,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)