aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/phy
diff options
context:
space:
mode:
authorVenu Byravarasu <vbyravarasu@nvidia.com>2013-05-16 10:13:02 -0400
committerFelipe Balbi <balbi@ti.com>2013-05-29 19:49:11 -0400
commit2d22b42db02fdafeb7b990c2c25caabff4dd46fe (patch)
tree5f80c9594098d7d6339d5bb19004c2be79b10d10 /drivers/usb/phy
parent6829f92f6e64bfc6a553d7a2203ce1cb2e433c01 (diff)
usb: phy: registering Tegra USB PHY as platform driver
Registered Tegra USB PHY as a separate platform driver. To synchronize host controller and PHY initialization, used deferred probe mechanism. As PHY should be initialized before EHCI starts running, deferred probe of Tegra EHCI driver till PHY probe gets completed. Got rid of instance number based handling in host driver. Made use of DT params to get the PHY Pad registers. Signed-off-by: Venu Byravarasu <vbyravarasu@nvidia.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/phy')
-rw-r--r--drivers/usb/phy/phy-tegra-usb.c325
1 files changed, 180 insertions, 145 deletions
diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c
index f423ae88b741..5d9af11d2731 100644
--- a/drivers/usb/phy/phy-tegra-usb.c
+++ b/drivers/usb/phy/phy-tegra-usb.c
@@ -1,9 +1,11 @@
1/* 1/*
2 * Copyright (C) 2010 Google, Inc. 2 * Copyright (C) 2010 Google, Inc.
3 * Copyright (C) 2013 NVIDIA Corporation
3 * 4 *
4 * Author: 5 * Author:
5 * Erik Gilling <konkers@google.com> 6 * Erik Gilling <konkers@google.com>
6 * Benoit Goby <benoit@android.com> 7 * Benoit Goby <benoit@android.com>
8 * Venu Byravarasu <vbyravarasu@nvidia.com>
7 * 9 *
8 * This software is licensed under the terms of the GNU General Public 10 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and 11 * License version 2, as published by the Free Software Foundation, and
@@ -30,9 +32,7 @@
30#include <linux/usb/ulpi.h> 32#include <linux/usb/ulpi.h>
31#include <asm/mach-types.h> 33#include <asm/mach-types.h>
32#include <linux/usb/tegra_usb_phy.h> 34#include <linux/usb/tegra_usb_phy.h>
33 35#include <linux/module.h>
34#define TEGRA_USB_BASE 0xC5000000
35#define TEGRA_USB_SIZE SZ_16K
36 36
37#define ULPI_VIEWPORT 0x170 37#define ULPI_VIEWPORT 0x170
38 38
@@ -198,32 +198,15 @@ static struct tegra_utmip_config utmip_default[] = {
198 198
199static int utmip_pad_open(struct tegra_usb_phy *phy) 199static int utmip_pad_open(struct tegra_usb_phy *phy)
200{ 200{
201 phy->pad_clk = clk_get_sys("utmip-pad", NULL); 201 phy->pad_clk = devm_clk_get(phy->dev, "utmi-pads");
202 if (IS_ERR(phy->pad_clk)) { 202 if (IS_ERR(phy->pad_clk)) {
203 pr_err("%s: can't get utmip pad clock\n", __func__); 203 pr_err("%s: can't get utmip pad clock\n", __func__);
204 return PTR_ERR(phy->pad_clk); 204 return PTR_ERR(phy->pad_clk);
205 } 205 }
206 206
207 if (phy->is_legacy_phy) {
208 phy->pad_regs = phy->regs;
209 } else {
210 phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
211 if (!phy->pad_regs) {
212 pr_err("%s: can't remap usb registers\n", __func__);
213 clk_put(phy->pad_clk);
214 return -ENOMEM;
215 }
216 }
217 return 0; 207 return 0;
218} 208}
219 209
220static void utmip_pad_close(struct tegra_usb_phy *phy)
221{
222 if (!phy->is_legacy_phy)
223 iounmap(phy->pad_regs);
224 clk_put(phy->pad_clk);
225}
226
227static void utmip_pad_power_on(struct tegra_usb_phy *phy) 210static void utmip_pad_power_on(struct tegra_usb_phy *phy)
228{ 211{
229 unsigned long val, flags; 212 unsigned long val, flags;
@@ -299,7 +282,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
299 val &= ~USB_SUSP_SET; 282 val &= ~USB_SUSP_SET;
300 writel(val, base + USB_SUSP_CTRL); 283 writel(val, base + USB_SUSP_CTRL);
301 } else 284 } else
302 phy->set_phcd(&phy->u_phy, true); 285 tegra_ehci_set_phcd(&phy->u_phy, true);
303 286
304 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) 287 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
305 pr_err("%s: timeout waiting for phy to stabilize\n", __func__); 288 pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
@@ -321,7 +304,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
321 val &= ~USB_SUSP_CLR; 304 val &= ~USB_SUSP_CLR;
322 writel(val, base + USB_SUSP_CTRL); 305 writel(val, base + USB_SUSP_CTRL);
323 } else 306 } else
324 phy->set_phcd(&phy->u_phy, false); 307 tegra_ehci_set_phcd(&phy->u_phy, false);
325 308
326 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 309 if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
327 USB_PHY_CLK_VALID)) 310 USB_PHY_CLK_VALID))
@@ -444,7 +427,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
444 utmi_phy_clk_enable(phy); 427 utmi_phy_clk_enable(phy);
445 428
446 if (!phy->is_legacy_phy) 429 if (!phy->is_legacy_phy)
447 phy->set_pts(&phy->u_phy, 0); 430 tegra_ehci_set_pts(&phy->u_phy, 0);
448 431
449 return 0; 432 return 0;
450} 433}
@@ -614,76 +597,11 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
614 return gpio_direction_output(phy->reset_gpio, 0); 597 return gpio_direction_output(phy->reset_gpio, 0);
615} 598}
616 599
617static int tegra_phy_init(struct usb_phy *x)
618{
619 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
620 struct tegra_ulpi_config *ulpi_config;
621 int err;
622
623 if (phy->is_ulpi_phy) {
624 ulpi_config = phy->config;
625 phy->clk = clk_get_sys(NULL, ulpi_config->clk);
626 if (IS_ERR(phy->clk)) {
627 pr_err("%s: can't get ulpi clock\n", __func__);
628 return PTR_ERR(phy->clk);
629 }
630
631 phy->reset_gpio =
632 of_get_named_gpio(phy->dev->of_node,
633 "nvidia,phy-reset-gpio", 0);
634 if (!gpio_is_valid(phy->reset_gpio)) {
635 dev_err(phy->dev, "invalid gpio: %d\n",
636 phy->reset_gpio);
637 err = phy->reset_gpio;
638 goto cleanup_clk_get;
639 }
640
641 err = gpio_request(phy->reset_gpio, "ulpi_phy_reset_b");
642 if (err < 0) {
643 dev_err(phy->dev, "request failed for gpio: %d\n",
644 phy->reset_gpio);
645 goto cleanup_clk_get;
646 }
647
648 err = gpio_direction_output(phy->reset_gpio, 0);
649 if (err < 0) {
650 dev_err(phy->dev, "gpio %d direction not set to output\n",
651 phy->reset_gpio);
652 goto cleanup_gpio_req;
653 }
654
655 phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
656 if (!phy->ulpi) {
657 dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
658 err = -ENOMEM;
659 goto cleanup_gpio_req;
660 }
661
662 phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
663 } else {
664 err = utmip_pad_open(phy);
665 if (err < 0)
666 return err;
667 }
668 return 0;
669cleanup_gpio_req:
670 gpio_free(phy->reset_gpio);
671cleanup_clk_get:
672 clk_put(phy->clk);
673 return err;
674}
675
676static void tegra_usb_phy_close(struct usb_phy *x) 600static void tegra_usb_phy_close(struct usb_phy *x)
677{ 601{
678 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); 602 struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy);
679 603
680 if (phy->is_ulpi_phy)
681 clk_put(phy->clk);
682 else
683 utmip_pad_close(phy);
684 clk_disable_unprepare(phy->pll_u); 604 clk_disable_unprepare(phy->pll_u);
685 clk_put(phy->pll_u);
686 kfree(phy);
687} 605}
688 606
689static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) 607static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
@@ -711,63 +629,63 @@ static int tegra_usb_phy_suspend(struct usb_phy *x, int suspend)
711 return tegra_usb_phy_power_on(phy); 629 return tegra_usb_phy_power_on(phy);
712} 630}
713 631
714struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, 632static int ulpi_open(struct tegra_usb_phy *phy)
715 void __iomem *regs, void *config,
716 void (*set_pts)(struct usb_phy *x, u8 pts_val),
717 void (*set_phcd)(struct usb_phy *x, bool enable))
718
719{ 633{
720 struct tegra_usb_phy *phy;
721 unsigned long parent_rate;
722 int i;
723 int err; 634 int err;
724 struct device_node *np = dev->of_node;
725 635
726 phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); 636 phy->clk = devm_clk_get(phy->dev, "ulpi-link");
727 if (!phy) 637 if (IS_ERR(phy->clk)) {
728 return ERR_PTR(-ENOMEM); 638 pr_err("%s: can't get ulpi clock\n", __func__);
639 return PTR_ERR(phy->clk);
640 }
729 641
730 phy->instance = instance; 642 err = devm_gpio_request(phy->dev, phy->reset_gpio, "ulpi_phy_reset_b");
731 phy->regs = regs; 643 if (err < 0) {
732 phy->config = config; 644 dev_err(phy->dev, "request failed for gpio: %d\n",
733 phy->dev = dev; 645 phy->reset_gpio);
734 phy->is_legacy_phy = 646 return err;
735 of_property_read_bool(np, "nvidia,has-legacy-mode"); 647 }
736 phy->set_pts = set_pts;
737 phy->set_phcd = set_phcd;
738 err = of_property_match_string(np, "phy_type", "ulpi");
739 if (err < 0)
740 phy->is_ulpi_phy = false;
741 else
742 phy->is_ulpi_phy = true;
743 648
744 err = of_property_match_string(np, "dr_mode", "otg"); 649 err = gpio_direction_output(phy->reset_gpio, 0);
745 if (err < 0) { 650 if (err < 0) {
746 err = of_property_match_string(np, "dr_mode", "peripheral"); 651 dev_err(phy->dev, "gpio %d direction not set to output\n",
747 if (err < 0) 652 phy->reset_gpio);
748 phy->mode = TEGRA_USB_PHY_MODE_HOST; 653 return err;
654 }
655
656 phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
657 if (!phy->ulpi) {
658 dev_err(phy->dev, "otg_ulpi_create returned NULL\n");
659 err = -ENOMEM;
660 return err;
661 }
662
663 phy->ulpi->io_priv = phy->regs + ULPI_VIEWPORT;
664 return 0;
665}
666
667static int tegra_usb_phy_init(struct tegra_usb_phy *phy)
668{
669 unsigned long parent_rate;
670 int i;
671 int err;
672
673 if (!phy->is_ulpi_phy) {
674 if (phy->is_legacy_phy)
675 phy->config = &utmip_default[0];
749 else 676 else
750 phy->mode = TEGRA_USB_PHY_MODE_DEVICE; 677 phy->config = &utmip_default[2];
751 } else
752 phy->mode = TEGRA_USB_PHY_MODE_OTG;
753
754 if (!phy->config) {
755 if (phy->is_ulpi_phy) {
756 pr_err("%s: ulpi phy configuration missing", __func__);
757 err = -EINVAL;
758 goto err0;
759 } else {
760 phy->config = &utmip_default[instance];
761 }
762 } 678 }
763 679
764 phy->pll_u = clk_get_sys(NULL, "pll_u"); 680 phy->pll_u = devm_clk_get(phy->dev, "pll_u");
765 if (IS_ERR(phy->pll_u)) { 681 if (IS_ERR(phy->pll_u)) {
766 pr_err("Can't get pll_u clock\n"); 682 pr_err("Can't get pll_u clock\n");
767 err = PTR_ERR(phy->pll_u); 683 return PTR_ERR(phy->pll_u);
768 goto err0;
769 } 684 }
770 clk_prepare_enable(phy->pll_u); 685
686 err = clk_prepare_enable(phy->pll_u);
687 if (err)
688 return err;
771 689
772 parent_rate = clk_get_rate(clk_get_parent(phy->pll_u)); 690 parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
773 for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) { 691 for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
@@ -779,23 +697,22 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance,
779 if (!phy->freq) { 697 if (!phy->freq) {
780 pr_err("invalid pll_u parent rate %ld\n", parent_rate); 698 pr_err("invalid pll_u parent rate %ld\n", parent_rate);
781 err = -EINVAL; 699 err = -EINVAL;
782 goto err1; 700 goto fail;
783 } 701 }
784 702
785 phy->u_phy.init = tegra_phy_init; 703 if (phy->is_ulpi_phy)
786 phy->u_phy.shutdown = tegra_usb_phy_close; 704 err = ulpi_open(phy);
787 phy->u_phy.set_suspend = tegra_usb_phy_suspend; 705 else
706 err = utmip_pad_open(phy);
707 if (err < 0)
708 goto fail;
788 709
789 return phy; 710 return 0;
790 711
791err1: 712fail:
792 clk_disable_unprepare(phy->pll_u); 713 clk_disable_unprepare(phy->pll_u);
793 clk_put(phy->pll_u); 714 return err;
794err0:
795 kfree(phy);
796 return ERR_PTR(err);
797} 715}
798EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
799 716
800void tegra_usb_phy_preresume(struct usb_phy *x) 717void tegra_usb_phy_preresume(struct usb_phy *x)
801{ 718{
@@ -834,3 +751,121 @@ void tegra_ehci_phy_restore_end(struct usb_phy *x)
834} 751}
835EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); 752EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end);
836 753
754static int tegra_usb_phy_probe(struct platform_device *pdev)
755{
756 struct resource *res;
757 struct tegra_usb_phy *tegra_phy = NULL;
758 struct device_node *np = pdev->dev.of_node;
759 int err;
760
761 tegra_phy = devm_kzalloc(&pdev->dev, sizeof(*tegra_phy), GFP_KERNEL);
762 if (!tegra_phy) {
763 dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n");
764 return -ENOMEM;
765 }
766
767 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
768 if (!res) {
769 dev_err(&pdev->dev, "Failed to get I/O memory\n");
770 return -ENXIO;
771 }
772
773 tegra_phy->regs = devm_ioremap(&pdev->dev, res->start,
774 resource_size(res));
775 if (!tegra_phy->regs) {
776 dev_err(&pdev->dev, "Failed to remap I/O memory\n");
777 return -ENOMEM;
778 }
779
780 tegra_phy->is_legacy_phy =
781 of_property_read_bool(np, "nvidia,has-legacy-mode");
782
783 err = of_property_match_string(np, "phy_type", "ulpi");
784 if (err < 0) {
785 tegra_phy->is_ulpi_phy = false;
786
787 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
788 if (!res) {
789 dev_err(&pdev->dev, "Failed to get UTMI Pad regs\n");
790 return -ENXIO;
791 }
792
793 tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
794 resource_size(res));
795 if (!tegra_phy->regs) {
796 dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");
797 return -ENOMEM;
798 }
799 } else {
800 tegra_phy->is_ulpi_phy = true;
801
802 tegra_phy->reset_gpio =
803 of_get_named_gpio(np, "nvidia,phy-reset-gpio", 0);
804 if (!gpio_is_valid(tegra_phy->reset_gpio)) {
805 dev_err(&pdev->dev, "invalid gpio: %d\n",
806 tegra_phy->reset_gpio);
807 return tegra_phy->reset_gpio;
808 }
809 }
810
811 err = of_property_match_string(np, "dr_mode", "otg");
812 if (err < 0) {
813 err = of_property_match_string(np, "dr_mode", "peripheral");
814 if (err < 0)
815 tegra_phy->mode = TEGRA_USB_PHY_MODE_HOST;
816 else
817 tegra_phy->mode = TEGRA_USB_PHY_MODE_DEVICE;
818 } else
819 tegra_phy->mode = TEGRA_USB_PHY_MODE_OTG;
820
821 tegra_phy->dev = &pdev->dev;
822 err = tegra_usb_phy_init(tegra_phy);
823 if (err < 0)
824 return err;
825
826 tegra_phy->u_phy.shutdown = tegra_usb_phy_close;
827 tegra_phy->u_phy.set_suspend = tegra_usb_phy_suspend;
828
829 dev_set_drvdata(&pdev->dev, tegra_phy);
830 return 0;
831}
832
833static struct of_device_id tegra_usb_phy_id_table[] = {
834 { .compatible = "nvidia,tegra20-usb-phy", },
835 { },
836};
837MODULE_DEVICE_TABLE(of, tegra_usb_phy_id_table);
838
839static struct platform_driver tegra_usb_phy_driver = {
840 .probe = tegra_usb_phy_probe,
841 .driver = {
842 .name = "tegra-phy",
843 .owner = THIS_MODULE,
844 .of_match_table = of_match_ptr(tegra_usb_phy_id_table),
845 },
846};
847module_platform_driver(tegra_usb_phy_driver);
848
849static int tegra_usb_phy_match(struct device *dev, void *data)
850{
851 struct tegra_usb_phy *tegra_phy = dev_get_drvdata(dev);
852 struct device_node *dn = data;
853
854 return (tegra_phy->dev->of_node == dn) ? 1 : 0;
855}
856
857struct usb_phy *tegra_usb_get_phy(struct device_node *dn)
858{
859 struct device *dev;
860 struct tegra_usb_phy *tegra_phy;
861
862 dev = driver_find_device(&tegra_usb_phy_driver.driver, NULL, dn,
863 tegra_usb_phy_match);
864 if (!dev)
865 return ERR_PTR(-EPROBE_DEFER);
866
867 tegra_phy = dev_get_drvdata(dev);
868
869 return &tegra_phy->u_phy;
870}
871EXPORT_SYMBOL_GPL(tegra_usb_get_phy);