dp_pll.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/err.h>
  6. #include <linux/of_device.h>
  7. #include "dp_debug.h"
  8. #include "dp_pll.h"
  9. static int dp_pll_fill_io(struct dp_pll *pll)
  10. {
  11. struct dp_parser *parser = pll->parser;
  12. pll->io.dp_phy = parser->get_io(parser, "dp_phy");
  13. if (!pll->io.dp_phy) {
  14. DP_ERR("Invalid dp_phy resource\n");
  15. return -ENOMEM;
  16. }
  17. pll->io.dp_pll = parser->get_io(parser, "dp_pll");
  18. if (!pll->io.dp_pll) {
  19. DP_ERR("Invalid dp_pll resource\n");
  20. return -ENOMEM;
  21. }
  22. pll->io.dp_ln_tx0 = parser->get_io(parser, "dp_ln_tx0");
  23. if (!pll->io.dp_ln_tx0) {
  24. DP_ERR("Invalid dp_ln_tx1 resource\n");
  25. return -ENOMEM;
  26. }
  27. pll->io.dp_ln_tx1 = parser->get_io(parser, "dp_ln_tx1");
  28. if (!pll->io.dp_ln_tx1) {
  29. DP_ERR("Invalid dp_ln_tx1 resource\n");
  30. return -ENOMEM;
  31. }
  32. pll->io.gdsc = parser->get_io(parser, "gdsc");
  33. if (!pll->io.gdsc) {
  34. DP_ERR("Invalid gdsc resource\n");
  35. return -ENOMEM;
  36. }
  37. return 0;
  38. }
  39. static int dp_pll_clock_register(struct dp_pll *pll)
  40. {
  41. int rc;
  42. switch (pll->revision) {
  43. case DP_PLL_5NM_V1:
  44. case DP_PLL_5NM_V2:
  45. rc = dp_pll_clock_register_5nm(pll);
  46. break;
  47. default:
  48. rc = -ENOTSUPP;
  49. break;
  50. }
  51. return rc;
  52. }
  53. static void dp_pll_clock_unregister(struct dp_pll *pll)
  54. {
  55. switch (pll->revision) {
  56. case DP_PLL_5NM_V1:
  57. case DP_PLL_5NM_V2:
  58. dp_pll_clock_unregister_5nm(pll);
  59. break;
  60. default:
  61. break;
  62. }
  63. }
  64. int dp_pll_clock_register_helper(struct dp_pll *pll, struct dp_pll_vco_clk *clks, int num_clks)
  65. {
  66. int rc = 0, i = 0;
  67. struct platform_device *pdev;
  68. struct clk *clk;
  69. if (!pll || !clks) {
  70. DP_ERR("input not initialized\n");
  71. return -EINVAL;
  72. }
  73. pdev = pll->pdev;
  74. for (i = 0; i < num_clks; i++) {
  75. clks[i].priv = pll;
  76. clk = clk_register(&pdev->dev, &clks[i].hw);
  77. if (IS_ERR(clk)) {
  78. DP_ERR("%s registration failed for DP: %d\n",
  79. clk_hw_get_name(&clks[i].hw), pll->index);
  80. return -EINVAL;
  81. }
  82. pll->clk_data->clks[i] = clk;
  83. }
  84. return rc;
  85. }
  86. struct dp_pll *dp_pll_get(struct dp_pll_in *in)
  87. {
  88. int rc = 0;
  89. struct dp_pll *pll;
  90. struct dp_parser *parser;
  91. const char *label = NULL;
  92. struct platform_device *pdev;
  93. if (!in || !in->pdev || !in->pdev->dev.of_node || !in->parser) {
  94. DP_ERR("Invalid resource pointers\n");
  95. return ERR_PTR(-EINVAL);
  96. }
  97. pll = kzalloc(sizeof(*pll), GFP_KERNEL);
  98. if (!pll)
  99. return ERR_PTR(-ENOMEM);
  100. pll->pdev = in->pdev;
  101. pll->parser = in->parser;
  102. pll->aux = in->aux;
  103. pll->dp_core_revision = in->dp_core_revision;
  104. parser = pll->parser;
  105. pdev = pll->pdev;
  106. label = of_get_property(pdev->dev.of_node, "qcom,pll-revision", NULL);
  107. if (label) {
  108. if (!strcmp(label, "5nm-v1")) {
  109. pll->revision = DP_PLL_5NM_V1;
  110. } else if (!strcmp(label, "5nm-v2")) {
  111. pll->revision = DP_PLL_5NM_V2;
  112. } else {
  113. DP_ERR("Unsupported pll revision\n");
  114. rc = -ENOTSUPP;
  115. goto error;
  116. }
  117. } else {
  118. DP_ERR("pll revision not specified\n");
  119. rc = -EINVAL;
  120. goto error;
  121. }
  122. pll->ssc_en = of_property_read_bool(pdev->dev.of_node,
  123. "qcom,ssc-feature-enable");
  124. pll->bonding_en = of_property_read_bool(pdev->dev.of_node,
  125. "qcom,bonding-feature-enable");
  126. rc = dp_pll_fill_io(pll);
  127. if (rc)
  128. goto error;
  129. rc = dp_pll_clock_register(pll);
  130. if (rc)
  131. goto error;
  132. DP_INFO("revision=%s, ssc_en=%d, bonding_en=%d\n",
  133. dp_pll_get_revision(pll->revision), pll->ssc_en,
  134. pll->bonding_en);
  135. return pll;
  136. error:
  137. kfree(pll);
  138. return ERR_PTR(rc);
  139. }
  140. void dp_pll_put(struct dp_pll *pll)
  141. {
  142. dp_pll_clock_unregister(pll);
  143. kfree(pll);
  144. }