clk.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * Copyright (c) 2013 Samsung Electronics Co., Ltd.
  3. * Copyright (c) 2013 Linaro Ltd.
  4. * Author: Thomas Abraham <thomas.ab@samsung.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This file includes utility functions to register clocks to common
  11. * clock framework for Samsung platforms.
  12. */
  13. #include <linux/syscore_ops.h>
  14. #include "clk.h"
  15. static DEFINE_SPINLOCK(lock);
  16. static struct clk **clk_table;
  17. static void __iomem *reg_base;
  18. #ifdef CONFIG_OF
  19. static struct clk_onecell_data clk_data;
  20. #endif
  21. #ifdef CONFIG_PM_SLEEP
  22. static struct samsung_clk_reg_dump *reg_dump;
  23. static unsigned long nr_reg_dump;
  24. static int samsung_clk_suspend(void)
  25. {
  26. struct samsung_clk_reg_dump *rd = reg_dump;
  27. unsigned long i;
  28. for (i = 0; i < nr_reg_dump; i++, rd++)
  29. rd->value = __raw_readl(reg_base + rd->offset);
  30. return 0;
  31. }
  32. static void samsung_clk_resume(void)
  33. {
  34. struct samsung_clk_reg_dump *rd = reg_dump;
  35. unsigned long i;
  36. for (i = 0; i < nr_reg_dump; i++, rd++)
  37. __raw_writel(rd->value, reg_base + rd->offset);
  38. }
  39. static struct syscore_ops samsung_clk_syscore_ops = {
  40. .suspend = samsung_clk_suspend,
  41. .resume = samsung_clk_resume,
  42. };
  43. #endif /* CONFIG_PM_SLEEP */
  44. /* setup the essentials required to support clock lookup using ccf */
  45. void __init samsung_clk_init(struct device_node *np, void __iomem *base,
  46. unsigned long nr_clks, unsigned long *rdump,
  47. unsigned long nr_rdump, unsigned long *soc_rdump,
  48. unsigned long nr_soc_rdump)
  49. {
  50. reg_base = base;
  51. #ifdef CONFIG_PM_SLEEP
  52. if (rdump && nr_rdump) {
  53. unsigned int idx;
  54. reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
  55. * (nr_rdump + nr_soc_rdump), GFP_KERNEL);
  56. if (!reg_dump) {
  57. pr_err("%s: memory alloc for register dump failed\n",
  58. __func__);
  59. return;
  60. }
  61. for (idx = 0; idx < nr_rdump; idx++)
  62. reg_dump[idx].offset = rdump[idx];
  63. for (idx = 0; idx < nr_soc_rdump; idx++)
  64. reg_dump[nr_rdump + idx].offset = soc_rdump[idx];
  65. nr_reg_dump = nr_rdump + nr_soc_rdump;
  66. register_syscore_ops(&samsung_clk_syscore_ops);
  67. }
  68. #endif
  69. clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
  70. if (!clk_table)
  71. panic("could not allocate clock lookup table\n");
  72. if (!np)
  73. return;
  74. #ifdef CONFIG_OF
  75. clk_data.clks = clk_table;
  76. clk_data.clk_num = nr_clks;
  77. of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
  78. #endif
  79. }
  80. /* add a clock instance to the clock lookup table used for dt based lookup */
  81. void samsung_clk_add_lookup(struct clk *clk, unsigned int id)
  82. {
  83. if (clk_table && id)
  84. clk_table[id] = clk;
  85. }
  86. /* register a list of aliases */
  87. void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
  88. unsigned int nr_clk)
  89. {
  90. struct clk *clk;
  91. unsigned int idx, ret;
  92. if (!clk_table) {
  93. pr_err("%s: clock table missing\n", __func__);
  94. return;
  95. }
  96. for (idx = 0; idx < nr_clk; idx++, list++) {
  97. if (!list->id) {
  98. pr_err("%s: clock id missing for index %d\n", __func__,
  99. idx);
  100. continue;
  101. }
  102. clk = clk_table[list->id];
  103. if (!clk) {
  104. pr_err("%s: failed to find clock %d\n", __func__,
  105. list->id);
  106. continue;
  107. }
  108. ret = clk_register_clkdev(clk, list->alias, list->dev_name);
  109. if (ret)
  110. pr_err("%s: failed to register lookup %s\n",
  111. __func__, list->alias);
  112. }
  113. }
  114. /* register a list of fixed clocks */
  115. void __init samsung_clk_register_fixed_rate(
  116. struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
  117. {
  118. struct clk *clk;
  119. unsigned int idx, ret;
  120. for (idx = 0; idx < nr_clk; idx++, list++) {
  121. clk = clk_register_fixed_rate(NULL, list->name,
  122. list->parent_name, list->flags, list->fixed_rate);
  123. if (IS_ERR(clk)) {
  124. pr_err("%s: failed to register clock %s\n", __func__,
  125. list->name);
  126. continue;
  127. }
  128. samsung_clk_add_lookup(clk, list->id);
  129. /*
  130. * Unconditionally add a clock lookup for the fixed rate clocks.
  131. * There are not many of these on any of Samsung platforms.
  132. */
  133. ret = clk_register_clkdev(clk, list->name, NULL);
  134. if (ret)
  135. pr_err("%s: failed to register clock lookup for %s",
  136. __func__, list->name);
  137. }
  138. }
  139. /* register a list of fixed factor clocks */
  140. void __init samsung_clk_register_fixed_factor(
  141. struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
  142. {
  143. struct clk *clk;
  144. unsigned int idx;
  145. for (idx = 0; idx < nr_clk; idx++, list++) {
  146. clk = clk_register_fixed_factor(NULL, list->name,
  147. list->parent_name, list->flags, list->mult, list->div);
  148. if (IS_ERR(clk)) {
  149. pr_err("%s: failed to register clock %s\n", __func__,
  150. list->name);
  151. continue;
  152. }
  153. samsung_clk_add_lookup(clk, list->id);
  154. }
  155. }
  156. /* register a list of mux clocks */
  157. void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
  158. unsigned int nr_clk)
  159. {
  160. struct clk *clk;
  161. unsigned int idx, ret;
  162. for (idx = 0; idx < nr_clk; idx++, list++) {
  163. clk = clk_register_mux(NULL, list->name, list->parent_names,
  164. list->num_parents, list->flags, reg_base + list->offset,
  165. list->shift, list->width, list->mux_flags, &lock);
  166. if (IS_ERR(clk)) {
  167. pr_err("%s: failed to register clock %s\n", __func__,
  168. list->name);
  169. continue;
  170. }
  171. samsung_clk_add_lookup(clk, list->id);
  172. /* register a clock lookup only if a clock alias is specified */
  173. if (list->alias) {
  174. ret = clk_register_clkdev(clk, list->alias,
  175. list->dev_name);
  176. if (ret)
  177. pr_err("%s: failed to register lookup %s\n",
  178. __func__, list->alias);
  179. }
  180. }
  181. }
  182. /* register a list of div clocks */
  183. void __init samsung_clk_register_div(struct samsung_div_clock *list,
  184. unsigned int nr_clk)
  185. {
  186. struct clk *clk;
  187. unsigned int idx, ret;
  188. for (idx = 0; idx < nr_clk; idx++, list++) {
  189. if (list->table)
  190. clk = clk_register_divider_table(NULL, list->name,
  191. list->parent_name, list->flags,
  192. reg_base + list->offset, list->shift,
  193. list->width, list->div_flags,
  194. list->table, &lock);
  195. else
  196. clk = clk_register_divider(NULL, list->name,
  197. list->parent_name, list->flags,
  198. reg_base + list->offset, list->shift,
  199. list->width, list->div_flags, &lock);
  200. if (IS_ERR(clk)) {
  201. pr_err("%s: failed to register clock %s\n", __func__,
  202. list->name);
  203. continue;
  204. }
  205. samsung_clk_add_lookup(clk, list->id);
  206. /* register a clock lookup only if a clock alias is specified */
  207. if (list->alias) {
  208. ret = clk_register_clkdev(clk, list->alias,
  209. list->dev_name);
  210. if (ret)
  211. pr_err("%s: failed to register lookup %s\n",
  212. __func__, list->alias);
  213. }
  214. }
  215. }
  216. /* register a list of gate clocks */
  217. void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
  218. unsigned int nr_clk)
  219. {
  220. struct clk *clk;
  221. unsigned int idx, ret;
  222. for (idx = 0; idx < nr_clk; idx++, list++) {
  223. clk = clk_register_gate(NULL, list->name, list->parent_name,
  224. list->flags, reg_base + list->offset,
  225. list->bit_idx, list->gate_flags, &lock);
  226. if (IS_ERR(clk)) {
  227. pr_err("%s: failed to register clock %s\n", __func__,
  228. list->name);
  229. continue;
  230. }
  231. /* register a clock lookup only if a clock alias is specified */
  232. if (list->alias) {
  233. ret = clk_register_clkdev(clk, list->alias,
  234. list->dev_name);
  235. if (ret)
  236. pr_err("%s: failed to register lookup %s\n",
  237. __func__, list->alias);
  238. }
  239. samsung_clk_add_lookup(clk, list->id);
  240. }
  241. }
  242. /*
  243. * obtain the clock speed of all external fixed clock sources from device
  244. * tree and register it
  245. */
  246. #ifdef CONFIG_OF
  247. void __init samsung_clk_of_register_fixed_ext(
  248. struct samsung_fixed_rate_clock *fixed_rate_clk,
  249. unsigned int nr_fixed_rate_clk,
  250. struct of_device_id *clk_matches)
  251. {
  252. const struct of_device_id *match;
  253. struct device_node *np;
  254. u32 freq;
  255. for_each_matching_node_and_match(np, clk_matches, &match) {
  256. if (of_property_read_u32(np, "clock-frequency", &freq))
  257. continue;
  258. fixed_rate_clk[(u32)match->data].fixed_rate = freq;
  259. }
  260. samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
  261. }
  262. #endif
  263. /* utility function to get the rate of a specified clock */
  264. unsigned long _get_rate(const char *clk_name)
  265. {
  266. struct clk *clk;
  267. clk = __clk_lookup(clk_name);
  268. if (!clk) {
  269. pr_err("%s: could not find clock %s\n", __func__, clk_name);
  270. return 0;
  271. }
  272. return clk_get_rate(clk);
  273. }