clk.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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)
  48. {
  49. reg_base = base;
  50. if (!np)
  51. return;
  52. #ifdef CONFIG_OF
  53. clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
  54. if (!clk_table)
  55. panic("could not allocate clock lookup table\n");
  56. clk_data.clks = clk_table;
  57. clk_data.clk_num = nr_clks;
  58. of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
  59. #endif
  60. #ifdef CONFIG_PM_SLEEP
  61. if (rdump && nr_rdump) {
  62. unsigned int idx;
  63. reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
  64. * nr_rdump, GFP_KERNEL);
  65. if (!reg_dump) {
  66. pr_err("%s: memory alloc for register dump failed\n",
  67. __func__);
  68. return;
  69. }
  70. for (idx = 0; idx < nr_rdump; idx++)
  71. reg_dump[idx].offset = rdump[idx];
  72. nr_reg_dump = nr_rdump;
  73. register_syscore_ops(&samsung_clk_syscore_ops);
  74. }
  75. #endif
  76. }
  77. /* add a clock instance to the clock lookup table used for dt based lookup */
  78. void samsung_clk_add_lookup(struct clk *clk, unsigned int id)
  79. {
  80. if (clk_table && id)
  81. clk_table[id] = clk;
  82. }
  83. /* register a list of fixed clocks */
  84. void __init samsung_clk_register_fixed_rate(
  85. struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
  86. {
  87. struct clk *clk;
  88. unsigned int idx, ret;
  89. for (idx = 0; idx < nr_clk; idx++, list++) {
  90. clk = clk_register_fixed_rate(NULL, list->name,
  91. list->parent_name, list->flags, list->fixed_rate);
  92. if (IS_ERR(clk)) {
  93. pr_err("%s: failed to register clock %s\n", __func__,
  94. list->name);
  95. continue;
  96. }
  97. samsung_clk_add_lookup(clk, list->id);
  98. /*
  99. * Unconditionally add a clock lookup for the fixed rate clocks.
  100. * There are not many of these on any of Samsung platforms.
  101. */
  102. ret = clk_register_clkdev(clk, list->name, NULL);
  103. if (ret)
  104. pr_err("%s: failed to register clock lookup for %s",
  105. __func__, list->name);
  106. }
  107. }
  108. /* register a list of fixed factor clocks */
  109. void __init samsung_clk_register_fixed_factor(
  110. struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
  111. {
  112. struct clk *clk;
  113. unsigned int idx;
  114. for (idx = 0; idx < nr_clk; idx++, list++) {
  115. clk = clk_register_fixed_factor(NULL, list->name,
  116. list->parent_name, list->flags, list->mult, list->div);
  117. if (IS_ERR(clk)) {
  118. pr_err("%s: failed to register clock %s\n", __func__,
  119. list->name);
  120. continue;
  121. }
  122. samsung_clk_add_lookup(clk, list->id);
  123. }
  124. }
  125. /* register a list of mux clocks */
  126. void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
  127. unsigned int nr_clk)
  128. {
  129. struct clk *clk;
  130. unsigned int idx, ret;
  131. for (idx = 0; idx < nr_clk; idx++, list++) {
  132. clk = clk_register_mux(NULL, list->name, list->parent_names,
  133. list->num_parents, list->flags, reg_base + list->offset,
  134. list->shift, list->width, list->mux_flags, &lock);
  135. if (IS_ERR(clk)) {
  136. pr_err("%s: failed to register clock %s\n", __func__,
  137. list->name);
  138. continue;
  139. }
  140. samsung_clk_add_lookup(clk, list->id);
  141. /* register a clock lookup only if a clock alias is specified */
  142. if (list->alias) {
  143. ret = clk_register_clkdev(clk, list->alias,
  144. list->dev_name);
  145. if (ret)
  146. pr_err("%s: failed to register lookup %s\n",
  147. __func__, list->alias);
  148. }
  149. }
  150. }
  151. /* register a list of div clocks */
  152. void __init samsung_clk_register_div(struct samsung_div_clock *list,
  153. unsigned int nr_clk)
  154. {
  155. struct clk *clk;
  156. unsigned int idx, ret;
  157. for (idx = 0; idx < nr_clk; idx++, list++) {
  158. if (list->table)
  159. clk = clk_register_divider_table(NULL, list->name,
  160. list->parent_name, list->flags,
  161. reg_base + list->offset, list->shift,
  162. list->width, list->div_flags,
  163. list->table, &lock);
  164. else
  165. clk = clk_register_divider(NULL, list->name,
  166. list->parent_name, list->flags,
  167. reg_base + list->offset, list->shift,
  168. list->width, list->div_flags, &lock);
  169. if (IS_ERR(clk)) {
  170. pr_err("%s: failed to register clock %s\n", __func__,
  171. list->name);
  172. continue;
  173. }
  174. samsung_clk_add_lookup(clk, list->id);
  175. /* register a clock lookup only if a clock alias is specified */
  176. if (list->alias) {
  177. ret = clk_register_clkdev(clk, list->alias,
  178. list->dev_name);
  179. if (ret)
  180. pr_err("%s: failed to register lookup %s\n",
  181. __func__, list->alias);
  182. }
  183. }
  184. }
  185. /* register a list of gate clocks */
  186. void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
  187. unsigned int nr_clk)
  188. {
  189. struct clk *clk;
  190. unsigned int idx, ret;
  191. for (idx = 0; idx < nr_clk; idx++, list++) {
  192. clk = clk_register_gate(NULL, list->name, list->parent_name,
  193. list->flags, reg_base + list->offset,
  194. list->bit_idx, list->gate_flags, &lock);
  195. if (IS_ERR(clk)) {
  196. pr_err("%s: failed to register clock %s\n", __func__,
  197. list->name);
  198. continue;
  199. }
  200. /* register a clock lookup only if a clock alias is specified */
  201. if (list->alias) {
  202. ret = clk_register_clkdev(clk, list->alias,
  203. list->dev_name);
  204. if (ret)
  205. pr_err("%s: failed to register lookup %s\n",
  206. __func__, list->alias);
  207. }
  208. samsung_clk_add_lookup(clk, list->id);
  209. }
  210. }
  211. /*
  212. * obtain the clock speed of all external fixed clock sources from device
  213. * tree and register it
  214. */
  215. void __init samsung_clk_of_register_fixed_ext(
  216. struct samsung_fixed_rate_clock *fixed_rate_clk,
  217. unsigned int nr_fixed_rate_clk,
  218. struct of_device_id *clk_matches)
  219. {
  220. const struct of_device_id *match;
  221. struct device_node *np;
  222. u32 freq;
  223. for_each_matching_node_and_match(np, clk_matches, &match) {
  224. if (of_property_read_u32(np, "clock-frequency", &freq))
  225. continue;
  226. fixed_rate_clk[(u32)match->data].fixed_rate = freq;
  227. }
  228. samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
  229. }
  230. /* utility function to get the rate of a specified clock */
  231. unsigned long _get_rate(const char *clk_name)
  232. {
  233. struct clk *clk;
  234. unsigned long rate;
  235. clk = clk_get(NULL, clk_name);
  236. if (IS_ERR(clk)) {
  237. pr_err("%s: could not find clock %s\n", __func__, clk_name);
  238. return 0;
  239. }
  240. rate = clk_get_rate(clk);
  241. clk_put(clk);
  242. return rate;
  243. }