aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/otg
diff options
context:
space:
mode:
authorPavankumar Kondeti <pkondeti@codeaurora.org>2010-12-07 07:23:58 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-12-10 17:23:32 -0500
commit87c0104af742af2acfcbd685f2b9a40f33770dc0 (patch)
treef17e999013e443ec70bb4c05a79a44c6ae52054f /drivers/usb/otg
parent8bb6a164b906bb7ca319202f85b30e3ef096cd65 (diff)
USB: OTG: msm: Add support for power management
Implement runtime and system pm ops to put hardware into low power mode (LPM). As part of LPM, USB clocks are turned off, PHY is put into suspend state and PHY comparators are turned off if VBUS/Id notifications are not required from PHY. Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r--drivers/usb/otg/Kconfig5
-rw-r--r--drivers/usb/otg/msm72k_otg.c283
2 files changed, 282 insertions, 6 deletions
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 915c729872f8..2810c2af71b0 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -88,7 +88,8 @@ config USB_MSM_OTG_72K
88 help 88 help
89 Enable this to support the USB OTG transceiver on MSM chips. It 89 Enable this to support the USB OTG transceiver on MSM chips. It
90 handles PHY initialization, clock management, and workarounds 90 handles PHY initialization, clock management, and workarounds
91 required after resetting the hardware. This driver is required 91 required after resetting the hardware and power management.
92 even for peripheral only or host only mode configuration. 92 This driver is required even for peripheral only or host only
93 mode configurations.
93 94
94endif # USB || OTG 95endif # USB || OTG
diff --git a/drivers/usb/otg/msm72k_otg.c b/drivers/usb/otg/msm72k_otg.c
index 46f468a912f4..1cd52edcd0c2 100644
--- a/drivers/usb/otg/msm72k_otg.c
+++ b/drivers/usb/otg/msm72k_otg.c
@@ -29,6 +29,7 @@
29#include <linux/uaccess.h> 29#include <linux/uaccess.h>
30#include <linux/debugfs.h> 30#include <linux/debugfs.h>
31#include <linux/seq_file.h> 31#include <linux/seq_file.h>
32#include <linux/pm_runtime.h>
32 33
33#include <linux/usb.h> 34#include <linux/usb.h>
34#include <linux/usb/otg.h> 35#include <linux/usb/otg.h>
@@ -251,6 +252,154 @@ static int msm_otg_reset(struct otg_transceiver *otg)
251 return 0; 252 return 0;
252} 253}
253 254
255#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
256static int msm_otg_suspend(struct msm_otg *motg)
257{
258 struct otg_transceiver *otg = &motg->otg;
259 struct usb_bus *bus = otg->host;
260 struct msm_otg_platform_data *pdata = motg->pdata;
261 int cnt = 0;
262
263 if (atomic_read(&motg->in_lpm))
264 return 0;
265
266 disable_irq(motg->irq);
267 /*
268 * Interrupt Latch Register auto-clear feature is not present
269 * in all PHY versions. Latch register is clear on read type.
270 * Clear latch register to avoid spurious wakeup from
271 * low power mode (LPM).
272 */
273 ulpi_read(otg, 0x14);
274
275 /*
276 * PHY comparators are disabled when PHY enters into low power
277 * mode (LPM). Keep PHY comparators ON in LPM only when we expect
278 * VBUS/Id notifications from USB PHY. Otherwise turn off USB
279 * PHY comparators. This save significant amount of power.
280 */
281 if (pdata->otg_control == OTG_PHY_CONTROL)
282 ulpi_write(otg, 0x01, 0x30);
283
284 /*
285 * PLL is not turned off when PHY enters into low power mode (LPM).
286 * Disable PLL for maximum power savings.
287 */
288 ulpi_write(otg, 0x08, 0x09);
289
290 /*
291 * PHY may take some time or even fail to enter into low power
292 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
293 * in failure case.
294 */
295 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
296 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
297 if (readl(USB_PORTSC) & PORTSC_PHCD)
298 break;
299 udelay(1);
300 cnt++;
301 }
302
303 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
304 dev_err(otg->dev, "Unable to suspend PHY\n");
305 msm_otg_reset(otg);
306 enable_irq(motg->irq);
307 return -ETIMEDOUT;
308 }
309
310 /*
311 * PHY has capability to generate interrupt asynchronously in low
312 * power mode (LPM). This interrupt is level triggered. So USB IRQ
313 * line must be disabled till async interrupt enable bit is cleared
314 * in USBCMD register. Assert STP (ULPI interface STOP signal) to
315 * block data communication from PHY.
316 */
317 writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD);
318
319 clk_disable(motg->pclk);
320 clk_disable(motg->clk);
321 if (motg->core_clk)
322 clk_disable(motg->core_clk);
323
324 if (device_may_wakeup(otg->dev))
325 enable_irq_wake(motg->irq);
326 if (bus)
327 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
328
329 atomic_set(&motg->in_lpm, 1);
330 enable_irq(motg->irq);
331
332 dev_info(otg->dev, "USB in low power mode\n");
333
334 return 0;
335}
336
337#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
338static int msm_otg_resume(struct msm_otg *motg)
339{
340 struct otg_transceiver *otg = &motg->otg;
341 struct usb_bus *bus = otg->host;
342 int cnt = 0;
343 unsigned temp;
344
345 if (!atomic_read(&motg->in_lpm))
346 return 0;
347
348 clk_enable(motg->pclk);
349 clk_enable(motg->clk);
350 if (motg->core_clk)
351 clk_enable(motg->core_clk);
352
353 temp = readl(USB_USBCMD);
354 temp &= ~ASYNC_INTR_CTRL;
355 temp &= ~ULPI_STP_CTRL;
356 writel(temp, USB_USBCMD);
357
358 /*
359 * PHY comes out of low power mode (LPM) in case of wakeup
360 * from asynchronous interrupt.
361 */
362 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
363 goto skip_phy_resume;
364
365 writel(readl(USB_PORTSC) & ~PORTSC_PHCD, USB_PORTSC);
366 while (cnt < PHY_RESUME_TIMEOUT_USEC) {
367 if (!(readl(USB_PORTSC) & PORTSC_PHCD))
368 break;
369 udelay(1);
370 cnt++;
371 }
372
373 if (cnt >= PHY_RESUME_TIMEOUT_USEC) {
374 /*
375 * This is a fatal error. Reset the link and
376 * PHY. USB state can not be restored. Re-insertion
377 * of USB cable is the only way to get USB working.
378 */
379 dev_err(otg->dev, "Unable to resume USB."
380 "Re-plugin the cable\n");
381 msm_otg_reset(otg);
382 }
383
384skip_phy_resume:
385 if (device_may_wakeup(otg->dev))
386 disable_irq_wake(motg->irq);
387 if (bus)
388 set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
389
390 if (motg->async_int) {
391 motg->async_int = 0;
392 pm_runtime_put(otg->dev);
393 enable_irq(motg->irq);
394 }
395
396 atomic_set(&motg->in_lpm, 0);
397
398 dev_info(otg->dev, "USB exited from low power mode\n");
399
400 return 0;
401}
402
254static void msm_otg_start_host(struct otg_transceiver *otg, int on) 403static void msm_otg_start_host(struct otg_transceiver *otg, int on)
255{ 404{
256 struct msm_otg *motg = container_of(otg, struct msm_otg, otg); 405 struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
@@ -306,6 +455,7 @@ static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
306 455
307 if (!host) { 456 if (!host) {
308 if (otg->state == OTG_STATE_A_HOST) { 457 if (otg->state == OTG_STATE_A_HOST) {
458 pm_runtime_get_sync(otg->dev);
309 msm_otg_start_host(otg, 0); 459 msm_otg_start_host(otg, 0);
310 otg->host = NULL; 460 otg->host = NULL;
311 otg->state = OTG_STATE_UNDEFINED; 461 otg->state = OTG_STATE_UNDEFINED;
@@ -327,8 +477,10 @@ static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
327 * Kick the state machine work, if peripheral is not supported 477 * Kick the state machine work, if peripheral is not supported
328 * or peripheral is already registered with us. 478 * or peripheral is already registered with us.
329 */ 479 */
330 if (motg->pdata->mode == USB_HOST || otg->gadget) 480 if (motg->pdata->mode == USB_HOST || otg->gadget) {
481 pm_runtime_get_sync(otg->dev);
331 schedule_work(&motg->sm_work); 482 schedule_work(&motg->sm_work);
483 }
332 484
333 return 0; 485 return 0;
334} 486}
@@ -376,6 +528,7 @@ static int msm_otg_set_peripheral(struct otg_transceiver *otg,
376 528
377 if (!gadget) { 529 if (!gadget) {
378 if (otg->state == OTG_STATE_B_PERIPHERAL) { 530 if (otg->state == OTG_STATE_B_PERIPHERAL) {
531 pm_runtime_get_sync(otg->dev);
379 msm_otg_start_peripheral(otg, 0); 532 msm_otg_start_peripheral(otg, 0);
380 otg->gadget = NULL; 533 otg->gadget = NULL;
381 otg->state = OTG_STATE_UNDEFINED; 534 otg->state = OTG_STATE_UNDEFINED;
@@ -393,8 +546,10 @@ static int msm_otg_set_peripheral(struct otg_transceiver *otg,
393 * Kick the state machine work, if host is not supported 546 * Kick the state machine work, if host is not supported
394 * or host is already registered with us. 547 * or host is already registered with us.
395 */ 548 */
396 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) 549 if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
550 pm_runtime_get_sync(otg->dev);
397 schedule_work(&motg->sm_work); 551 schedule_work(&motg->sm_work);
552 }
398 553
399 return 0; 554 return 0;
400} 555}
@@ -473,6 +628,7 @@ static void msm_otg_sm_work(struct work_struct *w)
473 msm_otg_start_peripheral(otg, 1); 628 msm_otg_start_peripheral(otg, 1);
474 otg->state = OTG_STATE_B_PERIPHERAL; 629 otg->state = OTG_STATE_B_PERIPHERAL;
475 } 630 }
631 pm_runtime_put_sync(otg->dev);
476 break; 632 break;
477 case OTG_STATE_B_PERIPHERAL: 633 case OTG_STATE_B_PERIPHERAL:
478 dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n"); 634 dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
@@ -504,6 +660,13 @@ static irqreturn_t msm_otg_irq(int irq, void *data)
504 struct otg_transceiver *otg = &motg->otg; 660 struct otg_transceiver *otg = &motg->otg;
505 u32 otgsc = 0; 661 u32 otgsc = 0;
506 662
663 if (atomic_read(&motg->in_lpm)) {
664 disable_irq_nosync(irq);
665 motg->async_int = 1;
666 pm_runtime_get(otg->dev);
667 return IRQ_HANDLED;
668 }
669
507 otgsc = readl(USB_OTGSC); 670 otgsc = readl(USB_OTGSC);
508 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS))) 671 if (!(otgsc & (OTGSC_IDIS | OTGSC_BSVIS)))
509 return IRQ_NONE; 672 return IRQ_NONE;
@@ -514,12 +677,14 @@ static irqreturn_t msm_otg_irq(int irq, void *data)
514 else 677 else
515 clear_bit(ID, &motg->inputs); 678 clear_bit(ID, &motg->inputs);
516 dev_dbg(otg->dev, "ID set/clear\n"); 679 dev_dbg(otg->dev, "ID set/clear\n");
680 pm_runtime_get_noresume(otg->dev);
517 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) { 681 } else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
518 if (otgsc & OTGSC_BSV) 682 if (otgsc & OTGSC_BSV)
519 set_bit(B_SESS_VLD, &motg->inputs); 683 set_bit(B_SESS_VLD, &motg->inputs);
520 else 684 else
521 clear_bit(B_SESS_VLD, &motg->inputs); 685 clear_bit(B_SESS_VLD, &motg->inputs);
522 dev_dbg(otg->dev, "BSV set/clear\n"); 686 dev_dbg(otg->dev, "BSV set/clear\n");
687 pm_runtime_get_noresume(otg->dev);
523 } 688 }
524 689
525 writel(otgsc, USB_OTGSC); 690 writel(otgsc, USB_OTGSC);
@@ -616,6 +781,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
616 goto out; 781 goto out;
617 } 782 }
618 783
784 pm_runtime_get_sync(otg->dev);
619 schedule_work(&motg->sm_work); 785 schedule_work(&motg->sm_work);
620out: 786out:
621 return status; 787 return status;
@@ -770,8 +936,10 @@ static int __init msm_otg_probe(struct platform_device *pdev)
770 "not available\n"); 936 "not available\n");
771 } 937 }
772 938
773 return 0; 939 pm_runtime_set_active(&pdev->dev);
940 pm_runtime_enable(&pdev->dev);
774 941
942 return 0;
775free_irq: 943free_irq:
776 free_irq(motg->irq, motg); 944 free_irq(motg->irq, motg);
777disable_clks: 945disable_clks:
@@ -796,23 +964,45 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
796{ 964{
797 struct msm_otg *motg = platform_get_drvdata(pdev); 965 struct msm_otg *motg = platform_get_drvdata(pdev);
798 struct otg_transceiver *otg = &motg->otg; 966 struct otg_transceiver *otg = &motg->otg;
967 int cnt = 0;
799 968
800 if (otg->host || otg->gadget) 969 if (otg->host || otg->gadget)
801 return -EBUSY; 970 return -EBUSY;
802 971
803 msm_otg_debugfs_cleanup(); 972 msm_otg_debugfs_cleanup();
804 cancel_work_sync(&motg->sm_work); 973 cancel_work_sync(&motg->sm_work);
974
975 msm_otg_resume(motg);
976
805 device_init_wakeup(&pdev->dev, 0); 977 device_init_wakeup(&pdev->dev, 0);
806 otg_set_transceiver(NULL); 978 pm_runtime_disable(&pdev->dev);
807 979
980 otg_set_transceiver(NULL);
808 free_irq(motg->irq, motg); 981 free_irq(motg->irq, motg);
809 982
983 /*
984 * Put PHY in low power mode.
985 */
986 ulpi_read(otg, 0x14);
987 ulpi_write(otg, 0x08, 0x09);
988
989 writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
990 while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
991 if (readl(USB_PORTSC) & PORTSC_PHCD)
992 break;
993 udelay(1);
994 cnt++;
995 }
996 if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
997 dev_err(otg->dev, "Unable to suspend PHY\n");
998
810 clk_disable(motg->pclk); 999 clk_disable(motg->pclk);
811 clk_disable(motg->clk); 1000 clk_disable(motg->clk);
812 if (motg->core_clk) 1001 if (motg->core_clk)
813 clk_disable(motg->core_clk); 1002 clk_disable(motg->core_clk);
814 1003
815 iounmap(motg->regs); 1004 iounmap(motg->regs);
1005 pm_runtime_set_suspended(&pdev->dev);
816 1006
817 clk_put(motg->phy_reset_clk); 1007 clk_put(motg->phy_reset_clk);
818 clk_put(motg->pclk); 1008 clk_put(motg->pclk);
@@ -825,11 +1015,96 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
825 return 0; 1015 return 0;
826} 1016}
827 1017
1018#ifdef CONFIG_PM_RUNTIME
1019static int msm_otg_runtime_idle(struct device *dev)
1020{
1021 struct msm_otg *motg = dev_get_drvdata(dev);
1022 struct otg_transceiver *otg = &motg->otg;
1023
1024 dev_dbg(dev, "OTG runtime idle\n");
1025
1026 /*
1027 * It is observed some times that a spurious interrupt
1028 * comes when PHY is put into LPM immediately after PHY reset.
1029 * This 1 sec delay also prevents entering into LPM immediately
1030 * after asynchronous interrupt.
1031 */
1032 if (otg->state != OTG_STATE_UNDEFINED)
1033 pm_schedule_suspend(dev, 1000);
1034
1035 return -EAGAIN;
1036}
1037
1038static int msm_otg_runtime_suspend(struct device *dev)
1039{
1040 struct msm_otg *motg = dev_get_drvdata(dev);
1041
1042 dev_dbg(dev, "OTG runtime suspend\n");
1043 return msm_otg_suspend(motg);
1044}
1045
1046static int msm_otg_runtime_resume(struct device *dev)
1047{
1048 struct msm_otg *motg = dev_get_drvdata(dev);
1049
1050 dev_dbg(dev, "OTG runtime resume\n");
1051 return msm_otg_resume(motg);
1052}
1053#else
1054#define msm_otg_runtime_idle NULL
1055#define msm_otg_runtime_suspend NULL
1056#define msm_otg_runtime_resume NULL
1057#endif
1058
1059#ifdef CONFIG_PM
1060static int msm_otg_pm_suspend(struct device *dev)
1061{
1062 struct msm_otg *motg = dev_get_drvdata(dev);
1063
1064 dev_dbg(dev, "OTG PM suspend\n");
1065 return msm_otg_suspend(motg);
1066}
1067
1068static int msm_otg_pm_resume(struct device *dev)
1069{
1070 struct msm_otg *motg = dev_get_drvdata(dev);
1071 int ret;
1072
1073 dev_dbg(dev, "OTG PM resume\n");
1074
1075 ret = msm_otg_resume(motg);
1076 if (ret)
1077 return ret;
1078
1079 /*
1080 * Runtime PM Documentation recommends bringing the
1081 * device to full powered state upon resume.
1082 */
1083 pm_runtime_disable(dev);
1084 pm_runtime_set_active(dev);
1085 pm_runtime_enable(dev);
1086
1087 return 0;
1088}
1089#else
1090#define msm_otg_pm_suspend NULL
1091#define msm_otg_pm_resume NULL
1092#endif
1093
1094static const struct dev_pm_ops msm_otg_dev_pm_ops = {
1095 .runtime_suspend = msm_otg_runtime_suspend,
1096 .runtime_resume = msm_otg_runtime_resume,
1097 .runtime_idle = msm_otg_runtime_idle,
1098 .suspend = msm_otg_pm_suspend,
1099 .resume = msm_otg_pm_resume,
1100};
1101
828static struct platform_driver msm_otg_driver = { 1102static struct platform_driver msm_otg_driver = {
829 .remove = __devexit_p(msm_otg_remove), 1103 .remove = __devexit_p(msm_otg_remove),
830 .driver = { 1104 .driver = {
831 .name = DRIVER_NAME, 1105 .name = DRIVER_NAME,
832 .owner = THIS_MODULE, 1106 .owner = THIS_MODULE,
1107 .pm = &msm_otg_dev_pm_ops,
833 }, 1108 },
834}; 1109};
835 1110