dp_pll.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2016-2020, 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. struct dp_pll *dp_pll_get(struct dp_pll_in *in)
  65. {
  66. int rc = 0;
  67. struct dp_pll *pll;
  68. struct dp_parser *parser;
  69. const char *label = NULL;
  70. struct platform_device *pdev;
  71. if (!in || !in->pdev || !in->pdev->dev.of_node || !in->parser) {
  72. DP_ERR("Invalid resource pointers\n");
  73. return ERR_PTR(-EINVAL);
  74. }
  75. pll = kzalloc(sizeof(*pll), GFP_KERNEL);
  76. if (!pll)
  77. return ERR_PTR(-ENOMEM);
  78. pll->pdev = in->pdev;
  79. pll->parser = in->parser;
  80. pll->aux = in->aux;
  81. parser = pll->parser;
  82. pdev = pll->pdev;
  83. label = of_get_property(pdev->dev.of_node, "qcom,pll-revision", NULL);
  84. if (label) {
  85. if (!strcmp(label, "5nm-v1")) {
  86. pll->revision = DP_PLL_5NM_V1;
  87. } else if (!strcmp(label, "5nm-v2")) {
  88. pll->revision = DP_PLL_5NM_V2;
  89. } else {
  90. DP_ERR("Unsupported pll revision\n");
  91. rc = -ENOTSUPP;
  92. goto error;
  93. }
  94. } else {
  95. DP_ERR("pll revision not specified\n");
  96. rc = -EINVAL;
  97. goto error;
  98. }
  99. pll->ssc_en = of_property_read_bool(pdev->dev.of_node,
  100. "qcom,ssc-feature-enable");
  101. pll->bonding_en = of_property_read_bool(pdev->dev.of_node,
  102. "qcom,bonding-feature-enable");
  103. rc = dp_pll_fill_io(pll);
  104. if (rc)
  105. goto error;
  106. rc = dp_pll_clock_register(pll);
  107. if (rc)
  108. goto error;
  109. DP_INFO("revision=%s, ssc_en=%d, bonding_en=%d\n",
  110. dp_pll_get_revision(pll->revision), pll->ssc_en,
  111. pll->bonding_en);
  112. return pll;
  113. error:
  114. kfree(pll);
  115. return ERR_PTR(rc);
  116. }
  117. void dp_pll_put(struct dp_pll *pll)
  118. {
  119. dp_pll_clock_unregister(pll);
  120. kfree(pll);
  121. }