aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHema HK <hemahk@ti.com>2011-02-28 03:49:34 -0500
committerFelipe Balbi <balbi@ti.com>2011-03-01 04:35:12 -0500
commit7acc6197b76edd0b932a7cbcc6cfad0a8a87f026 (patch)
treea8d2d259791cf0cb236eab4a1c9c17ce19a85bac /drivers
parentda68ccec210c45eb99e461ad31b499b4e7043c41 (diff)
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')
-rw-r--r--drivers/usb/musb/musb_core.c40
-rw-r--r--drivers/usb/musb/musb_gadget.c11
-rw-r--r--drivers/usb/musb/omap2430.c49
3 files changed, 78 insertions, 22 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index bc296557dc1..36376d2b1a7 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1956,6 +1956,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
1956 goto fail0; 1956 goto fail0;
1957 } 1957 }
1958 1958
1959 pm_runtime_use_autosuspend(musb->controller);
1960 pm_runtime_set_autosuspend_delay(musb->controller, 200);
1961 pm_runtime_enable(musb->controller);
1962
1959 spin_lock_init(&musb->lock); 1963 spin_lock_init(&musb->lock);
1960 musb->board_mode = plat->mode; 1964 musb->board_mode = plat->mode;
1961 musb->board_set_power = plat->set_power; 1965 musb->board_set_power = plat->set_power;
@@ -2091,6 +2095,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
2091 if (status < 0) 2095 if (status < 0)
2092 goto fail3; 2096 goto fail3;
2093 2097
2098 pm_runtime_put(musb->controller);
2099
2094 status = musb_init_debugfs(musb); 2100 status = musb_init_debugfs(musb);
2095 if (status < 0) 2101 if (status < 0)
2096 goto fail4; 2102 goto fail4;
@@ -2190,9 +2196,11 @@ static int __exit musb_remove(struct platform_device *pdev)
2190 * - Peripheral mode: peripheral is deactivated (or never-activated) 2196 * - Peripheral mode: peripheral is deactivated (or never-activated)
2191 * - OTG mode: both roles are deactivated (or never-activated) 2197 * - OTG mode: both roles are deactivated (or never-activated)
2192 */ 2198 */
2199 pm_runtime_get_sync(musb->controller);
2193 musb_exit_debugfs(musb); 2200 musb_exit_debugfs(musb);
2194 musb_shutdown(pdev); 2201 musb_shutdown(pdev);
2195 2202
2203 pm_runtime_put(musb->controller);
2196 musb_free(musb); 2204 musb_free(musb);
2197 iounmap(ctrl_base); 2205 iounmap(ctrl_base);
2198 device_init_wakeup(&pdev->dev, 0); 2206 device_init_wakeup(&pdev->dev, 0);
@@ -2378,9 +2386,41 @@ static int musb_resume_noirq(struct device *dev)
2378 return 0; 2386 return 0;
2379} 2387}
2380 2388
2389static int musb_runtime_suspend(struct device *dev)
2390{
2391 struct musb *musb = dev_to_musb(dev);
2392
2393 musb_save_context(musb);
2394
2395 return 0;
2396}
2397
2398static int musb_runtime_resume(struct device *dev)
2399{
2400 struct musb *musb = dev_to_musb(dev);
2401 static int first = 1;
2402
2403 /*
2404 * When pm_runtime_get_sync called for the first time in driver
2405 * init, some of the structure is still not initialized which is
2406 * used in restore function. But clock needs to be
2407 * enabled before any register access, so
2408 * pm_runtime_get_sync has to be called.
2409 * Also context restore without save does not make
2410 * any sense
2411 */
2412 if (!first)
2413 musb_restore_context(musb);
2414 first = 0;
2415
2416 return 0;
2417}
2418
2381static const struct dev_pm_ops musb_dev_pm_ops = { 2419static const struct dev_pm_ops musb_dev_pm_ops = {
2382 .suspend = musb_suspend, 2420 .suspend = musb_suspend,
2383 .resume_noirq = musb_resume_noirq, 2421 .resume_noirq = musb_resume_noirq,
2422 .runtime_suspend = musb_runtime_suspend,
2423 .runtime_resume = musb_runtime_resume,
2384}; 2424};
2385 2425
2386#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops) 2426#define MUSB_DEV_PM_OPS (&musb_dev_pm_ops)
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 2a3aee4e108..5c7b321d395 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1821,6 +1821,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
1821 goto err0; 1821 goto err0;
1822 } 1822 }
1823 1823
1824 pm_runtime_get_sync(musb->controller);
1825
1824 DBG(3, "registering driver %s\n", driver->function); 1826 DBG(3, "registering driver %s\n", driver->function);
1825 1827
1826 if (musb->gadget_driver) { 1828 if (musb->gadget_driver) {
@@ -1885,6 +1887,10 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
1885 } 1887 }
1886 1888
1887 hcd->self.uses_pio_for_control = 1; 1889 hcd->self.uses_pio_for_control = 1;
1890
1891 if (musb->xceiv->last_event == USB_EVENT_NONE)
1892 pm_runtime_put(musb->controller);
1893
1888 } 1894 }
1889 1895
1890 return 0; 1896 return 0;
@@ -1961,6 +1967,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
1961 if (!musb->gadget_driver) 1967 if (!musb->gadget_driver)
1962 return -EINVAL; 1968 return -EINVAL;
1963 1969
1970 if (musb->xceiv->last_event == USB_EVENT_NONE)
1971 pm_runtime_get_sync(musb->controller);
1972
1964 /* 1973 /*
1965 * REVISIT always use otg_set_peripheral() here too; 1974 * REVISIT always use otg_set_peripheral() here too;
1966 * this needs to shut down the OTG engine. 1975 * this needs to shut down the OTG engine.
@@ -2002,6 +2011,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
2002 if (!is_otg_enabled(musb)) 2011 if (!is_otg_enabled(musb))
2003 musb_stop(musb); 2012 musb_stop(musb);
2004 2013
2014 pm_runtime_put(musb->controller);
2015
2005 return 0; 2016 return 0;
2006} 2017}
2007EXPORT_SYMBOL(usb_gadget_unregister_driver); 2018EXPORT_SYMBOL(usb_gadget_unregister_driver);
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index b6dcc7eaa21..47267987077 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,
244 if (is_otg_enabled(musb)) { 244 if (is_otg_enabled(musb)) {
245#ifdef CONFIG_USB_GADGET_MUSB_HDRC 245#ifdef CONFIG_USB_GADGET_MUSB_HDRC
246 if (musb->gadget_driver) { 246 if (musb->gadget_driver) {
247 pm_runtime_get_sync(musb->controller);
247 otg_init(musb->xceiv); 248 otg_init(musb->xceiv);
248 249
249 if (data->interface_type == 250 if (data->interface_type ==
@@ -253,6 +254,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
253 } 254 }
254#endif 255#endif
255 } else { 256 } else {
257 pm_runtime_get_sync(musb->controller);
256 otg_init(musb->xceiv); 258 otg_init(musb->xceiv);
257 if (data->interface_type == 259 if (data->interface_type ==
258 MUSB_INTERFACE_UTMI) 260 MUSB_INTERFACE_UTMI)
@@ -263,12 +265,24 @@ static int musb_otg_notifications(struct notifier_block *nb,
263 case USB_EVENT_VBUS: 265 case USB_EVENT_VBUS:
264 DBG(4, "VBUS Connect\n"); 266 DBG(4, "VBUS Connect\n");
265 267
268 if (musb->gadget_driver)
269 pm_runtime_get_sync(musb->controller);
270
266 otg_init(musb->xceiv); 271 otg_init(musb->xceiv);
267 break; 272 break;
268 273
269 case USB_EVENT_NONE: 274 case USB_EVENT_NONE:
270 DBG(4, "VBUS Disconnect\n"); 275 DBG(4, "VBUS Disconnect\n");
271 276
277#ifdef CONFIG_USB_GADGET_MUSB_HDRC
278 if (is_otg_enabled(musb))
279 if (musb->gadget_driver)
280#endif
281 {
282 pm_runtime_mark_last_busy(musb->controller);
283 pm_runtime_put_autosuspend(musb->controller);
284 }
285
272 if (data->interface_type == MUSB_INTERFACE_UTMI) { 286 if (data->interface_type == MUSB_INTERFACE_UTMI) {
273 if (musb->xceiv->set_vbus) 287 if (musb->xceiv->set_vbus)
274 otg_set_vbus(musb->xceiv, 0); 288 otg_set_vbus(musb->xceiv, 0);
@@ -300,7 +314,11 @@ static int omap2430_musb_init(struct musb *musb)
300 return -ENODEV; 314 return -ENODEV;
301 } 315 }
302 316
303 omap2430_low_level_init(musb); 317 status = pm_runtime_get_sync(dev);
318 if (status < 0) {
319 dev_err(dev, "pm_runtime_get_sync FAILED");
320 goto err1;
321 }
304 322
305 l = musb_readl(musb->mregs, OTG_INTERFSEL); 323 l = musb_readl(musb->mregs, OTG_INTERFSEL);
306 324
@@ -331,6 +349,10 @@ static int omap2430_musb_init(struct musb *musb)
331 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); 349 setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
332 350
333 return 0; 351 return 0;
352
353err1:
354 pm_runtime_disable(dev);
355 return status;
334} 356}
335 357
336static void omap2430_musb_enable(struct musb *musb) 358static void omap2430_musb_enable(struct musb *musb)
@@ -407,8 +429,6 @@ static int __init omap2430_probe(struct platform_device *pdev)
407 struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; 429 struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
408 struct platform_device *musb; 430 struct platform_device *musb;
409 struct omap2430_glue *glue; 431 struct omap2430_glue *glue;
410 int status = 0;
411
412 int ret = -ENOMEM; 432 int ret = -ENOMEM;
413 433
414 glue = kzalloc(sizeof(*glue), GFP_KERNEL); 434 glue = kzalloc(sizeof(*glue), GFP_KERNEL);
@@ -454,16 +474,9 @@ static int __init omap2430_probe(struct platform_device *pdev)
454 } 474 }
455 475
456 pm_runtime_enable(&pdev->dev); 476 pm_runtime_enable(&pdev->dev);
457 status = pm_runtime_get_sync(&pdev->dev);
458 if (status < 0) {
459 dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
460 goto err3;
461 }
462 477
463 return 0; 478 return 0;
464 479
465err3:
466 pm_runtime_disable(&pdev->dev);
467err2: 480err2:
468 platform_device_put(musb); 481 platform_device_put(musb);
469 482
@@ -489,7 +502,7 @@ static int __exit omap2430_remove(struct platform_device *pdev)
489 502
490#ifdef CONFIG_PM 503#ifdef CONFIG_PM
491 504
492static int omap2430_suspend(struct device *dev) 505static int omap2430_runtime_suspend(struct device *dev)
493{ 506{
494 struct omap2430_glue *glue = dev_get_drvdata(dev); 507 struct omap2430_glue *glue = dev_get_drvdata(dev);
495 struct musb *musb = glue_to_musb(glue); 508 struct musb *musb = glue_to_musb(glue);
@@ -497,22 +510,14 @@ static int omap2430_suspend(struct device *dev)
497 omap2430_low_level_exit(musb); 510 omap2430_low_level_exit(musb);
498 otg_set_suspend(musb->xceiv, 1); 511 otg_set_suspend(musb->xceiv, 1);
499 512
500 if (!pm_runtime_suspended(dev) && dev->bus && dev->bus->pm &&
501 dev->bus->pm->runtime_suspend)
502 dev->bus->pm->runtime_suspend(dev);
503
504 return 0; 513 return 0;
505} 514}
506 515
507static int omap2430_resume(struct device *dev) 516static int omap2430_runtime_resume(struct device *dev)
508{ 517{
509 struct omap2430_glue *glue = dev_get_drvdata(dev); 518 struct omap2430_glue *glue = dev_get_drvdata(dev);
510 struct musb *musb = glue_to_musb(glue); 519 struct musb *musb = glue_to_musb(glue);
511 520
512 if (!pm_runtime_suspended(dev) && dev->bus && dev->bus->pm &&
513 dev->bus->pm->runtime_resume)
514 dev->bus->pm->runtime_resume(dev);
515
516 omap2430_low_level_init(musb); 521 omap2430_low_level_init(musb);
517 otg_set_suspend(musb->xceiv, 0); 522 otg_set_suspend(musb->xceiv, 0);
518 523
@@ -520,8 +525,8 @@ static int omap2430_resume(struct device *dev)
520} 525}
521 526
522static struct dev_pm_ops omap2430_pm_ops = { 527static struct dev_pm_ops omap2430_pm_ops = {
523 .suspend = omap2430_suspend, 528 .runtime_suspend = omap2430_runtime_suspend,
524 .resume = omap2430_resume, 529 .runtime_resume = omap2430_runtime_resume,
525}; 530};
526 531
527#define DEV_PM_OPS (&omap2430_pm_ops) 532#define DEV_PM_OPS (&omap2430_pm_ops)