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