161-clk-sunxi-add-pll2-for-sun457i.patch 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. From ea6871c5b3a934d0bfe08082e95c3b952f93ef39 Mon Sep 17 00:00:00 2001
  2. From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
  3. Date: Fri, 18 Jul 2014 15:48:35 -0300
  4. Subject: [PATCH] clk: sunxi: PLL2 support for sun4i, sun5i and sun7i
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. This patch adds support for PLL2 and derivates on A10 revision B and
  9. higher, as well as on sun5i and sun7i SoCs. As this PLL is only used for
  10. audio and requires good accuracy, we only support two known good rates.
  11. Signed-off-by: Emilio López <emilio@elopez.com.ar>
  12. Signed-off-by: Hans de Goede <hdegoede@redhat.com>
  13. ---
  14. drivers/clk/sunxi/Makefile | 1 +
  15. drivers/clk/sunxi/clk-a10-pll2.c | 249 +++++++++++++++++++++++++++++++++++++++
  16. 2 files changed, 250 insertions(+)
  17. create mode 100644 drivers/clk/sunxi/clk-a10-pll2.c
  18. --- a/drivers/clk/sunxi/Makefile
  19. +++ b/drivers/clk/sunxi/Makefile
  20. @@ -4,6 +4,7 @@
  21. obj-y += clk-sunxi.o clk-factors.o
  22. obj-y += clk-a10-hosc.o
  23. +obj-y += clk-a10-pll2.o
  24. obj-y += clk-a20-gmac.o
  25. obj-y += clk-mod0.o
  26. obj-y += clk-sun8i-mbus.o
  27. --- /dev/null
  28. +++ b/drivers/clk/sunxi/clk-a10-pll2.c
  29. @@ -0,0 +1,249 @@
  30. +/*
  31. + * Copyright 2013 Emilio López
  32. + *
  33. + * Emilio López <emilio@elopez.com.ar>
  34. + *
  35. + * This program is free software; you can redistribute it and/or modify
  36. + * it under the terms of the GNU General Public License as published by
  37. + * the Free Software Foundation; either version 2 of the License, or
  38. + * (at your option) any later version.
  39. + *
  40. + * This program is distributed in the hope that it will be useful,
  41. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  42. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  43. + * GNU General Public License for more details.
  44. + */
  45. +
  46. +#include <linux/clk-provider.h>
  47. +#include <linux/of.h>
  48. +#include <linux/of_address.h>
  49. +#include <linux/slab.h>
  50. +
  51. +#define SUN4I_PLL2_ENABLE 31
  52. +#define SUN4I_PLL2_POST_DIV 26
  53. +#define SUN4I_PLL2_POST_DIV_MASK 0xF
  54. +#define SUN4I_PLL2_N 8
  55. +#define SUN4I_PLL2_N_MASK 0x7F
  56. +#define SUN4I_PLL2_PRE_DIV 0
  57. +#define SUN4I_PLL2_PRE_DIV_MASK 0x1F
  58. +
  59. +#define SUN4I_PLL2_OUTPUTS 4
  60. +
  61. +struct sun4i_pll2_clk {
  62. + struct clk_hw hw;
  63. + void __iomem *reg;
  64. +};
  65. +
  66. +static inline struct sun4i_pll2_clk *to_sun4i_pll2_clk(struct clk_hw *hw)
  67. +{
  68. + return container_of(hw, struct sun4i_pll2_clk, hw);
  69. +}
  70. +
  71. +static unsigned long sun4i_pll2_1x_recalc_rate(struct clk_hw *hw,
  72. + unsigned long parent_rate)
  73. +{
  74. + struct sun4i_pll2_clk *clk = to_sun4i_pll2_clk(hw);
  75. + int n, prediv, postdiv;
  76. +
  77. + u32 val = readl(clk->reg);
  78. + n = (val >> SUN4I_PLL2_N) & SUN4I_PLL2_N_MASK;
  79. + prediv = (val >> SUN4I_PLL2_PRE_DIV) & SUN4I_PLL2_PRE_DIV_MASK;
  80. + postdiv = (val >> SUN4I_PLL2_POST_DIV) & SUN4I_PLL2_POST_DIV_MASK;
  81. +
  82. + /* 0 is a special case and means 1 */
  83. + if (n == 0)
  84. + n = 1;
  85. + if (prediv == 0)
  86. + prediv = 1;
  87. + if (postdiv == 0)
  88. + postdiv = 1;
  89. +
  90. + return ((parent_rate * n) / prediv) / postdiv;
  91. +}
  92. +
  93. +static unsigned long sun4i_pll2_8x_recalc_rate(struct clk_hw *hw,
  94. + unsigned long parent_rate)
  95. +{
  96. + struct sun4i_pll2_clk *clk = to_sun4i_pll2_clk(hw);
  97. + int n, prediv;
  98. +
  99. + u32 val = readl(clk->reg);
  100. + n = (val >> SUN4I_PLL2_N) & SUN4I_PLL2_N_MASK;
  101. + prediv = (val >> SUN4I_PLL2_PRE_DIV) & SUN4I_PLL2_PRE_DIV_MASK;
  102. +
  103. + /* 0 is a special case and means 1 */
  104. + if (n == 0)
  105. + n = 1;
  106. + if (prediv == 0)
  107. + prediv = 1;
  108. +
  109. + return ((parent_rate * 2 * n) / prediv);
  110. +}
  111. +
  112. +static unsigned long sun4i_pll2_4x_recalc_rate(struct clk_hw *hw,
  113. + unsigned long parent_rate)
  114. +{
  115. + return sun4i_pll2_8x_recalc_rate(hw, parent_rate / 2);
  116. +}
  117. +
  118. +static unsigned long sun4i_pll2_2x_recalc_rate(struct clk_hw *hw,
  119. + unsigned long parent_rate)
  120. +{
  121. + return sun4i_pll2_8x_recalc_rate(hw, parent_rate / 4);
  122. +}
  123. +
  124. +static long sun4i_pll2_1x_round_rate(struct clk_hw *hw, unsigned long rate,
  125. + unsigned long *parent_rate)
  126. +{
  127. + /*
  128. + * There is only two interesting rates for the audio PLL, the
  129. + * rest isn't really usable due to accuracy concerns. Therefore,
  130. + * we specifically round to those rates here
  131. + */
  132. + if (rate < 22579200)
  133. + return -EINVAL;
  134. +
  135. + if (rate >= 22579200 && rate < 24576000)
  136. + return 22579200;
  137. +
  138. + return 24576000;
  139. +}
  140. +
  141. +static long sun4i_pll2_8x_round_rate(struct clk_hw *hw, unsigned long rate,
  142. + unsigned long *parent_rate)
  143. +{
  144. + /*
  145. + * We should account for the postdiv that we're undoing on PLL2x8,
  146. + * which is always 4 in the usable configurations. The division
  147. + * by two is done because PLL2x8 also doubles the rate
  148. + */
  149. + *parent_rate = (rate * 4) / 2;
  150. +
  151. + return rate;
  152. +}
  153. +
  154. +static long sun4i_pll2_4x_round_rate(struct clk_hw *hw, unsigned long rate,
  155. + unsigned long *parent_rate)
  156. +{
  157. + /* PLL2x4 * 2 = PLL2x8 */
  158. + return sun4i_pll2_8x_round_rate(hw, rate * 2, parent_rate);
  159. +}
  160. +
  161. +static long sun4i_pll2_2x_round_rate(struct clk_hw *hw, unsigned long rate,
  162. + unsigned long *parent_rate)
  163. +{
  164. + /* PLL2x2 * 4 = PLL2x8 */
  165. + return sun4i_pll2_8x_round_rate(hw, rate * 4, parent_rate);
  166. +}
  167. +
  168. +static int sun4i_pll2_set_rate(struct clk_hw *hw, unsigned long rate,
  169. + unsigned long parent_rate)
  170. +{
  171. + struct sun4i_pll2_clk *clk = to_sun4i_pll2_clk(hw);
  172. + u32 val = readl(clk->reg);
  173. +
  174. + val &= ~(SUN4I_PLL2_N_MASK << SUN4I_PLL2_N);
  175. + val &= ~(SUN4I_PLL2_PRE_DIV_MASK << SUN4I_PLL2_PRE_DIV);
  176. + val &= ~(SUN4I_PLL2_POST_DIV_MASK << SUN4I_PLL2_POST_DIV);
  177. +
  178. + val |= (21 << SUN4I_PLL2_PRE_DIV) | (4 << SUN4I_PLL2_POST_DIV);
  179. +
  180. + if (rate == 22579200)
  181. + val |= (79 << SUN4I_PLL2_N);
  182. + else if (rate == 24576000)
  183. + val |= (86 << SUN4I_PLL2_N);
  184. + else
  185. + return -EINVAL;
  186. +
  187. + writel(val, clk->reg);
  188. +
  189. + return 0;
  190. +}
  191. +
  192. +static struct clk_ops sun4i_pll2_ops_1x = {
  193. + .recalc_rate = sun4i_pll2_1x_recalc_rate,
  194. + .round_rate = sun4i_pll2_1x_round_rate,
  195. + .set_rate = sun4i_pll2_set_rate,
  196. +};
  197. +
  198. +static struct clk_ops sun4i_pll2_ops_2x = {
  199. + .recalc_rate = sun4i_pll2_2x_recalc_rate,
  200. + .round_rate = sun4i_pll2_2x_round_rate,
  201. +};
  202. +
  203. +static struct clk_ops sun4i_pll2_ops_4x = {
  204. + .recalc_rate = sun4i_pll2_4x_recalc_rate,
  205. + .round_rate = sun4i_pll2_4x_round_rate,
  206. +};
  207. +
  208. +static struct clk_ops sun4i_pll2_ops_8x = {
  209. + .recalc_rate = sun4i_pll2_8x_recalc_rate,
  210. + .round_rate = sun4i_pll2_8x_round_rate,
  211. +};
  212. +
  213. +static void __init sun4i_pll2_setup(struct device_node *np)
  214. +{
  215. + const char *clk_name = np->name, *parent;
  216. + struct clk_onecell_data *clk_data;
  217. + struct sun4i_pll2_clk *pll2;
  218. + struct clk_gate *gate;
  219. + struct clk **clks;
  220. + void __iomem *reg;
  221. +
  222. + pll2 = kzalloc(sizeof(*pll2), GFP_KERNEL);
  223. + gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  224. + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
  225. + clks = kcalloc(SUN4I_PLL2_OUTPUTS, sizeof(struct clk *), GFP_KERNEL);
  226. + if (!pll2 || !gate || !clk_data || !clks)
  227. + goto free_mem;
  228. +
  229. + reg = of_iomap(np, 0);
  230. + parent = of_clk_get_parent_name(np, 0);
  231. + of_property_read_string_index(np, "clock-output-names", 0, &clk_name);
  232. +
  233. + pll2->reg = reg;
  234. + gate->reg = reg;
  235. + gate->bit_idx = SUN4I_PLL2_ENABLE;
  236. +
  237. + /* PLL2, also known as PLL2x1 */
  238. + of_property_read_string_index(np, "clock-output-names", 0, &clk_name);
  239. + clks[0] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
  240. + &pll2->hw, &sun4i_pll2_ops_1x,
  241. + &gate->hw, &clk_gate_ops, 0);
  242. + WARN_ON(IS_ERR(clks[0]));
  243. + parent = clk_name;
  244. +
  245. + /* PLL2x2, 1/4 the rate of PLL2x8 */
  246. + of_property_read_string_index(np, "clock-output-names", 1, &clk_name);
  247. + clks[1] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
  248. + &pll2->hw, &sun4i_pll2_ops_2x,
  249. + NULL, NULL, CLK_SET_RATE_PARENT);
  250. + WARN_ON(IS_ERR(clks[1]));
  251. +
  252. + /* PLL2x4, 1/2 the rate of PLL2x8 */
  253. + of_property_read_string_index(np, "clock-output-names", 2, &clk_name);
  254. + clks[2] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
  255. + &pll2->hw, &sun4i_pll2_ops_4x,
  256. + NULL, NULL, CLK_SET_RATE_PARENT);
  257. + WARN_ON(IS_ERR(clks[2]));
  258. +
  259. + /* PLL2x8, double of PLL2 without the post divisor */
  260. + of_property_read_string_index(np, "clock-output-names", 3, &clk_name);
  261. + clks[3] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
  262. + &pll2->hw, &sun4i_pll2_ops_8x,
  263. + NULL, NULL, CLK_SET_RATE_PARENT);
  264. + WARN_ON(IS_ERR(clks[3]));
  265. +
  266. + clk_data->clks = clks;
  267. + clk_data->clk_num = SUN4I_PLL2_OUTPUTS;
  268. + of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
  269. +
  270. + return;
  271. +
  272. +free_mem:
  273. + kfree(pll2);
  274. + kfree(gate);
  275. + kfree(clk_data);
  276. + kfree(clks);
  277. +}
  278. +CLK_OF_DECLARE(sun4i_pll2, "allwinner,sun4i-a10-b-pll2-clk", sun4i_pll2_setup);