clk-scpi.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. * System Control and Power Interface (SCPI) Protocol based clock driver
  3. *
  4. * Copyright (C) 2015 ARM Ltd.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms and conditions of the GNU General Public License,
  8. * version 2, as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with
  16. * this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <linux/clk-provider.h>
  19. #include <linux/device.h>
  20. #include <linux/err.h>
  21. #include <linux/of.h>
  22. #include <linux/module.h>
  23. #include <linux/of_platform.h>
  24. #include <linux/platform_device.h>
  25. #include <linux/scpi_protocol.h>
  26. struct scpi_clk {
  27. u32 id;
  28. struct clk_hw hw;
  29. struct scpi_dvfs_info *info;
  30. struct scpi_ops *scpi_ops;
  31. };
  32. #define to_scpi_clk(clk) container_of(clk, struct scpi_clk, hw)
  33. static struct platform_device *cpufreq_dev;
  34. static unsigned long scpi_clk_recalc_rate(struct clk_hw *hw,
  35. unsigned long parent_rate)
  36. {
  37. struct scpi_clk *clk = to_scpi_clk(hw);
  38. return clk->scpi_ops->clk_get_val(clk->id);
  39. }
  40. static long scpi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
  41. unsigned long *parent_rate)
  42. {
  43. /*
  44. * We can't figure out what rate it will be, so just return the
  45. * rate back to the caller. scpi_clk_recalc_rate() will be called
  46. * after the rate is set and we'll know what rate the clock is
  47. * running at then.
  48. */
  49. return rate;
  50. }
  51. static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
  52. unsigned long parent_rate)
  53. {
  54. struct scpi_clk *clk = to_scpi_clk(hw);
  55. return clk->scpi_ops->clk_set_val(clk->id, rate);
  56. }
  57. static const struct clk_ops scpi_clk_ops = {
  58. .recalc_rate = scpi_clk_recalc_rate,
  59. .round_rate = scpi_clk_round_rate,
  60. .set_rate = scpi_clk_set_rate,
  61. };
  62. /* find closest match to given frequency in OPP table */
  63. static long __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
  64. {
  65. int idx;
  66. unsigned long fmin = 0, fmax = ~0, ftmp;
  67. const struct scpi_opp *opp = clk->info->opps;
  68. for (idx = 0; idx < clk->info->count; idx++, opp++) {
  69. ftmp = opp->freq;
  70. if (ftmp >= rate) {
  71. if (ftmp <= fmax)
  72. fmax = ftmp;
  73. break;
  74. } else if (ftmp >= fmin) {
  75. fmin = ftmp;
  76. }
  77. }
  78. return fmax != ~0 ? fmax : fmin;
  79. }
  80. static unsigned long scpi_dvfs_recalc_rate(struct clk_hw *hw,
  81. unsigned long parent_rate)
  82. {
  83. struct scpi_clk *clk = to_scpi_clk(hw);
  84. int idx = clk->scpi_ops->dvfs_get_idx(clk->id);
  85. const struct scpi_opp *opp;
  86. if (idx < 0)
  87. return 0;
  88. opp = clk->info->opps + idx;
  89. return opp->freq;
  90. }
  91. static long scpi_dvfs_round_rate(struct clk_hw *hw, unsigned long rate,
  92. unsigned long *parent_rate)
  93. {
  94. struct scpi_clk *clk = to_scpi_clk(hw);
  95. return __scpi_dvfs_round_rate(clk, rate);
  96. }
  97. static int __scpi_find_dvfs_index(struct scpi_clk *clk, unsigned long rate)
  98. {
  99. int idx, max_opp = clk->info->count;
  100. const struct scpi_opp *opp = clk->info->opps;
  101. for (idx = 0; idx < max_opp; idx++, opp++)
  102. if (opp->freq == rate)
  103. return idx;
  104. return -EINVAL;
  105. }
  106. static int scpi_dvfs_set_rate(struct clk_hw *hw, unsigned long rate,
  107. unsigned long parent_rate)
  108. {
  109. struct scpi_clk *clk = to_scpi_clk(hw);
  110. int ret = __scpi_find_dvfs_index(clk, rate);
  111. if (ret < 0)
  112. return ret;
  113. return clk->scpi_ops->dvfs_set_idx(clk->id, (u8)ret);
  114. }
  115. static const struct clk_ops scpi_dvfs_ops = {
  116. .recalc_rate = scpi_dvfs_recalc_rate,
  117. .round_rate = scpi_dvfs_round_rate,
  118. .set_rate = scpi_dvfs_set_rate,
  119. };
  120. static const struct of_device_id scpi_clk_match[] = {
  121. { .compatible = "arm,scpi-dvfs-clocks", .data = &scpi_dvfs_ops, },
  122. { .compatible = "arm,scpi-variable-clocks", .data = &scpi_clk_ops, },
  123. {}
  124. };
  125. static struct clk *
  126. scpi_clk_ops_init(struct device *dev, const struct of_device_id *match,
  127. struct scpi_clk *sclk, const char *name)
  128. {
  129. struct clk_init_data init;
  130. struct clk *clk;
  131. unsigned long min = 0, max = 0;
  132. init.name = name;
  133. init.flags = CLK_IS_ROOT;
  134. init.num_parents = 0;
  135. init.ops = match->data;
  136. sclk->hw.init = &init;
  137. sclk->scpi_ops = get_scpi_ops();
  138. if (init.ops == &scpi_dvfs_ops) {
  139. sclk->info = sclk->scpi_ops->dvfs_get_info(sclk->id);
  140. if (IS_ERR(sclk->info))
  141. return NULL;
  142. } else if (init.ops == &scpi_clk_ops) {
  143. if (sclk->scpi_ops->clk_get_range(sclk->id, &min, &max) || !max)
  144. return NULL;
  145. } else {
  146. return NULL;
  147. }
  148. clk = devm_clk_register(dev, &sclk->hw);
  149. if (!IS_ERR(clk) && max)
  150. clk_hw_set_rate_range(&sclk->hw, min, max);
  151. return clk;
  152. }
  153. struct scpi_clk_data {
  154. struct scpi_clk **clk;
  155. unsigned int clk_num;
  156. };
  157. static struct clk *
  158. scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data)
  159. {
  160. struct scpi_clk *sclk;
  161. struct scpi_clk_data *clk_data = data;
  162. unsigned int idx = clkspec->args[0], count;
  163. for (count = 0; count < clk_data->clk_num; count++) {
  164. sclk = clk_data->clk[count];
  165. if (idx == sclk->id)
  166. return sclk->hw.clk;
  167. }
  168. return ERR_PTR(-EINVAL);
  169. }
  170. static int scpi_clk_add(struct device *dev, struct device_node *np,
  171. const struct of_device_id *match)
  172. {
  173. struct clk **clks;
  174. int idx, count;
  175. struct scpi_clk_data *clk_data;
  176. count = of_property_count_strings(np, "clock-output-names");
  177. if (count < 0) {
  178. dev_err(dev, "%s: invalid clock output count\n", np->name);
  179. return -EINVAL;
  180. }
  181. clk_data = devm_kmalloc(dev, sizeof(*clk_data), GFP_KERNEL);
  182. if (!clk_data)
  183. return -ENOMEM;
  184. clk_data->clk_num = count;
  185. clk_data->clk = devm_kcalloc(dev, count, sizeof(*clk_data->clk),
  186. GFP_KERNEL);
  187. if (!clk_data->clk)
  188. return -ENOMEM;
  189. clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL);
  190. if (!clks)
  191. return -ENOMEM;
  192. for (idx = 0; idx < count; idx++) {
  193. struct scpi_clk *sclk;
  194. const char *name;
  195. u32 val;
  196. sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
  197. if (!sclk)
  198. return -ENOMEM;
  199. if (of_property_read_string_index(np, "clock-output-names",
  200. idx, &name)) {
  201. dev_err(dev, "invalid clock name @ %s\n", np->name);
  202. return -EINVAL;
  203. }
  204. if (of_property_read_u32_index(np, "clock-indices",
  205. idx, &val)) {
  206. dev_err(dev, "invalid clock index @ %s\n", np->name);
  207. return -EINVAL;
  208. }
  209. sclk->id = val;
  210. clks[idx] = scpi_clk_ops_init(dev, match, sclk, name);
  211. if (IS_ERR_OR_NULL(clks[idx]))
  212. dev_err(dev, "failed to register clock '%s'\n", name);
  213. else
  214. dev_dbg(dev, "Registered clock '%s'\n", name);
  215. clk_data->clk[idx] = sclk;
  216. }
  217. return of_clk_add_provider(np, scpi_of_clk_src_get, clk_data);
  218. }
  219. static int scpi_clocks_remove(struct platform_device *pdev)
  220. {
  221. struct device *dev = &pdev->dev;
  222. struct device_node *child, *np = dev->of_node;
  223. if (cpufreq_dev) {
  224. platform_device_unregister(cpufreq_dev);
  225. cpufreq_dev = NULL;
  226. }
  227. for_each_available_child_of_node(np, child)
  228. of_clk_del_provider(np);
  229. return 0;
  230. }
  231. static int scpi_clocks_probe(struct platform_device *pdev)
  232. {
  233. int ret;
  234. struct device *dev = &pdev->dev;
  235. struct device_node *child, *np = dev->of_node;
  236. const struct of_device_id *match;
  237. if (!get_scpi_ops())
  238. return -ENXIO;
  239. for_each_available_child_of_node(np, child) {
  240. match = of_match_node(scpi_clk_match, child);
  241. if (!match)
  242. continue;
  243. ret = scpi_clk_add(dev, child, match);
  244. if (ret) {
  245. scpi_clocks_remove(pdev);
  246. of_node_put(child);
  247. return ret;
  248. }
  249. }
  250. /* Add the virtual cpufreq device */
  251. cpufreq_dev = platform_device_register_simple("scpi-cpufreq",
  252. -1, NULL, 0);
  253. if (!cpufreq_dev)
  254. pr_warn("unable to register cpufreq device");
  255. return 0;
  256. }
  257. static const struct of_device_id scpi_clocks_ids[] = {
  258. { .compatible = "arm,scpi-clocks", },
  259. {}
  260. };
  261. MODULE_DEVICE_TABLE(of, scpi_clocks_ids);
  262. static struct platform_driver scpi_clocks_driver = {
  263. .driver = {
  264. .name = "scpi_clocks",
  265. .of_match_table = scpi_clocks_ids,
  266. },
  267. .probe = scpi_clocks_probe,
  268. .remove = scpi_clocks_remove,
  269. };
  270. module_platform_driver(scpi_clocks_driver);
  271. MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
  272. MODULE_DESCRIPTION("ARM SCPI clock driver");
  273. MODULE_LICENSE("GPL v2");