diff options
Diffstat (limited to 'drivers/usb/phy/tegra_usb_phy.c')
-rw-r--r-- | drivers/usb/phy/tegra_usb_phy.c | 132 |
1 files changed, 45 insertions, 87 deletions
diff --git a/drivers/usb/phy/tegra_usb_phy.c b/drivers/usb/phy/tegra_usb_phy.c index 9d13c81754e0..5487d38481af 100644 --- a/drivers/usb/phy/tegra_usb_phy.c +++ b/drivers/usb/phy/tegra_usb_phy.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | #include <linux/gpio.h> | 26 | #include <linux/gpio.h> |
27 | #include <linux/of.h> | ||
27 | #include <linux/of_gpio.h> | 28 | #include <linux/of_gpio.h> |
28 | #include <linux/usb/otg.h> | 29 | #include <linux/usb/otg.h> |
29 | #include <linux/usb/ulpi.h> | 30 | #include <linux/usb/ulpi.h> |
@@ -35,19 +36,6 @@ | |||
35 | 36 | ||
36 | #define ULPI_VIEWPORT 0x170 | 37 | #define ULPI_VIEWPORT 0x170 |
37 | 38 | ||
38 | #define USB_PORTSC1 0x184 | ||
39 | #define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30) | ||
40 | #define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26) | ||
41 | #define USB_PORTSC1_PHCD (1 << 23) | ||
42 | #define USB_PORTSC1_WKOC (1 << 22) | ||
43 | #define USB_PORTSC1_WKDS (1 << 21) | ||
44 | #define USB_PORTSC1_WKCN (1 << 20) | ||
45 | #define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16) | ||
46 | #define USB_PORTSC1_PP (1 << 12) | ||
47 | #define USB_PORTSC1_SUSP (1 << 7) | ||
48 | #define USB_PORTSC1_PE (1 << 2) | ||
49 | #define USB_PORTSC1_CCS (1 << 0) | ||
50 | |||
51 | #define USB_SUSP_CTRL 0x400 | 39 | #define USB_SUSP_CTRL 0x400 |
52 | #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) | 40 | #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) |
53 | #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) | 41 | #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) |
@@ -208,11 +196,6 @@ static struct tegra_utmip_config utmip_default[] = { | |||
208 | }, | 196 | }, |
209 | }; | 197 | }; |
210 | 198 | ||
211 | static inline bool phy_is_ulpi(struct tegra_usb_phy *phy) | ||
212 | { | ||
213 | return (phy->instance == 1); | ||
214 | } | ||
215 | |||
216 | static int utmip_pad_open(struct tegra_usb_phy *phy) | 199 | static int utmip_pad_open(struct tegra_usb_phy *phy) |
217 | { | 200 | { |
218 | phy->pad_clk = clk_get_sys("utmip-pad", NULL); | 201 | phy->pad_clk = clk_get_sys("utmip-pad", NULL); |
@@ -221,7 +204,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) | |||
221 | return PTR_ERR(phy->pad_clk); | 204 | return PTR_ERR(phy->pad_clk); |
222 | } | 205 | } |
223 | 206 | ||
224 | if (phy->instance == 0) { | 207 | if (phy->is_legacy_phy) { |
225 | phy->pad_regs = phy->regs; | 208 | phy->pad_regs = phy->regs; |
226 | } else { | 209 | } else { |
227 | phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); | 210 | phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE); |
@@ -236,7 +219,7 @@ static int utmip_pad_open(struct tegra_usb_phy *phy) | |||
236 | 219 | ||
237 | static void utmip_pad_close(struct tegra_usb_phy *phy) | 220 | static void utmip_pad_close(struct tegra_usb_phy *phy) |
238 | { | 221 | { |
239 | if (phy->instance != 0) | 222 | if (!phy->is_legacy_phy) |
240 | iounmap(phy->pad_regs); | 223 | iounmap(phy->pad_regs); |
241 | clk_put(phy->pad_clk); | 224 | clk_put(phy->pad_clk); |
242 | } | 225 | } |
@@ -305,7 +288,7 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) | |||
305 | unsigned long val; | 288 | unsigned long val; |
306 | void __iomem *base = phy->regs; | 289 | void __iomem *base = phy->regs; |
307 | 290 | ||
308 | if (phy->instance == 0) { | 291 | if (phy->is_legacy_phy) { |
309 | val = readl(base + USB_SUSP_CTRL); | 292 | val = readl(base + USB_SUSP_CTRL); |
310 | val |= USB_SUSP_SET; | 293 | val |= USB_SUSP_SET; |
311 | writel(val, base + USB_SUSP_CTRL); | 294 | writel(val, base + USB_SUSP_CTRL); |
@@ -315,13 +298,8 @@ static void utmi_phy_clk_disable(struct tegra_usb_phy *phy) | |||
315 | val = readl(base + USB_SUSP_CTRL); | 298 | val = readl(base + USB_SUSP_CTRL); |
316 | val &= ~USB_SUSP_SET; | 299 | val &= ~USB_SUSP_SET; |
317 | writel(val, base + USB_SUSP_CTRL); | 300 | writel(val, base + USB_SUSP_CTRL); |
318 | } | 301 | } else |
319 | 302 | tegra_ehci_set_phcd(&phy->u_phy, true); | |
320 | if (phy->instance == 2) { | ||
321 | val = readl(base + USB_PORTSC1); | ||
322 | val |= USB_PORTSC1_PHCD; | ||
323 | writel(val, base + USB_PORTSC1); | ||
324 | } | ||
325 | 303 | ||
326 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) | 304 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0) |
327 | pr_err("%s: timeout waiting for phy to stabilize\n", __func__); | 305 | pr_err("%s: timeout waiting for phy to stabilize\n", __func__); |
@@ -332,7 +310,7 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) | |||
332 | unsigned long val; | 310 | unsigned long val; |
333 | void __iomem *base = phy->regs; | 311 | void __iomem *base = phy->regs; |
334 | 312 | ||
335 | if (phy->instance == 0) { | 313 | if (phy->is_legacy_phy) { |
336 | val = readl(base + USB_SUSP_CTRL); | 314 | val = readl(base + USB_SUSP_CTRL); |
337 | val |= USB_SUSP_CLR; | 315 | val |= USB_SUSP_CLR; |
338 | writel(val, base + USB_SUSP_CTRL); | 316 | writel(val, base + USB_SUSP_CTRL); |
@@ -342,13 +320,8 @@ static void utmi_phy_clk_enable(struct tegra_usb_phy *phy) | |||
342 | val = readl(base + USB_SUSP_CTRL); | 320 | val = readl(base + USB_SUSP_CTRL); |
343 | val &= ~USB_SUSP_CLR; | 321 | val &= ~USB_SUSP_CLR; |
344 | writel(val, base + USB_SUSP_CTRL); | 322 | writel(val, base + USB_SUSP_CTRL); |
345 | } | 323 | } else |
346 | 324 | tegra_ehci_set_phcd(&phy->u_phy, false); | |
347 | if (phy->instance == 2) { | ||
348 | val = readl(base + USB_PORTSC1); | ||
349 | val &= ~USB_PORTSC1_PHCD; | ||
350 | writel(val, base + USB_PORTSC1); | ||
351 | } | ||
352 | 325 | ||
353 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, | 326 | if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, |
354 | USB_PHY_CLK_VALID)) | 327 | USB_PHY_CLK_VALID)) |
@@ -365,7 +338,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
365 | val |= UTMIP_RESET; | 338 | val |= UTMIP_RESET; |
366 | writel(val, base + USB_SUSP_CTRL); | 339 | writel(val, base + USB_SUSP_CTRL); |
367 | 340 | ||
368 | if (phy->instance == 0) { | 341 | if (phy->is_legacy_phy) { |
369 | val = readl(base + USB1_LEGACY_CTRL); | 342 | val = readl(base + USB1_LEGACY_CTRL); |
370 | val |= USB1_NO_LEGACY_MODE; | 343 | val |= USB1_NO_LEGACY_MODE; |
371 | writel(val, base + USB1_LEGACY_CTRL); | 344 | writel(val, base + USB1_LEGACY_CTRL); |
@@ -440,16 +413,14 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
440 | val |= UTMIP_BIAS_PDTRK_COUNT(0x5); | 413 | val |= UTMIP_BIAS_PDTRK_COUNT(0x5); |
441 | writel(val, base + UTMIP_BIAS_CFG1); | 414 | writel(val, base + UTMIP_BIAS_CFG1); |
442 | 415 | ||
443 | if (phy->instance == 0) { | 416 | if (phy->is_legacy_phy) { |
444 | val = readl(base + UTMIP_SPARE_CFG0); | 417 | val = readl(base + UTMIP_SPARE_CFG0); |
445 | if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) | 418 | if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) |
446 | val &= ~FUSE_SETUP_SEL; | 419 | val &= ~FUSE_SETUP_SEL; |
447 | else | 420 | else |
448 | val |= FUSE_SETUP_SEL; | 421 | val |= FUSE_SETUP_SEL; |
449 | writel(val, base + UTMIP_SPARE_CFG0); | 422 | writel(val, base + UTMIP_SPARE_CFG0); |
450 | } | 423 | } else { |
451 | |||
452 | if (phy->instance == 2) { | ||
453 | val = readl(base + USB_SUSP_CTRL); | 424 | val = readl(base + USB_SUSP_CTRL); |
454 | val |= UTMIP_PHY_ENABLE; | 425 | val |= UTMIP_PHY_ENABLE; |
455 | writel(val, base + USB_SUSP_CTRL); | 426 | writel(val, base + USB_SUSP_CTRL); |
@@ -459,7 +430,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
459 | val &= ~UTMIP_RESET; | 430 | val &= ~UTMIP_RESET; |
460 | writel(val, base + USB_SUSP_CTRL); | 431 | writel(val, base + USB_SUSP_CTRL); |
461 | 432 | ||
462 | if (phy->instance == 0) { | 433 | if (phy->is_legacy_phy) { |
463 | val = readl(base + USB1_LEGACY_CTRL); | 434 | val = readl(base + USB1_LEGACY_CTRL); |
464 | val &= ~USB1_VBUS_SENSE_CTL_MASK; | 435 | val &= ~USB1_VBUS_SENSE_CTL_MASK; |
465 | val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; | 436 | val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD; |
@@ -472,11 +443,8 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy) | |||
472 | 443 | ||
473 | utmi_phy_clk_enable(phy); | 444 | utmi_phy_clk_enable(phy); |
474 | 445 | ||
475 | if (phy->instance == 2) { | 446 | if (!phy->is_legacy_phy) |
476 | val = readl(base + USB_PORTSC1); | 447 | tegra_ehci_set_pts(&phy->u_phy, 0); |
477 | val &= ~USB_PORTSC1_PTS(~0); | ||
478 | writel(val, base + USB_PORTSC1); | ||
479 | } | ||
480 | 448 | ||
481 | return 0; | 449 | return 0; |
482 | } | 450 | } |
@@ -621,10 +589,6 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) | |||
621 | return ret; | 589 | return ret; |
622 | } | 590 | } |
623 | 591 | ||
624 | val = readl(base + USB_PORTSC1); | ||
625 | val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN; | ||
626 | writel(val, base + USB_PORTSC1); | ||
627 | |||
628 | val = readl(base + USB_SUSP_CTRL); | 592 | val = readl(base + USB_SUSP_CTRL); |
629 | val |= USB_SUSP_CLR; | 593 | val |= USB_SUSP_CLR; |
630 | writel(val, base + USB_SUSP_CTRL); | 594 | writel(val, base + USB_SUSP_CTRL); |
@@ -639,17 +603,8 @@ static int ulpi_phy_power_on(struct tegra_usb_phy *phy) | |||
639 | 603 | ||
640 | static int ulpi_phy_power_off(struct tegra_usb_phy *phy) | 604 | static int ulpi_phy_power_off(struct tegra_usb_phy *phy) |
641 | { | 605 | { |
642 | unsigned long val; | ||
643 | void __iomem *base = phy->regs; | ||
644 | struct tegra_ulpi_config *config = phy->config; | 606 | struct tegra_ulpi_config *config = phy->config; |
645 | 607 | ||
646 | /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB | ||
647 | * Controller to immediately bring the ULPI PHY out of low power | ||
648 | */ | ||
649 | val = readl(base + USB_PORTSC1); | ||
650 | val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN); | ||
651 | writel(val, base + USB_PORTSC1); | ||
652 | |||
653 | clk_disable(phy->clk); | 608 | clk_disable(phy->clk); |
654 | return gpio_direction_output(config->reset_gpio, 0); | 609 | return gpio_direction_output(config->reset_gpio, 0); |
655 | } | 610 | } |
@@ -660,7 +615,7 @@ static int tegra_phy_init(struct usb_phy *x) | |||
660 | struct tegra_ulpi_config *ulpi_config; | 615 | struct tegra_ulpi_config *ulpi_config; |
661 | int err; | 616 | int err; |
662 | 617 | ||
663 | if (phy_is_ulpi(phy)) { | 618 | if (phy->is_ulpi_phy) { |
664 | ulpi_config = phy->config; | 619 | ulpi_config = phy->config; |
665 | phy->clk = clk_get_sys(NULL, ulpi_config->clk); | 620 | phy->clk = clk_get_sys(NULL, ulpi_config->clk); |
666 | if (IS_ERR(phy->clk)) { | 621 | if (IS_ERR(phy->clk)) { |
@@ -698,7 +653,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) | |||
698 | { | 653 | { |
699 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); | 654 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
700 | 655 | ||
701 | if (phy_is_ulpi(phy)) | 656 | if (phy->is_ulpi_phy) |
702 | clk_put(phy->clk); | 657 | clk_put(phy->clk); |
703 | else | 658 | else |
704 | utmip_pad_close(phy); | 659 | utmip_pad_close(phy); |
@@ -709,7 +664,7 @@ static void tegra_usb_phy_close(struct usb_phy *x) | |||
709 | 664 | ||
710 | static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) | 665 | static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) |
711 | { | 666 | { |
712 | if (phy_is_ulpi(phy)) | 667 | if (phy->is_ulpi_phy) |
713 | return ulpi_phy_power_on(phy); | 668 | return ulpi_phy_power_on(phy); |
714 | else | 669 | else |
715 | return utmi_phy_power_on(phy); | 670 | return utmi_phy_power_on(phy); |
@@ -717,7 +672,7 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) | |||
717 | 672 | ||
718 | static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) | 673 | static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy) |
719 | { | 674 | { |
720 | if (phy_is_ulpi(phy)) | 675 | if (phy->is_ulpi_phy) |
721 | return ulpi_phy_power_off(phy); | 676 | return ulpi_phy_power_off(phy); |
722 | else | 677 | else |
723 | return utmi_phy_power_off(phy); | 678 | return utmi_phy_power_off(phy); |
@@ -739,8 +694,9 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, | |||
739 | unsigned long parent_rate; | 694 | unsigned long parent_rate; |
740 | int i; | 695 | int i; |
741 | int err; | 696 | int err; |
697 | struct device_node *np = dev->of_node; | ||
742 | 698 | ||
743 | phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); | 699 | phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL); |
744 | if (!phy) | 700 | if (!phy) |
745 | return ERR_PTR(-ENOMEM); | 701 | return ERR_PTR(-ENOMEM); |
746 | 702 | ||
@@ -749,9 +705,16 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, | |||
749 | phy->config = config; | 705 | phy->config = config; |
750 | phy->mode = phy_mode; | 706 | phy->mode = phy_mode; |
751 | phy->dev = dev; | 707 | phy->dev = dev; |
708 | phy->is_legacy_phy = | ||
709 | of_property_read_bool(np, "nvidia,has-legacy-mode"); | ||
710 | err = of_property_match_string(np, "phy_type", "ulpi"); | ||
711 | if (err < 0) | ||
712 | phy->is_ulpi_phy = false; | ||
713 | else | ||
714 | phy->is_ulpi_phy = true; | ||
752 | 715 | ||
753 | if (!phy->config) { | 716 | if (!phy->config) { |
754 | if (phy_is_ulpi(phy)) { | 717 | if (phy->is_ulpi_phy) { |
755 | pr_err("%s: ulpi phy configuration missing", __func__); | 718 | pr_err("%s: ulpi phy configuration missing", __func__); |
756 | err = -EINVAL; | 719 | err = -EINVAL; |
757 | goto err0; | 720 | goto err0; |
@@ -796,45 +759,40 @@ err0: | |||
796 | } | 759 | } |
797 | EXPORT_SYMBOL_GPL(tegra_usb_phy_open); | 760 | EXPORT_SYMBOL_GPL(tegra_usb_phy_open); |
798 | 761 | ||
799 | void tegra_usb_phy_preresume(struct tegra_usb_phy *phy) | 762 | void tegra_usb_phy_preresume(struct usb_phy *x) |
800 | { | 763 | { |
801 | if (!phy_is_ulpi(phy)) | 764 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
765 | |||
766 | if (!phy->is_ulpi_phy) | ||
802 | utmi_phy_preresume(phy); | 767 | utmi_phy_preresume(phy); |
803 | } | 768 | } |
804 | EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); | 769 | EXPORT_SYMBOL_GPL(tegra_usb_phy_preresume); |
805 | 770 | ||
806 | void tegra_usb_phy_postresume(struct tegra_usb_phy *phy) | 771 | void tegra_usb_phy_postresume(struct usb_phy *x) |
807 | { | 772 | { |
808 | if (!phy_is_ulpi(phy)) | 773 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
774 | |||
775 | if (!phy->is_ulpi_phy) | ||
809 | utmi_phy_postresume(phy); | 776 | utmi_phy_postresume(phy); |
810 | } | 777 | } |
811 | EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); | 778 | EXPORT_SYMBOL_GPL(tegra_usb_phy_postresume); |
812 | 779 | ||
813 | void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, | 780 | void tegra_ehci_phy_restore_start(struct usb_phy *x, |
814 | enum tegra_usb_phy_port_speed port_speed) | 781 | enum tegra_usb_phy_port_speed port_speed) |
815 | { | 782 | { |
816 | if (!phy_is_ulpi(phy)) | 783 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
784 | |||
785 | if (!phy->is_ulpi_phy) | ||
817 | utmi_phy_restore_start(phy, port_speed); | 786 | utmi_phy_restore_start(phy, port_speed); |
818 | } | 787 | } |
819 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); | 788 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_start); |
820 | 789 | ||
821 | void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy) | 790 | void tegra_ehci_phy_restore_end(struct usb_phy *x) |
822 | { | 791 | { |
823 | if (!phy_is_ulpi(phy)) | 792 | struct tegra_usb_phy *phy = container_of(x, struct tegra_usb_phy, u_phy); |
793 | |||
794 | if (!phy->is_ulpi_phy) | ||
824 | utmi_phy_restore_end(phy); | 795 | utmi_phy_restore_end(phy); |
825 | } | 796 | } |
826 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); | 797 | EXPORT_SYMBOL_GPL(tegra_ehci_phy_restore_end); |
827 | 798 | ||
828 | void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy) | ||
829 | { | ||
830 | if (!phy_is_ulpi(phy)) | ||
831 | utmi_phy_clk_disable(phy); | ||
832 | } | ||
833 | EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_disable); | ||
834 | |||
835 | void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) | ||
836 | { | ||
837 | if (!phy_is_ulpi(phy)) | ||
838 | utmi_phy_clk_enable(phy); | ||
839 | } | ||
840 | EXPORT_SYMBOL_GPL(tegra_usb_phy_clk_enable); | ||