aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phy/phy-exynos5-usbdrd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy/phy-exynos5-usbdrd.c')
-rw-r--r--drivers/phy/phy-exynos5-usbdrd.c139
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 */
160struct exynos5_usbdrd_phy { 165struct 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
177static inline 186static 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
488fail_vbus_boost:
489 if (phy_drd->vbus_boost)
490 regulator_disable(phy_drd->vbus_boost);
491
465fail_vbus: 492fail_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
548static 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
509static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { 599static 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
530static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { 621static 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
627static 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
535static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { 633static 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);