dsi_pll.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2020, The Linux Foundation. All rights reserved.
  4. */
  5. #define pr_fmt(fmt) "%s: " fmt, __func__
  6. #include <linux/module.h>
  7. #include <linux/of_device.h>
  8. #include <linux/kernel.h>
  9. #include <linux/err.h>
  10. #include <linux/delay.h>
  11. #include <linux/iopoll.h>
  12. #include "dsi_pll.h"
  13. static int dsi_pll_clock_register(struct platform_device *pdev,
  14. struct dsi_pll_resource *pll_res)
  15. {
  16. int rc;
  17. switch (pll_res->pll_revision) {
  18. case DSI_PLL_5NM:
  19. rc = dsi_pll_clock_register_5nm(pdev, pll_res);
  20. break;
  21. default:
  22. rc = -EINVAL;
  23. break;
  24. }
  25. if (rc)
  26. DSI_PLL_ERR(pll_res, "clock register failed rc=%d\n", rc);
  27. return rc;
  28. }
  29. static inline int dsi_pll_get_ioresources(struct platform_device *pdev,
  30. void __iomem **regmap, char *resource_name)
  31. {
  32. int rc = 0;
  33. struct resource *rsc = platform_get_resource_byname(pdev,
  34. IORESOURCE_MEM, resource_name);
  35. if (rsc) {
  36. if (!regmap)
  37. return -ENOMEM;
  38. *regmap = devm_ioremap(&pdev->dev,
  39. rsc->start, resource_size(rsc));
  40. if (!*regmap)
  41. return -ENOMEM;
  42. }
  43. return rc;
  44. }
  45. int dsi_pll_init(struct platform_device *pdev, struct dsi_pll_resource **pll)
  46. {
  47. int rc = 0;
  48. const char *label;
  49. struct dsi_pll_resource *pll_res = NULL;
  50. if (!pdev->dev.of_node) {
  51. pr_err("Invalid DSI PHY node\n");
  52. return -ENOTSUPP;
  53. }
  54. pll_res = devm_kzalloc(&pdev->dev, sizeof(struct dsi_pll_resource),
  55. GFP_KERNEL);
  56. if (!pll_res)
  57. return -ENOMEM;
  58. *pll = pll_res;
  59. label = of_get_property(pdev->dev.of_node, "pll-label", NULL);
  60. if (!label) {
  61. DSI_PLL_ERR(pll_res, "DSI pll label not specified\n");
  62. return 0;
  63. }
  64. DSI_PLL_INFO(pll_res, "DSI pll label = %s\n", label);
  65. /**
  66. * Currently, Only supports 5nm PLL version. Will add
  67. * support for other versions as needed.
  68. */
  69. if (!strcmp(label, "dsi_pll_5nm"))
  70. pll_res->pll_revision = DSI_PLL_5NM;
  71. else
  72. return -ENOTSUPP;
  73. rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
  74. &pll_res->index);
  75. if (rc) {
  76. DSI_PLL_ERR(pll_res, "Unable to get the cell-index rc=%d\n", rc);
  77. pll_res->index = 0;
  78. }
  79. pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node,
  80. "qcom,dsi-pll-ssc-en");
  81. if (pll_res->ssc_en) {
  82. DSI_PLL_INFO(pll_res, "PLL SSC enabled\n");
  83. rc = of_property_read_u32(pdev->dev.of_node,
  84. "qcom,ssc-frequency-hz", &pll_res->ssc_freq);
  85. rc = of_property_read_u32(pdev->dev.of_node,
  86. "qcom,ssc-ppm", &pll_res->ssc_ppm);
  87. pll_res->ssc_center = false;
  88. label = of_get_property(pdev->dev.of_node,
  89. "qcom,dsi-pll-ssc-mode", NULL);
  90. if (label && !strcmp(label, "center-spread"))
  91. pll_res->ssc_center = true;
  92. }
  93. if (dsi_pll_get_ioresources(pdev, &pll_res->pll_base, "pll_base")) {
  94. DSI_PLL_ERR(pll_res, "Unable to remap pll base resources\n");
  95. return -ENOMEM;
  96. }
  97. pr_info("PLL base=%p\n", pll_res->pll_base);
  98. if (dsi_pll_get_ioresources(pdev, &pll_res->phy_base, "dsi_phy")) {
  99. DSI_PLL_ERR(pll_res, "Unable to remap pll phy base resources\n");
  100. return -ENOMEM;
  101. }
  102. if (dsi_pll_get_ioresources(pdev, &pll_res->dyn_pll_base,
  103. "dyn_refresh_base")) {
  104. DSI_PLL_ERR(pll_res, "Unable to remap dynamic pll base resources\n");
  105. return -ENOMEM;
  106. }
  107. if (dsi_pll_get_ioresources(pdev, &pll_res->gdsc_base, "gdsc_base")) {
  108. DSI_PLL_ERR(pll_res, "Unable to remap gdsc base resources\n");
  109. return -ENOMEM;
  110. }
  111. rc = dsi_pll_clock_register(pdev, pll_res);
  112. if (rc) {
  113. DSI_PLL_ERR(pll_res, "clock register failed rc=%d\n", rc);
  114. return -EINVAL;
  115. }
  116. return rc;
  117. }