aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy/phy-twl4030-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy/phy-twl4030-usb.c')
-rw-r--r--drivers/phy/phy-twl4030-usb.c121
1 files changed, 73 insertions, 48 deletions
diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c
index e1a6623d4696..9cd33a4bcfb1 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,9 +577,27 @@ 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
593 /* don't schedule during sleep - irq works right then */
594 if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
595 cancel_delayed_work(&twl->id_workaround_work);
596 schedule_delayed_work(&twl->id_workaround_work, HZ);
597 }
598
599 if (irq)
600 sysfs_notify(&twl->dev->kobj, NULL, "vbus");
564 601
565 return IRQ_HANDLED; 602 return IRQ_HANDLED;
566} 603}
@@ -569,29 +606,8 @@ static void twl4030_id_workaround_work(struct work_struct *work)
569{ 606{
570 struct twl4030_usb *twl = container_of(work, struct twl4030_usb, 607 struct twl4030_usb *twl = container_of(work, struct twl4030_usb,
571 id_workaround_work.work); 608 id_workaround_work.work);
572 enum omap_musb_vbus_id_status status;
573 bool status_changed = false;
574
575 status = twl4030_usb_linkstat(twl);
576
577 spin_lock_irq(&twl->lock);
578 if (status >= 0 && status != twl->linkstat) {
579 twl->linkstat = status;
580 status_changed = true;
581 }
582 spin_unlock_irq(&twl->lock);
583
584 if (status_changed) {
585 dev_dbg(twl->dev, "handle missing status change to %d\n",
586 status);
587 omap_musb_mailbox(status);
588 }
589 609
590 /* don't schedule during sleep - irq works right then */ 610 twl4030_usb_irq(0, twl);
591 if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) {
592 cancel_delayed_work(&twl->id_workaround_work);
593 schedule_delayed_work(&twl->id_workaround_work, HZ);
594 }
595} 611}
596 612
597static int twl4030_phy_init(struct phy *phy) 613static int twl4030_phy_init(struct phy *phy)
@@ -599,22 +615,17 @@ static int twl4030_phy_init(struct phy *phy)
599 struct twl4030_usb *twl = phy_get_drvdata(phy); 615 struct twl4030_usb *twl = phy_get_drvdata(phy);
600 enum omap_musb_vbus_id_status status; 616 enum omap_musb_vbus_id_status status;
601 617
602 /* 618 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); 619 status = twl4030_usb_linkstat(twl);
610 twl->linkstat = status; 620 twl->linkstat = status;
611 621
612 if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID) { 622 if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID)
613 omap_musb_mailbox(twl->linkstat); 623 omap_musb_mailbox(twl->linkstat);
614 twl4030_phy_power_on(phy);
615 }
616 624
617 sysfs_notify(&twl->dev->kobj, NULL, "vbus"); 625 sysfs_notify(&twl->dev->kobj, NULL, "vbus");
626 pm_runtime_mark_last_busy(twl->dev);
627 pm_runtime_put_autosuspend(twl->dev);
628
618 return 0; 629 return 0;
619} 630}
620 631
@@ -650,6 +661,11 @@ static const struct phy_ops ops = {
650 .owner = THIS_MODULE, 661 .owner = THIS_MODULE,
651}; 662};
652 663
664static const struct dev_pm_ops twl4030_usb_pm_ops = {
665 SET_RUNTIME_PM_OPS(twl4030_usb_runtime_suspend,
666 twl4030_usb_runtime_resume, NULL)
667};
668
653static int twl4030_usb_probe(struct platform_device *pdev) 669static int twl4030_usb_probe(struct platform_device *pdev)
654{ 670{
655 struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev); 671 struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev);
@@ -726,6 +742,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
726 742
727 ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier); 743 ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
728 744
745 pm_runtime_use_autosuspend(&pdev->dev);
746 pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
747 pm_runtime_enable(&pdev->dev);
748 pm_runtime_get_sync(&pdev->dev);
749
729 /* Our job is to use irqs and status from the power module 750 /* Our job is to use irqs and status from the power module
730 * to keep the transceiver disabled when nothing's connected. 751 * to keep the transceiver disabled when nothing's connected.
731 * 752 *
@@ -744,6 +765,9 @@ static int twl4030_usb_probe(struct platform_device *pdev)
744 return status; 765 return status;
745 } 766 }
746 767
768 pm_runtime_mark_last_busy(&pdev->dev);
769 pm_runtime_put_autosuspend(twl->dev);
770
747 dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); 771 dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
748 return 0; 772 return 0;
749} 773}
@@ -753,6 +777,7 @@ static int twl4030_usb_remove(struct platform_device *pdev)
753 struct twl4030_usb *twl = platform_get_drvdata(pdev); 777 struct twl4030_usb *twl = platform_get_drvdata(pdev);
754 int val; 778 int val;
755 779
780 pm_runtime_get_sync(twl->dev);
756 cancel_delayed_work(&twl->id_workaround_work); 781 cancel_delayed_work(&twl->id_workaround_work);
757 device_remove_file(twl->dev, &dev_attr_vbus); 782 device_remove_file(twl->dev, &dev_attr_vbus);
758 783
@@ -772,9 +797,8 @@ static int twl4030_usb_remove(struct platform_device *pdev)
772 797
773 /* disable complete OTG block */ 798 /* disable complete OTG block */
774 twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); 799 twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
775 800 pm_runtime_mark_last_busy(twl->dev);
776 if (!twl->asleep) 801 pm_runtime_put(twl->dev);
777 twl4030_phy_power(twl, 0);
778 802
779 return 0; 803 return 0;
780} 804}
@@ -792,6 +816,7 @@ static struct platform_driver twl4030_usb_driver = {
792 .remove = twl4030_usb_remove, 816 .remove = twl4030_usb_remove,
793 .driver = { 817 .driver = {
794 .name = "twl4030_usb", 818 .name = "twl4030_usb",
819 .pm = &twl4030_usb_pm_ops,
795 .owner = THIS_MODULE, 820 .owner = THIS_MODULE,
796 .of_match_table = of_match_ptr(twl4030_usb_id_table), 821 .of_match_table = of_match_ptr(twl4030_usb_id_table),
797 }, 822 },