dsi_pll.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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_INFO(pll_res, "DSI pll label not specified\n");
  62. else
  63. DSI_PLL_INFO(pll_res, "DSI pll label = %s\n", label);
  64. /**
  65. * Currently, Only supports 5nm PLL version. Will add
  66. * support for other versions as needed.
  67. */
  68. if (!strcmp(label, "dsi_pll_5nm"))
  69. pll_res->pll_revision = DSI_PLL_5NM;
  70. else
  71. return -ENOTSUPP;
  72. rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
  73. &pll_res->index);
  74. if (rc) {
  75. DSI_PLL_ERR(pll_res, "Unable to get the cell-index rc=%d\n", rc);
  76. pll_res->index = 0;
  77. }
  78. pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node,
  79. "qcom,dsi-pll-ssc-en");
  80. if (pll_res->ssc_en) {
  81. DSI_PLL_INFO(pll_res, "PLL SSC enabled\n");
  82. rc = of_property_read_u32(pdev->dev.of_node,
  83. "qcom,ssc-frequency-hz", &pll_res->ssc_freq);
  84. rc = of_property_read_u32(pdev->dev.of_node,
  85. "qcom,ssc-ppm", &pll_res->ssc_ppm);
  86. pll_res->ssc_center = false;
  87. label = of_get_property(pdev->dev.of_node,
  88. "qcom,dsi-pll-ssc-mode", NULL);
  89. if (label && !strcmp(label, "center-spread"))
  90. pll_res->ssc_center = true;
  91. }
  92. if (dsi_pll_get_ioresources(pdev, &pll_res->pll_base, "pll_base")) {
  93. DSI_PLL_ERR(pll_res, "Unable to remap pll base resources\n");
  94. return -ENOMEM;
  95. }
  96. pr_info("PLL base=%p\n", pll_res->pll_base);
  97. if (dsi_pll_get_ioresources(pdev, &pll_res->phy_base, "dsi_phy")) {
  98. DSI_PLL_ERR(pll_res, "Unable to remap pll phy base resources\n");
  99. return -ENOMEM;
  100. }
  101. if (dsi_pll_get_ioresources(pdev, &pll_res->dyn_pll_base,
  102. "dyn_refresh_base")) {
  103. DSI_PLL_ERR(pll_res, "Unable to remap dynamic pll base resources\n");
  104. return -ENOMEM;
  105. }
  106. if (dsi_pll_get_ioresources(pdev, &pll_res->gdsc_base, "gdsc_base")) {
  107. DSI_PLL_ERR(pll_res, "Unable to remap gdsc base resources\n");
  108. return -ENOMEM;
  109. }
  110. rc = dsi_pll_clock_register(pdev, pll_res);
  111. if (rc) {
  112. DSI_PLL_ERR(pll_res, "clock register failed rc=%d\n", rc);
  113. return -EINVAL;
  114. }
  115. return rc;
  116. }