phy-mtk-hdmi.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2018 MediaTek Inc.
  4. * Author: Jie Qiu <[email protected]>
  5. */
  6. #include "phy-mtk-hdmi.h"
  7. static int mtk_hdmi_phy_power_on(struct phy *phy);
  8. static int mtk_hdmi_phy_power_off(struct phy *phy);
  9. static const struct phy_ops mtk_hdmi_phy_dev_ops = {
  10. .power_on = mtk_hdmi_phy_power_on,
  11. .power_off = mtk_hdmi_phy_power_off,
  12. .owner = THIS_MODULE,
  13. };
  14. inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw)
  15. {
  16. return container_of(hw, struct mtk_hdmi_phy, pll_hw);
  17. }
  18. static int mtk_hdmi_phy_power_on(struct phy *phy)
  19. {
  20. struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
  21. int ret;
  22. ret = clk_prepare_enable(hdmi_phy->pll);
  23. if (ret < 0)
  24. return ret;
  25. hdmi_phy->conf->hdmi_phy_enable_tmds(hdmi_phy);
  26. return 0;
  27. }
  28. static int mtk_hdmi_phy_power_off(struct phy *phy)
  29. {
  30. struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
  31. hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy);
  32. clk_disable_unprepare(hdmi_phy->pll);
  33. return 0;
  34. }
  35. static const struct phy_ops *
  36. mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy)
  37. {
  38. if (hdmi_phy && hdmi_phy->conf &&
  39. hdmi_phy->conf->hdmi_phy_enable_tmds &&
  40. hdmi_phy->conf->hdmi_phy_disable_tmds)
  41. return &mtk_hdmi_phy_dev_ops;
  42. if (hdmi_phy)
  43. dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n");
  44. return NULL;
  45. }
  46. static void mtk_hdmi_phy_clk_get_data(struct mtk_hdmi_phy *hdmi_phy,
  47. struct clk_init_data *clk_init)
  48. {
  49. clk_init->flags = hdmi_phy->conf->flags;
  50. clk_init->ops = hdmi_phy->conf->hdmi_phy_clk_ops;
  51. }
  52. static int mtk_hdmi_phy_probe(struct platform_device *pdev)
  53. {
  54. struct device *dev = &pdev->dev;
  55. struct mtk_hdmi_phy *hdmi_phy;
  56. struct clk *ref_clk;
  57. const char *ref_clk_name;
  58. struct clk_init_data clk_init = {
  59. .num_parents = 1,
  60. .parent_names = (const char * const *)&ref_clk_name,
  61. };
  62. struct phy *phy;
  63. struct phy_provider *phy_provider;
  64. int ret;
  65. hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL);
  66. if (!hdmi_phy)
  67. return -ENOMEM;
  68. hdmi_phy->regs = devm_platform_ioremap_resource(pdev, 0);
  69. if (IS_ERR(hdmi_phy->regs))
  70. return PTR_ERR(hdmi_phy->regs);
  71. ref_clk = devm_clk_get(dev, "pll_ref");
  72. if (IS_ERR(ref_clk))
  73. return dev_err_probe(dev, PTR_ERR(ref_clk),
  74. "Failed to get PLL reference clock\n");
  75. ref_clk_name = __clk_get_name(ref_clk);
  76. ret = of_property_read_string(dev->of_node, "clock-output-names",
  77. &clk_init.name);
  78. if (ret < 0)
  79. return dev_err_probe(dev, ret, "Failed to read clock-output-names\n");
  80. hdmi_phy->dev = dev;
  81. hdmi_phy->conf =
  82. (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev);
  83. mtk_hdmi_phy_clk_get_data(hdmi_phy, &clk_init);
  84. hdmi_phy->pll_hw.init = &clk_init;
  85. hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw);
  86. if (IS_ERR(hdmi_phy->pll))
  87. return dev_err_probe(dev, PTR_ERR(hdmi_phy->pll),
  88. "Failed to register PLL\n");
  89. ret = of_property_read_u32(dev->of_node, "mediatek,ibias",
  90. &hdmi_phy->ibias);
  91. if (ret < 0)
  92. return dev_err_probe(dev, ret, "Failed to get ibias\n");
  93. ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up",
  94. &hdmi_phy->ibias_up);
  95. if (ret < 0)
  96. return dev_err_probe(dev, ret, "Failed to get ibias_up\n");
  97. dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n");
  98. hdmi_phy->drv_imp_clk = 0x30;
  99. hdmi_phy->drv_imp_d2 = 0x30;
  100. hdmi_phy->drv_imp_d1 = 0x30;
  101. hdmi_phy->drv_imp_d0 = 0x30;
  102. phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy));
  103. if (IS_ERR(phy))
  104. return dev_err_probe(dev, PTR_ERR(phy), "Cannot create HDMI PHY\n");
  105. phy_set_drvdata(phy, hdmi_phy);
  106. phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
  107. if (IS_ERR(phy_provider))
  108. return dev_err_probe(dev, PTR_ERR(phy_provider),
  109. "Failed to register HDMI PHY\n");
  110. if (hdmi_phy->conf->pll_default_off)
  111. hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy);
  112. return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
  113. hdmi_phy->pll);
  114. }
  115. static const struct of_device_id mtk_hdmi_phy_match[] = {
  116. { .compatible = "mediatek,mt2701-hdmi-phy",
  117. .data = &mtk_hdmi_phy_2701_conf,
  118. },
  119. { .compatible = "mediatek,mt8173-hdmi-phy",
  120. .data = &mtk_hdmi_phy_8173_conf,
  121. },
  122. {},
  123. };
  124. MODULE_DEVICE_TABLE(of, mtk_hdmi_phy_match);
  125. static struct platform_driver mtk_hdmi_phy_driver = {
  126. .probe = mtk_hdmi_phy_probe,
  127. .driver = {
  128. .name = "mediatek-hdmi-phy",
  129. .of_match_table = mtk_hdmi_phy_match,
  130. },
  131. };
  132. module_platform_driver(mtk_hdmi_phy_driver);
  133. MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
  134. MODULE_LICENSE("GPL v2");