ap806-system-controller.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * Marvell Armada AP806 System Controller
  3. *
  4. * Copyright (C) 2016 Marvell
  5. *
  6. * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
  7. *
  8. * This file is licensed under the terms of the GNU General Public
  9. * License version 2. This program is licensed "as is" without any
  10. * warranty of any kind, whether express or implied.
  11. */
  12. #define pr_fmt(fmt) "ap806-system-controller: " fmt
  13. #include <linux/clk-provider.h>
  14. #include <linux/mfd/syscon.h>
  15. #include <linux/init.h>
  16. #include <linux/of.h>
  17. #include <linux/of_address.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/regmap.h>
  20. #define AP806_SAR_REG 0x400
  21. #define AP806_SAR_CLKFREQ_MODE_MASK 0x1f
  22. #define AP806_CLK_NUM 5
  23. static struct clk *ap806_clks[AP806_CLK_NUM];
  24. static struct clk_onecell_data ap806_clk_data = {
  25. .clks = ap806_clks,
  26. .clk_num = AP806_CLK_NUM,
  27. };
  28. static char *ap806_unique_name(struct device *dev, struct device_node *np,
  29. char *name)
  30. {
  31. const __be32 *reg;
  32. u64 addr;
  33. reg = of_get_property(np, "reg", NULL);
  34. addr = of_translate_address(np, reg);
  35. return devm_kasprintf(dev, GFP_KERNEL, "%llx-%s",
  36. (unsigned long long)addr, name);
  37. }
  38. static int ap806_syscon_common_probe(struct platform_device *pdev,
  39. struct device_node *syscon_node)
  40. {
  41. unsigned int freq_mode, cpuclk_freq;
  42. const char *name, *fixedclk_name;
  43. struct device *dev = &pdev->dev;
  44. struct device_node *np = dev->of_node;
  45. struct regmap *regmap;
  46. u32 reg;
  47. int ret;
  48. regmap = syscon_node_to_regmap(syscon_node);
  49. if (IS_ERR(regmap)) {
  50. dev_err(dev, "cannot get regmap\n");
  51. return PTR_ERR(regmap);
  52. }
  53. ret = regmap_read(regmap, AP806_SAR_REG, &reg);
  54. if (ret) {
  55. dev_err(dev, "cannot read from regmap\n");
  56. return ret;
  57. }
  58. freq_mode = reg & AP806_SAR_CLKFREQ_MODE_MASK;
  59. switch (freq_mode) {
  60. case 0x0:
  61. case 0x1:
  62. cpuclk_freq = 2000;
  63. break;
  64. case 0x6:
  65. case 0x7:
  66. cpuclk_freq = 1800;
  67. break;
  68. case 0x4:
  69. case 0xB:
  70. case 0xD:
  71. cpuclk_freq = 1600;
  72. break;
  73. case 0x1a:
  74. cpuclk_freq = 1400;
  75. break;
  76. case 0x14:
  77. case 0x17:
  78. cpuclk_freq = 1300;
  79. break;
  80. case 0x19:
  81. cpuclk_freq = 1200;
  82. break;
  83. case 0x13:
  84. case 0x1d:
  85. cpuclk_freq = 1000;
  86. break;
  87. case 0x1c:
  88. cpuclk_freq = 800;
  89. break;
  90. case 0x1b:
  91. cpuclk_freq = 600;
  92. break;
  93. default:
  94. dev_err(dev, "invalid SAR value\n");
  95. return -EINVAL;
  96. }
  97. /* Convert to hertz */
  98. cpuclk_freq *= 1000 * 1000;
  99. /* CPU clocks depend on the Sample At Reset configuration */
  100. name = ap806_unique_name(dev, syscon_node, "cpu-cluster-0");
  101. ap806_clks[0] = clk_register_fixed_rate(dev, name, NULL,
  102. 0, cpuclk_freq);
  103. if (IS_ERR(ap806_clks[0])) {
  104. ret = PTR_ERR(ap806_clks[0]);
  105. goto fail0;
  106. }
  107. name = ap806_unique_name(dev, syscon_node, "cpu-cluster-1");
  108. ap806_clks[1] = clk_register_fixed_rate(dev, name, NULL, 0,
  109. cpuclk_freq);
  110. if (IS_ERR(ap806_clks[1])) {
  111. ret = PTR_ERR(ap806_clks[1]);
  112. goto fail1;
  113. }
  114. /* Fixed clock is always 1200 Mhz */
  115. fixedclk_name = ap806_unique_name(dev, syscon_node, "fixed");
  116. ap806_clks[2] = clk_register_fixed_rate(dev, fixedclk_name, NULL,
  117. 0, 1200 * 1000 * 1000);
  118. if (IS_ERR(ap806_clks[2])) {
  119. ret = PTR_ERR(ap806_clks[2]);
  120. goto fail2;
  121. }
  122. /* MSS Clock is fixed clock divided by 6 */
  123. name = ap806_unique_name(dev, syscon_node, "mss");
  124. ap806_clks[3] = clk_register_fixed_factor(NULL, name, fixedclk_name,
  125. 0, 1, 6);
  126. if (IS_ERR(ap806_clks[3])) {
  127. ret = PTR_ERR(ap806_clks[3]);
  128. goto fail3;
  129. }
  130. /* SDIO(/eMMC) Clock is fixed clock divided by 3 */
  131. name = ap806_unique_name(dev, syscon_node, "sdio");
  132. ap806_clks[4] = clk_register_fixed_factor(NULL, name,
  133. fixedclk_name,
  134. 0, 1, 3);
  135. if (IS_ERR(ap806_clks[4])) {
  136. ret = PTR_ERR(ap806_clks[4]);
  137. goto fail4;
  138. }
  139. of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
  140. ret = of_clk_add_provider(np, of_clk_src_onecell_get, &ap806_clk_data);
  141. if (ret)
  142. goto fail_clk_add;
  143. return 0;
  144. fail_clk_add:
  145. clk_unregister_fixed_factor(ap806_clks[4]);
  146. fail4:
  147. clk_unregister_fixed_factor(ap806_clks[3]);
  148. fail3:
  149. clk_unregister_fixed_rate(ap806_clks[2]);
  150. fail2:
  151. clk_unregister_fixed_rate(ap806_clks[1]);
  152. fail1:
  153. clk_unregister_fixed_rate(ap806_clks[0]);
  154. fail0:
  155. return ret;
  156. }
  157. static int ap806_syscon_legacy_probe(struct platform_device *pdev)
  158. {
  159. dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n");
  160. dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n");
  161. dev_warn(&pdev->dev, FW_WARN
  162. "This binding won't be supported in future kernel\n");
  163. return ap806_syscon_common_probe(pdev, pdev->dev.of_node);
  164. }
  165. static int ap806_clock_probe(struct platform_device *pdev)
  166. {
  167. return ap806_syscon_common_probe(pdev, pdev->dev.of_node->parent);
  168. }
  169. static const struct of_device_id ap806_syscon_legacy_of_match[] = {
  170. { .compatible = "marvell,ap806-system-controller", },
  171. { }
  172. };
  173. static struct platform_driver ap806_syscon_legacy_driver = {
  174. .probe = ap806_syscon_legacy_probe,
  175. .driver = {
  176. .name = "marvell-ap806-system-controller",
  177. .of_match_table = ap806_syscon_legacy_of_match,
  178. .suppress_bind_attrs = true,
  179. },
  180. };
  181. builtin_platform_driver(ap806_syscon_legacy_driver);
  182. static const struct of_device_id ap806_clock_of_match[] = {
  183. { .compatible = "marvell,ap806-clock", },
  184. { }
  185. };
  186. static struct platform_driver ap806_clock_driver = {
  187. .probe = ap806_clock_probe,
  188. .driver = {
  189. .name = "marvell-ap806-clock",
  190. .of_match_table = ap806_clock_of_match,
  191. .suppress_bind_attrs = true,
  192. },
  193. };
  194. builtin_platform_driver(ap806_clock_driver);