aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/phy-twl4030-usb.c88
1 files changed, 63 insertions, 25 deletions
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index e1a6623d4696..0cb872bdbe7e 100644
--- a/drivers/phy/phy-twl4030-usb.c
+++ b/drivers/phy/phy-twl4030-usb.c
@@ -34,6 +34,7 @@
34#include <linux/delay.h> 34#include <linux/delay.h>
35#include <linux/usb/otg.h> 35#include <linux/usb/otg.h>
36#include <linux/phy/phy.h> 36#include <linux/phy/phy.h>
37#include <linux/pm_runtime.h>
37#include <linux/usb/musb-omap.h> 38#include <linux/usb/musb-omap.h>
38#include <linux/usb/ulpi.h> 39#include <linux/usb/ulpi.h>
39#include <linux/i2c/twl.h> 40#include <linux/i2c/twl.h>
@@ -422,37 +423,55 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on)
422 } 423 }
423} 424}
424 425
425static int twl4030_phy_power_off(struct phy *phy) 426static int twl4030_usb_runtime_suspend(struct device *dev)
426{ 427{
427 struct twl4030_usb *twl = phy_get_drvdata(phy); 428 struct twl4030_usb *twl = dev_get_drvdata(dev);
428 429
430 dev_dbg(twl->dev, "%s\n", __func__);
429 if (twl->asleep) 431 if (twl->asleep)
430 return 0; 432 return 0;
431 433
432 twl4030_phy_power(twl, 0); 434 twl4030_phy_power(twl, 0);
433 twl->asleep = 1; 435 twl->asleep = 1;
434 dev_dbg(twl->dev, "%s\n", __func__); 436
435 return 0; 437 return 0;
436} 438}
437 439
438static void __twl4030_phy_power_on(struct twl4030_usb *twl) 440static int twl4030_usb_runtime_resume(struct device *dev)
439{ 441{
442 struct twl4030_usb *twl = dev_get_drvdata(dev);
443
444 dev_dbg(twl->dev, "%s\n", __func__);
445 if (!twl->asleep)
446 return 0;
447
440 twl4030_phy_power(twl, 1); 448 twl4030_phy_power(twl, 1);
441 twl4030_i2c_access(twl, 1); 449 twl->asleep = 0;
442 twl4030_usb_set_mode(twl, twl->usb_mode); 450
443 if (twl->usb_mode == T2_USB_MODE_ULPI) 451 return 0;
444 twl4030_i2c_access(twl, 0); 452}
453
454static int twl4030_phy_power_off(struct phy *phy)
455{
456 struct twl4030_usb *twl = phy_get_drvdata(phy);
457
458 dev_dbg(twl->dev, "%s\n", __func__);
459 pm_runtime_mark_last_busy(twl->dev);
460 pm_runtime_put_autosuspend(twl->dev);
461
462 return 0;
445} 463}
446 464
447static int twl4030_phy_power_on(struct phy *phy) 465static int twl4030_phy_power_on(struct phy *phy)
448{ 466{
449 struct twl4030_usb *twl = phy_get_drvdata(phy); 467 struct twl4030_usb *twl = phy_get_drvdata(phy);
450 468
451 if (!twl->asleep)
452 return 0;
453 __twl4030_phy_power_on(twl);
454 twl->asleep = 0;
455 dev_dbg(twl->dev, "%s\n", __func__); 469 dev_dbg(twl->dev, "%s\n", __func__);
470 pm_runtime_get_sync(twl->dev);
471 twl4030_i2c_access(twl, 1);
472 twl4030_usb_set_mode(twl, twl->usb_mode);
473 if (twl->usb_mode == T2_USB_MODE_ULPI)
474 twl4030_i2c_access(twl, 0);
456 475
457 /* 476 /*
458 * XXX When VBUS gets driven after musb goes to A mode, 477 * XXX When VBUS gets driven after musb goes to A mode,
@@ -558,6 +577,16 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
558 * USB_LINK_VBUS state. musb_hdrc won't care until it 577 * USB_LINK_VBUS state. musb_hdrc won't care until it
559 * starts to handle softconnect right. 578 * starts to handle softconnect right.
560 */ 579 */
580 if ((status == OMAP_MUSB_VBUS_VALID) ||
581 (status == OMAP_MUSB_ID_GROUND)) {
582 if (twl->asleep)
583 pm_runtime_get_sync(twl->dev);
584 } else {
585 if (!twl->asleep) {
586 pm_runtime_mark_last_busy(twl->dev);
587 pm_runtime_put_autosuspend(twl->dev);
588 }
589 }
561 omap_musb_mailbox(status); 590 omap_musb_mailbox(status);
562 } 591 }
563 sysfs_notify(&twl->dev->kobj, NULL, "vbus"); 592 sysfs_notify(&twl->dev->kobj, NULL, "vbus");
@@ -599,22 +628,17 @@ static int twl4030_phy_init(struct phy *phy)
599 struct twl4030_usb *twl = phy_get_drvdata(phy); 628 struct twl4030_usb *twl = phy_get_drvdata(phy);
600 enum omap_musb_vbus_id_status status; 629 enum omap_musb_vbus_id_status status;
601 630
602 /* 631 pm_runtime_get_sync(twl->dev);
603 * Start in sleep state, we'll get called through set_suspend()
604 * callback when musb is runtime resumed and it's time to start.
605 */
606 __twl4030_phy_power(twl, 0);
607 twl->asleep = 1;
608
609 status = twl4030_usb_linkstat(twl); 632 status = twl4030_usb_linkstat(twl);
610 twl->linkstat = status; 633 twl->linkstat = status;
611 634
612 if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID) { 635 if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID)
613 omap_musb_mailbox(twl->linkstat); 636 omap_musb_mailbox(twl->linkstat);
614 twl4030_phy_power_on(phy);
615 }
616 637
617 sysfs_notify(&twl->dev->kobj, NULL, "vbus"); 638 sysfs_notify(&twl->dev->kobj, NULL, "vbus");
639 pm_runtime_mark_last_busy(twl->dev);
640 pm_runtime_put_autosuspend(twl->dev);
641
618 return 0; 642 return 0;
619} 643}
620 644
@@ -650,6 +674,11 @@ static const struct phy_ops ops = {
650 .owner = THIS_MODULE, 674 .owner = THIS_MODULE,
651}; 675};
652 676
677static const struct dev_pm_ops twl4030_usb_pm_ops = {
678 SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend,
679 twl4030_usb_runtime_resume, NULL)
680};
681
653static int twl4030_usb_probe(struct platform_device *pdev) 682static int twl4030_usb_probe(struct platform_device *pdev)
654{ 683{
655 struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev); 684 struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev);
@@ -726,6 +755,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
726 755
727 ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); 756 ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
728 757
758 pm_runtime_use_autosuspend(&pdev->dev);
759 pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
760 pm_runtime_enable(&pdev->dev);
761 pm_runtime_get_sync(&pdev->dev);
762
729 /* Our job is to use irqs and status from the power module 763 /* Our job is to use irqs and status from the power module
730 * to keep the transceiver disabled when nothing's connected. 764 * to keep the transceiver disabled when nothing's connected.
731 * 765 *
@@ -744,6 +778,9 @@ static int twl4030_usb_probe(struct platform_device *pdev)
744 return status; 778 return status;
745 } 779 }
746 780
781 pm_runtime_mark_last_busy(&pdev->dev);
782 pm_runtime_put_autosuspend(twl->dev);
783
747 dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); 784 dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
748 return 0; 785 return 0;
749} 786}
@@ -753,6 +790,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
753 struct twl4030_usb *twl = platform_get_drvdata(pdev); 790 struct twl4030_usb *twl = platform_get_drvdata(pdev);
754 int val; 791 int val;
755 792
793 pm_runtime_get_sync(twl->dev);
756 cancel_delayed_work(&twl->id_workaround_work); 794 cancel_delayed_work(&twl->id_workaround_work);
757 device_remove_file(twl->dev, &dev_attr_vbus); 795 device_remove_file(twl->dev, &dev_attr_vbus);
758 796
@@ -772,9 +810,8 @@ static int twl4030_usb_remove(struct platform_device *pdev)
772 810
773 /* disable complete OTG block */ 811 /* disable complete OTG block */
774 twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); 812 twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
775 813 pm_runtime_mark_last_busy(twl->dev);
776 if (!twl->asleep) 814 pm_runtime_put(twl->dev);
777 twl4030_phy_power(twl, 0);
778 815
779 return 0; 816 return 0;
780} 817}
@@ -792,6 +829,7 @@ static struct platform_driver twl4030_usb_driver = {
792 .remove = twl4030_usb_remove, 829 .remove = twl4030_usb_remove,
793 .driver = { 830 .driver = {
794 .name = "twl4030_usb", 831 .name = "twl4030_usb",
832 .pm = &twl4030_usb_pm_ops,
795 .owner = THIS_MODULE, 833 .owner = THIS_MODULE,
796 .of_match_table = of_match_ptr(twl4030_usb_id_table), 834 .of_match_table = of_match_ptr(twl4030_usb_id_table),
797 }, 835 },