diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-14 17:57:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-14 17:57:16 -0500 |
commit | e7cf773d431a63a2417902696fcc9e0ebdc83bbe (patch) | |
tree | 86dbdceb7d91226507a3af0d57e03b0ca664b22e /drivers/phy/phy-exynos5-usbdrd.c | |
parent | 7a02d089695a1217992434f03a78aa32bad85b5c (diff) | |
parent | 81e1dadfb5b2d47aa513ad60b1c9cf0ea17b6514 (diff) |
Merge tag 'usb-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB updates from Greg KH:
"Here's the big set of USB and PHY patches for 3.19-rc1.
The normal churn in the USB gadget area is in here, as well as xhci
and other individual USB driver updates. The PHY tree is also in
here, as there were dependancies on the USB tree.
All of these have been in linux-next"
* tag 'usb-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (351 commits)
arm: omap3: twl: remove usb phy init data
usbip: fix error handling in stub_probe()
usb: gadget: udc: missing curly braces
USB: mos7720: delete some unneeded code
wusb: replace memset by memzero_explicit
usbip: remove unneeded structure
usb: xhci: fix comment for PORT_DEV_REMOVE
xhci: don't use the same variable for stopped and halted rings current TD
xhci: clear extra bits from slot context when setting max exit latency
xhci: cleanup finish_td function
USB: adutux: NULL dereferences on disconnect
usb: chipidea: fix platform_no_drv_owner.cocci warnings
usb: chipidea: Fixed a few typos in comments
Documentation: bindings: add doc for the USB2 ChipIdea USB driver
usb: chipidea: add a usb2 driver for ci13xxx
usb: chipidea: fix phy handling
usb: chipidea: remove duplicate dev_set_drvdata for host_start
usb: chipidea: parameter 'mode' isn't needed for hw_device_reset
usb: chipidea: add controller reset API
usb: chipidea: remove flag CI_HDRC_REQUIRE_TRANSCEIVER
...
Diffstat (limited to 'drivers/phy/phy-exynos5-usbdrd.c')
-rw-r--r-- | drivers/phy/phy-exynos5-usbdrd.c | 139 |
1 files changed, 117 insertions, 22 deletions
diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/phy-exynos5-usbdrd.c index f756aca871db..04374018425f 100644 --- a/drivers/phy/phy-exynos5-usbdrd.c +++ b/drivers/phy/phy-exynos5-usbdrd.c | |||
@@ -141,6 +141,7 @@ struct exynos5_usbdrd_phy_drvdata { | |||
141 | const struct exynos5_usbdrd_phy_config *phy_cfg; | 141 | const struct exynos5_usbdrd_phy_config *phy_cfg; |
142 | u32 pmu_offset_usbdrd0_phy; | 142 | u32 pmu_offset_usbdrd0_phy; |
143 | u32 pmu_offset_usbdrd1_phy; | 143 | u32 pmu_offset_usbdrd1_phy; |
144 | bool has_common_clk_gate; | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | /** | 147 | /** |
@@ -148,6 +149,9 @@ struct exynos5_usbdrd_phy_drvdata { | |||
148 | * @dev: pointer to device instance of this platform device | 149 | * @dev: pointer to device instance of this platform device |
149 | * @reg_phy: usb phy controller register memory base | 150 | * @reg_phy: usb phy controller register memory base |
150 | * @clk: phy clock for register access | 151 | * @clk: phy clock for register access |
152 | * @pipeclk: clock for pipe3 phy | ||
153 | * @utmiclk: clock for utmi+ phy | ||
154 | * @itpclk: clock for ITP generation | ||
151 | * @drv_data: pointer to SoC level driver data structure | 155 | * @drv_data: pointer to SoC level driver data structure |
152 | * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY | 156 | * @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY |
153 | * instances each with its 'phy' and 'phy_cfg'. | 157 | * instances each with its 'phy' and 'phy_cfg'. |
@@ -155,12 +159,16 @@ struct exynos5_usbdrd_phy_drvdata { | |||
155 | * reference clocks' for SS and HS operations | 159 | * reference clocks' for SS and HS operations |
156 | * @ref_clk: reference clock to PHY block from which PHY's | 160 | * @ref_clk: reference clock to PHY block from which PHY's |
157 | * operational clocks are derived | 161 | * operational clocks are derived |
158 | * @ref_rate: rate of above reference clock | 162 | * vbus: VBUS regulator for phy |
163 | * vbus_boost: Boost regulator for VBUS present on few Exynos boards | ||
159 | */ | 164 | */ |
160 | struct exynos5_usbdrd_phy { | 165 | struct exynos5_usbdrd_phy { |
161 | struct device *dev; | 166 | struct device *dev; |
162 | void __iomem *reg_phy; | 167 | void __iomem *reg_phy; |
163 | struct clk *clk; | 168 | struct clk *clk; |
169 | struct clk *pipeclk; | ||
170 | struct clk *utmiclk; | ||
171 | struct clk *itpclk; | ||
164 | const struct exynos5_usbdrd_phy_drvdata *drv_data; | 172 | const struct exynos5_usbdrd_phy_drvdata *drv_data; |
165 | struct phy_usb_instance { | 173 | struct phy_usb_instance { |
166 | struct phy *phy; | 174 | struct phy *phy; |
@@ -172,6 +180,7 @@ struct exynos5_usbdrd_phy { | |||
172 | u32 extrefclk; | 180 | u32 extrefclk; |
173 | struct clk *ref_clk; | 181 | struct clk *ref_clk; |
174 | struct regulator *vbus; | 182 | struct regulator *vbus; |
183 | struct regulator *vbus_boost; | ||
175 | }; | 184 | }; |
176 | 185 | ||
177 | static inline | 186 | static inline |
@@ -447,13 +456,27 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) | |||
447 | dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); | 456 | dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); |
448 | 457 | ||
449 | clk_prepare_enable(phy_drd->ref_clk); | 458 | clk_prepare_enable(phy_drd->ref_clk); |
459 | if (!phy_drd->drv_data->has_common_clk_gate) { | ||
460 | clk_prepare_enable(phy_drd->pipeclk); | ||
461 | clk_prepare_enable(phy_drd->utmiclk); | ||
462 | clk_prepare_enable(phy_drd->itpclk); | ||
463 | } | ||
450 | 464 | ||
451 | /* Enable VBUS supply */ | 465 | /* Enable VBUS supply */ |
466 | if (phy_drd->vbus_boost) { | ||
467 | ret = regulator_enable(phy_drd->vbus_boost); | ||
468 | if (ret) { | ||
469 | dev_err(phy_drd->dev, | ||
470 | "Failed to enable VBUS boost supply\n"); | ||
471 | goto fail_vbus; | ||
472 | } | ||
473 | } | ||
474 | |||
452 | if (phy_drd->vbus) { | 475 | if (phy_drd->vbus) { |
453 | ret = regulator_enable(phy_drd->vbus); | 476 | ret = regulator_enable(phy_drd->vbus); |
454 | if (ret) { | 477 | if (ret) { |
455 | dev_err(phy_drd->dev, "Failed to enable VBUS supply\n"); | 478 | dev_err(phy_drd->dev, "Failed to enable VBUS supply\n"); |
456 | goto fail_vbus; | 479 | goto fail_vbus_boost; |
457 | } | 480 | } |
458 | } | 481 | } |
459 | 482 | ||
@@ -462,8 +485,17 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) | |||
462 | 485 | ||
463 | return 0; | 486 | return 0; |
464 | 487 | ||
488 | fail_vbus_boost: | ||
489 | if (phy_drd->vbus_boost) | ||
490 | regulator_disable(phy_drd->vbus_boost); | ||
491 | |||
465 | fail_vbus: | 492 | fail_vbus: |
466 | clk_disable_unprepare(phy_drd->ref_clk); | 493 | clk_disable_unprepare(phy_drd->ref_clk); |
494 | if (!phy_drd->drv_data->has_common_clk_gate) { | ||
495 | clk_disable_unprepare(phy_drd->itpclk); | ||
496 | clk_disable_unprepare(phy_drd->utmiclk); | ||
497 | clk_disable_unprepare(phy_drd->pipeclk); | ||
498 | } | ||
467 | 499 | ||
468 | return ret; | 500 | return ret; |
469 | } | 501 | } |
@@ -481,8 +513,15 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy) | |||
481 | /* Disable VBUS supply */ | 513 | /* Disable VBUS supply */ |
482 | if (phy_drd->vbus) | 514 | if (phy_drd->vbus) |
483 | regulator_disable(phy_drd->vbus); | 515 | regulator_disable(phy_drd->vbus); |
516 | if (phy_drd->vbus_boost) | ||
517 | regulator_disable(phy_drd->vbus_boost); | ||
484 | 518 | ||
485 | clk_disable_unprepare(phy_drd->ref_clk); | 519 | clk_disable_unprepare(phy_drd->ref_clk); |
520 | if (!phy_drd->drv_data->has_common_clk_gate) { | ||
521 | clk_disable_unprepare(phy_drd->itpclk); | ||
522 | clk_disable_unprepare(phy_drd->pipeclk); | ||
523 | clk_disable_unprepare(phy_drd->utmiclk); | ||
524 | } | ||
486 | 525 | ||
487 | return 0; | 526 | return 0; |
488 | } | 527 | } |
@@ -506,6 +545,57 @@ static struct phy_ops exynos5_usbdrd_phy_ops = { | |||
506 | .owner = THIS_MODULE, | 545 | .owner = THIS_MODULE, |
507 | }; | 546 | }; |
508 | 547 | ||
548 | static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd) | ||
549 | { | ||
550 | unsigned long ref_rate; | ||
551 | int ret; | ||
552 | |||
553 | phy_drd->clk = devm_clk_get(phy_drd->dev, "phy"); | ||
554 | if (IS_ERR(phy_drd->clk)) { | ||
555 | dev_err(phy_drd->dev, "Failed to get phy clock\n"); | ||
556 | return PTR_ERR(phy_drd->clk); | ||
557 | } | ||
558 | |||
559 | phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref"); | ||
560 | if (IS_ERR(phy_drd->ref_clk)) { | ||
561 | dev_err(phy_drd->dev, "Failed to get phy reference clock\n"); | ||
562 | return PTR_ERR(phy_drd->ref_clk); | ||
563 | } | ||
564 | ref_rate = clk_get_rate(phy_drd->ref_clk); | ||
565 | |||
566 | ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); | ||
567 | if (ret) { | ||
568 | dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", | ||
569 | ref_rate); | ||
570 | return ret; | ||
571 | } | ||
572 | |||
573 | if (!phy_drd->drv_data->has_common_clk_gate) { | ||
574 | phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe"); | ||
575 | if (IS_ERR(phy_drd->pipeclk)) { | ||
576 | dev_info(phy_drd->dev, | ||
577 | "PIPE3 phy operational clock not specified\n"); | ||
578 | phy_drd->pipeclk = NULL; | ||
579 | } | ||
580 | |||
581 | phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi"); | ||
582 | if (IS_ERR(phy_drd->utmiclk)) { | ||
583 | dev_info(phy_drd->dev, | ||
584 | "UTMI phy operational clock not specified\n"); | ||
585 | phy_drd->utmiclk = NULL; | ||
586 | } | ||
587 | |||
588 | phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp"); | ||
589 | if (IS_ERR(phy_drd->itpclk)) { | ||
590 | dev_info(phy_drd->dev, | ||
591 | "ITP clock from main OSC not specified\n"); | ||
592 | phy_drd->itpclk = NULL; | ||
593 | } | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
509 | static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { | 599 | static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { |
510 | { | 600 | { |
511 | .id = EXYNOS5_DRDPHY_UTMI, | 601 | .id = EXYNOS5_DRDPHY_UTMI, |
@@ -525,11 +615,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { | |||
525 | .phy_cfg = phy_cfg_exynos5, | 615 | .phy_cfg = phy_cfg_exynos5, |
526 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, | 616 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, |
527 | .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, | 617 | .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, |
618 | .has_common_clk_gate = true, | ||
528 | }; | 619 | }; |
529 | 620 | ||
530 | static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { | 621 | static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { |
531 | .phy_cfg = phy_cfg_exynos5, | 622 | .phy_cfg = phy_cfg_exynos5, |
532 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, | 623 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, |
624 | .has_common_clk_gate = true, | ||
625 | }; | ||
626 | |||
627 | static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = { | ||
628 | .phy_cfg = phy_cfg_exynos5, | ||
629 | .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, | ||
630 | .has_common_clk_gate = false, | ||
533 | }; | 631 | }; |
534 | 632 | ||
535 | static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { | 633 | static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { |
@@ -539,6 +637,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { | |||
539 | }, { | 637 | }, { |
540 | .compatible = "samsung,exynos5420-usbdrd-phy", | 638 | .compatible = "samsung,exynos5420-usbdrd-phy", |
541 | .data = &exynos5420_usbdrd_phy | 639 | .data = &exynos5420_usbdrd_phy |
640 | }, { | ||
641 | .compatible = "samsung,exynos7-usbdrd-phy", | ||
642 | .data = &exynos7_usbdrd_phy | ||
542 | }, | 643 | }, |
543 | { }, | 644 | { }, |
544 | }; | 645 | }; |
@@ -555,7 +656,6 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) | |||
555 | const struct exynos5_usbdrd_phy_drvdata *drv_data; | 656 | const struct exynos5_usbdrd_phy_drvdata *drv_data; |
556 | struct regmap *reg_pmu; | 657 | struct regmap *reg_pmu; |
557 | u32 pmu_offset; | 658 | u32 pmu_offset; |
558 | unsigned long ref_rate; | ||
559 | int i, ret; | 659 | int i, ret; |
560 | int channel; | 660 | int channel; |
561 | 661 | ||
@@ -576,23 +676,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) | |||
576 | drv_data = match->data; | 676 | drv_data = match->data; |
577 | phy_drd->drv_data = drv_data; | 677 | phy_drd->drv_data = drv_data; |
578 | 678 | ||
579 | phy_drd->clk = devm_clk_get(dev, "phy"); | 679 | ret = exynos5_usbdrd_phy_clk_handle(phy_drd); |
580 | if (IS_ERR(phy_drd->clk)) { | ||
581 | dev_err(dev, "Failed to get clock of phy controller\n"); | ||
582 | return PTR_ERR(phy_drd->clk); | ||
583 | } | ||
584 | |||
585 | phy_drd->ref_clk = devm_clk_get(dev, "ref"); | ||
586 | if (IS_ERR(phy_drd->ref_clk)) { | ||
587 | dev_err(dev, "Failed to get reference clock of usbdrd phy\n"); | ||
588 | return PTR_ERR(phy_drd->ref_clk); | ||
589 | } | ||
590 | ref_rate = clk_get_rate(phy_drd->ref_clk); | ||
591 | |||
592 | ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); | ||
593 | if (ret) { | 680 | if (ret) { |
594 | dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n", | 681 | dev_err(dev, "Failed to initialize clocks\n"); |
595 | ref_rate); | ||
596 | return ret; | 682 | return ret; |
597 | } | 683 | } |
598 | 684 | ||
@@ -622,7 +708,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) | |||
622 | break; | 708 | break; |
623 | } | 709 | } |
624 | 710 | ||
625 | /* Get Vbus regulator */ | 711 | /* Get Vbus regulators */ |
626 | phy_drd->vbus = devm_regulator_get(dev, "vbus"); | 712 | phy_drd->vbus = devm_regulator_get(dev, "vbus"); |
627 | if (IS_ERR(phy_drd->vbus)) { | 713 | if (IS_ERR(phy_drd->vbus)) { |
628 | ret = PTR_ERR(phy_drd->vbus); | 714 | ret = PTR_ERR(phy_drd->vbus); |
@@ -633,12 +719,21 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) | |||
633 | phy_drd->vbus = NULL; | 719 | phy_drd->vbus = NULL; |
634 | } | 720 | } |
635 | 721 | ||
722 | phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost"); | ||
723 | if (IS_ERR(phy_drd->vbus_boost)) { | ||
724 | ret = PTR_ERR(phy_drd->vbus_boost); | ||
725 | if (ret == -EPROBE_DEFER) | ||
726 | return ret; | ||
727 | |||
728 | dev_warn(dev, "Failed to get VBUS boost supply regulator\n"); | ||
729 | phy_drd->vbus_boost = NULL; | ||
730 | } | ||
731 | |||
636 | dev_vdbg(dev, "Creating usbdrd_phy phy\n"); | 732 | dev_vdbg(dev, "Creating usbdrd_phy phy\n"); |
637 | 733 | ||
638 | for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { | 734 | for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) { |
639 | struct phy *phy = devm_phy_create(dev, NULL, | 735 | struct phy *phy = devm_phy_create(dev, NULL, |
640 | &exynos5_usbdrd_phy_ops, | 736 | &exynos5_usbdrd_phy_ops); |
641 | NULL); | ||
642 | if (IS_ERR(phy)) { | 737 | if (IS_ERR(phy)) { |
643 | dev_err(dev, "Failed to create usbdrd_phy phy\n"); | 738 | dev_err(dev, "Failed to create usbdrd_phy phy\n"); |
644 | return PTR_ERR(phy); | 739 | return PTR_ERR(phy); |