clkc.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * Copyright (c) 2015 Endless Mobile, Inc.
  3. * Author: Carlo Caione <carlo@endlessm.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms and conditions of the GNU General Public License,
  7. * version 2, as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <linux/clk-provider.h>
  18. #include <linux/mfd/syscon.h>
  19. #include <linux/slab.h>
  20. #include "clkc.h"
  21. static DEFINE_SPINLOCK(clk_lock);
  22. static struct clk **clks;
  23. static struct clk_onecell_data clk_data;
  24. struct clk ** __init meson_clk_init(struct device_node *np,
  25. unsigned long nr_clks)
  26. {
  27. clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL);
  28. if (!clks)
  29. return ERR_PTR(-ENOMEM);
  30. clk_data.clks = clks;
  31. clk_data.clk_num = nr_clks;
  32. of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
  33. return clks;
  34. }
  35. static void meson_clk_add_lookup(struct clk *clk, unsigned int id)
  36. {
  37. if (clks && id)
  38. clks[id] = clk;
  39. }
  40. static struct clk * __init
  41. meson_clk_register_composite(const struct clk_conf *clk_conf,
  42. void __iomem *clk_base)
  43. {
  44. struct clk *clk;
  45. struct clk_mux *mux = NULL;
  46. struct clk_divider *div = NULL;
  47. struct clk_gate *gate = NULL;
  48. const struct clk_ops *mux_ops = NULL;
  49. const struct composite_conf *composite_conf;
  50. composite_conf = clk_conf->conf.composite;
  51. if (clk_conf->num_parents > 1) {
  52. mux = kzalloc(sizeof(*mux), GFP_KERNEL);
  53. if (!mux)
  54. return ERR_PTR(-ENOMEM);
  55. mux->reg = clk_base + clk_conf->reg_off
  56. + composite_conf->mux_parm.reg_off;
  57. mux->shift = composite_conf->mux_parm.shift;
  58. mux->mask = BIT(composite_conf->mux_parm.width) - 1;
  59. mux->flags = composite_conf->mux_flags;
  60. mux->lock = &clk_lock;
  61. mux->table = composite_conf->mux_table;
  62. mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ?
  63. &clk_mux_ro_ops : &clk_mux_ops;
  64. }
  65. if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) {
  66. div = kzalloc(sizeof(*div), GFP_KERNEL);
  67. if (!div) {
  68. clk = ERR_PTR(-ENOMEM);
  69. goto error;
  70. }
  71. div->reg = clk_base + clk_conf->reg_off
  72. + composite_conf->div_parm.reg_off;
  73. div->shift = composite_conf->div_parm.shift;
  74. div->width = composite_conf->div_parm.width;
  75. div->lock = &clk_lock;
  76. div->flags = composite_conf->div_flags;
  77. div->table = composite_conf->div_table;
  78. }
  79. if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) {
  80. gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  81. if (!gate) {
  82. clk = ERR_PTR(-ENOMEM);
  83. goto error;
  84. }
  85. gate->reg = clk_base + clk_conf->reg_off
  86. + composite_conf->div_parm.reg_off;
  87. gate->bit_idx = composite_conf->gate_parm.shift;
  88. gate->flags = composite_conf->gate_flags;
  89. gate->lock = &clk_lock;
  90. }
  91. clk = clk_register_composite(NULL, clk_conf->clk_name,
  92. clk_conf->clks_parent,
  93. clk_conf->num_parents,
  94. mux ? &mux->hw : NULL, mux_ops,
  95. div ? &div->hw : NULL, &clk_divider_ops,
  96. gate ? &gate->hw : NULL, &clk_gate_ops,
  97. clk_conf->flags);
  98. if (IS_ERR(clk))
  99. goto error;
  100. return clk;
  101. error:
  102. kfree(gate);
  103. kfree(div);
  104. kfree(mux);
  105. return clk;
  106. }
  107. static struct clk * __init
  108. meson_clk_register_fixed_factor(const struct clk_conf *clk_conf,
  109. void __iomem *clk_base)
  110. {
  111. struct clk *clk;
  112. const struct fixed_fact_conf *fixed_fact_conf;
  113. const struct parm *p;
  114. unsigned int mult, div;
  115. u32 reg;
  116. fixed_fact_conf = &clk_conf->conf.fixed_fact;
  117. mult = clk_conf->conf.fixed_fact.mult;
  118. div = clk_conf->conf.fixed_fact.div;
  119. if (!mult) {
  120. mult = 1;
  121. p = &fixed_fact_conf->mult_parm;
  122. if (MESON_PARM_APPLICABLE(p)) {
  123. reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
  124. mult = PARM_GET(p->width, p->shift, reg);
  125. }
  126. }
  127. if (!div) {
  128. div = 1;
  129. p = &fixed_fact_conf->div_parm;
  130. if (MESON_PARM_APPLICABLE(p)) {
  131. reg = readl(clk_base + clk_conf->reg_off + p->reg_off);
  132. mult = PARM_GET(p->width, p->shift, reg);
  133. }
  134. }
  135. clk = clk_register_fixed_factor(NULL,
  136. clk_conf->clk_name,
  137. clk_conf->clks_parent[0],
  138. clk_conf->flags,
  139. mult, div);
  140. return clk;
  141. }
  142. static struct clk * __init
  143. meson_clk_register_fixed_rate(const struct clk_conf *clk_conf,
  144. void __iomem *clk_base)
  145. {
  146. struct clk *clk;
  147. const struct fixed_rate_conf *fixed_rate_conf;
  148. const struct parm *r;
  149. unsigned long rate;
  150. u32 reg;
  151. fixed_rate_conf = &clk_conf->conf.fixed_rate;
  152. rate = fixed_rate_conf->rate;
  153. if (!rate) {
  154. r = &fixed_rate_conf->rate_parm;
  155. reg = readl(clk_base + clk_conf->reg_off + r->reg_off);
  156. rate = PARM_GET(r->width, r->shift, reg);
  157. }
  158. rate *= 1000000;
  159. clk = clk_register_fixed_rate(NULL,
  160. clk_conf->clk_name,
  161. clk_conf->num_parents
  162. ? clk_conf->clks_parent[0] : NULL,
  163. clk_conf->flags, rate);
  164. return clk;
  165. }
  166. void __init meson_clk_register_clks(const struct clk_conf *clk_confs,
  167. unsigned int nr_confs,
  168. void __iomem *clk_base)
  169. {
  170. unsigned int i;
  171. struct clk *clk = NULL;
  172. for (i = 0; i < nr_confs; i++) {
  173. const struct clk_conf *clk_conf = &clk_confs[i];
  174. switch (clk_conf->clk_type) {
  175. case CLK_FIXED_RATE:
  176. clk = meson_clk_register_fixed_rate(clk_conf,
  177. clk_base);
  178. break;
  179. case CLK_FIXED_FACTOR:
  180. clk = meson_clk_register_fixed_factor(clk_conf,
  181. clk_base);
  182. break;
  183. case CLK_COMPOSITE:
  184. clk = meson_clk_register_composite(clk_conf,
  185. clk_base);
  186. break;
  187. case CLK_CPU:
  188. clk = meson_clk_register_cpu(clk_conf, clk_base,
  189. &clk_lock);
  190. break;
  191. case CLK_PLL:
  192. clk = meson_clk_register_pll(clk_conf, clk_base,
  193. &clk_lock);
  194. break;
  195. default:
  196. clk = NULL;
  197. }
  198. if (!clk) {
  199. pr_err("%s: unknown clock type %d\n", __func__,
  200. clk_conf->clk_type);
  201. continue;
  202. }
  203. if (IS_ERR(clk)) {
  204. pr_warn("%s: Unable to create %s clock\n", __func__,
  205. clk_conf->clk_name);
  206. continue;
  207. }
  208. meson_clk_add_lookup(clk, clk_conf->clk_id);
  209. }
  210. }