apss-ipq-pll.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // SPDX-License-Identifier: GPL-2.0
  2. // Copyright (c) 2018, The Linux Foundation. All rights reserved.
  3. #include <linux/clk-provider.h>
  4. #include <linux/module.h>
  5. #include <linux/of.h>
  6. #include <linux/platform_device.h>
  7. #include <linux/regmap.h>
  8. #include "clk-alpha-pll.h"
  9. static struct clk_alpha_pll ipq_pll_huayra = {
  10. .offset = 0x0,
  11. .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_HUAYRA_APSS],
  12. .flags = SUPPORTS_DYNAMIC_UPDATE,
  13. .clkr = {
  14. .enable_reg = 0x0,
  15. .enable_mask = BIT(0),
  16. .hw.init = &(const struct clk_init_data) {
  17. .name = "a53pll",
  18. .parent_data = &(const struct clk_parent_data) {
  19. .fw_name = "xo",
  20. },
  21. .num_parents = 1,
  22. .ops = &clk_alpha_pll_huayra_ops,
  23. },
  24. },
  25. };
  26. static struct clk_alpha_pll ipq_pll_stromer = {
  27. .offset = 0x0,
  28. .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER],
  29. .flags = SUPPORTS_DYNAMIC_UPDATE,
  30. .clkr = {
  31. .enable_reg = 0x0,
  32. .enable_mask = BIT(0),
  33. .hw.init = &(const struct clk_init_data) {
  34. .name = "a53pll",
  35. .parent_data = &(const struct clk_parent_data) {
  36. .fw_name = "xo",
  37. },
  38. .num_parents = 1,
  39. .ops = &clk_alpha_pll_stromer_ops,
  40. },
  41. },
  42. };
  43. static struct clk_alpha_pll ipq_pll_stromer_plus = {
  44. .offset = 0x0,
  45. /*
  46. * The register offsets of the Stromer Plus PLL used in IPQ5332
  47. * are the same as the Stromer PLL's offsets.
  48. */
  49. .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_STROMER],
  50. .flags = SUPPORTS_DYNAMIC_UPDATE,
  51. .clkr = {
  52. .enable_reg = 0x0,
  53. .enable_mask = BIT(0),
  54. .hw.init = &(const struct clk_init_data) {
  55. .name = "a53pll",
  56. .parent_data = &(const struct clk_parent_data) {
  57. .fw_name = "xo",
  58. },
  59. .num_parents = 1,
  60. .ops = &clk_alpha_pll_stromer_plus_ops,
  61. },
  62. },
  63. };
  64. /* 1.008 GHz configuration */
  65. static const struct alpha_pll_config ipq5018_pll_config = {
  66. .l = 0x2a,
  67. .config_ctl_val = 0x4001075b,
  68. .main_output_mask = BIT(0),
  69. .aux_output_mask = BIT(1),
  70. .early_output_mask = BIT(3),
  71. .alpha_en_mask = BIT(24),
  72. .status_val = 0x3,
  73. .status_mask = GENMASK(10, 8),
  74. .lock_det = BIT(2),
  75. .test_ctl_hi_val = 0x00400003,
  76. };
  77. static const struct alpha_pll_config ipq5332_pll_config = {
  78. .l = 0x2d,
  79. .config_ctl_val = 0x4001075b,
  80. .main_output_mask = BIT(0),
  81. .aux_output_mask = BIT(1),
  82. .early_output_mask = BIT(3),
  83. .alpha_en_mask = BIT(24),
  84. .status_val = 0x3,
  85. .status_mask = GENMASK(10, 8),
  86. .lock_det = BIT(2),
  87. .test_ctl_hi_val = 0x00400003,
  88. };
  89. static const struct alpha_pll_config ipq6018_pll_config = {
  90. .l = 0x37,
  91. .config_ctl_val = 0x240d4828,
  92. .config_ctl_hi_val = 0x6,
  93. .early_output_mask = BIT(3),
  94. .aux2_output_mask = BIT(2),
  95. .aux_output_mask = BIT(1),
  96. .main_output_mask = BIT(0),
  97. .test_ctl_val = 0x1c0000C0,
  98. .test_ctl_hi_val = 0x4000,
  99. };
  100. static const struct alpha_pll_config ipq8074_pll_config = {
  101. .l = 0x48,
  102. .config_ctl_val = 0x200d4828,
  103. .config_ctl_hi_val = 0x6,
  104. .early_output_mask = BIT(3),
  105. .aux2_output_mask = BIT(2),
  106. .aux_output_mask = BIT(1),
  107. .main_output_mask = BIT(0),
  108. .test_ctl_val = 0x1c000000,
  109. .test_ctl_hi_val = 0x4000,
  110. };
  111. static const struct alpha_pll_config ipq9574_pll_config = {
  112. .l = 0x3b,
  113. .config_ctl_val = 0x200d4828,
  114. .config_ctl_hi_val = 0x6,
  115. .early_output_mask = BIT(3),
  116. .aux2_output_mask = BIT(2),
  117. .aux_output_mask = BIT(1),
  118. .main_output_mask = BIT(0),
  119. .test_ctl_val = 0x0,
  120. .test_ctl_hi_val = 0x4000,
  121. };
  122. struct apss_pll_data {
  123. int pll_type;
  124. struct clk_alpha_pll *pll;
  125. const struct alpha_pll_config *pll_config;
  126. };
  127. static const struct apss_pll_data ipq5018_pll_data = {
  128. .pll_type = CLK_ALPHA_PLL_TYPE_STROMER,
  129. .pll = &ipq_pll_stromer,
  130. .pll_config = &ipq5018_pll_config,
  131. };
  132. static const struct apss_pll_data ipq5332_pll_data = {
  133. .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS,
  134. .pll = &ipq_pll_stromer_plus,
  135. .pll_config = &ipq5332_pll_config,
  136. };
  137. static const struct apss_pll_data ipq8074_pll_data = {
  138. .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA,
  139. .pll = &ipq_pll_huayra,
  140. .pll_config = &ipq8074_pll_config,
  141. };
  142. static const struct apss_pll_data ipq6018_pll_data = {
  143. .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA,
  144. .pll = &ipq_pll_huayra,
  145. .pll_config = &ipq6018_pll_config,
  146. };
  147. static const struct apss_pll_data ipq9574_pll_data = {
  148. .pll_type = CLK_ALPHA_PLL_TYPE_HUAYRA,
  149. .pll = &ipq_pll_huayra,
  150. .pll_config = &ipq9574_pll_config,
  151. };
  152. static const struct regmap_config ipq_pll_regmap_config = {
  153. .reg_bits = 32,
  154. .reg_stride = 4,
  155. .val_bits = 32,
  156. .max_register = 0x40,
  157. .fast_io = true,
  158. };
  159. static int apss_ipq_pll_probe(struct platform_device *pdev)
  160. {
  161. const struct apss_pll_data *data;
  162. struct device *dev = &pdev->dev;
  163. struct regmap *regmap;
  164. void __iomem *base;
  165. int ret;
  166. base = devm_platform_ioremap_resource(pdev, 0);
  167. if (IS_ERR(base))
  168. return PTR_ERR(base);
  169. regmap = devm_regmap_init_mmio(dev, base, &ipq_pll_regmap_config);
  170. if (IS_ERR(regmap))
  171. return PTR_ERR(regmap);
  172. data = of_device_get_match_data(&pdev->dev);
  173. if (!data)
  174. return -ENODEV;
  175. if (data->pll_type == CLK_ALPHA_PLL_TYPE_HUAYRA)
  176. clk_alpha_pll_configure(data->pll, regmap, data->pll_config);
  177. else if (data->pll_type == CLK_ALPHA_PLL_TYPE_STROMER ||
  178. data->pll_type == CLK_ALPHA_PLL_TYPE_STROMER_PLUS)
  179. clk_stromer_pll_configure(data->pll, regmap, data->pll_config);
  180. ret = devm_clk_register_regmap(dev, &data->pll->clkr);
  181. if (ret)
  182. return ret;
  183. return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
  184. &data->pll->clkr.hw);
  185. }
  186. static const struct of_device_id apss_ipq_pll_match_table[] = {
  187. { .compatible = "qcom,ipq5018-a53pll", .data = &ipq5018_pll_data },
  188. { .compatible = "qcom,ipq5332-a53pll", .data = &ipq5332_pll_data },
  189. { .compatible = "qcom,ipq6018-a53pll", .data = &ipq6018_pll_data },
  190. { .compatible = "qcom,ipq8074-a53pll", .data = &ipq8074_pll_data },
  191. { .compatible = "qcom,ipq9574-a73pll", .data = &ipq9574_pll_data },
  192. { }
  193. };
  194. MODULE_DEVICE_TABLE(of, apss_ipq_pll_match_table);
  195. static struct platform_driver apss_ipq_pll_driver = {
  196. .probe = apss_ipq_pll_probe,
  197. .driver = {
  198. .name = "qcom-ipq-apss-pll",
  199. .of_match_table = apss_ipq_pll_match_table,
  200. },
  201. };
  202. module_platform_driver(apss_ipq_pll_driver);
  203. MODULE_DESCRIPTION("Qualcomm technology Inc APSS ALPHA PLL Driver");
  204. MODULE_LICENSE("GPL v2");