1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e874a669SEmilio López /*
3e874a669SEmilio López * Copyright 2013 Emilio López
4e874a669SEmilio López *
5e874a669SEmilio López * Emilio López <emilio@elopez.com.ar>
6e874a669SEmilio López */
7e874a669SEmilio López
89dfefe8cSStephen Boyd #include <linux/clk.h>
9e874a669SEmilio López #include <linux/clk-provider.h>
10e874a669SEmilio López #include <linux/clkdev.h>
1162e59c4eSStephen Boyd #include <linux/io.h>
12e874a669SEmilio López #include <linux/of.h>
13e874a669SEmilio López #include <linux/of_address.h>
14cfb0086dSHans de Goede #include <linux/reset-controller.h>
159dfefe8cSStephen Boyd #include <linux/slab.h>
16601da9d0SMaxime Ripard #include <linux/spinlock.h>
177954dfaeSChen-Yu Tsai #include <linux/log2.h>
18e874a669SEmilio López
19e874a669SEmilio López #include "clk-factors.h"
20e874a669SEmilio López
21e874a669SEmilio López static DEFINE_SPINLOCK(clk_lock);
22e874a669SEmilio López
2340a5dcbaSEmilio López /* Maximum number of parents our clocks have */
2440a5dcbaSEmilio López #define SUNXI_MAX_PARENTS 5
2540a5dcbaSEmilio López
26*58fdf74dSLee Jones /*
2781ba6c5eSMaxime Ripard * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1
28e874a669SEmilio López * PLL1 rate is calculated as follows
29e874a669SEmilio López * rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
30e874a669SEmilio López * parent_rate is always 24Mhz
31e874a669SEmilio López */
32e874a669SEmilio López
sun4i_get_pll1_factors(struct factors_request * req)33cfa63688SChen-Yu Tsai static void sun4i_get_pll1_factors(struct factors_request *req)
34e874a669SEmilio López {
35e874a669SEmilio López u8 div;
36e874a669SEmilio López
37e874a669SEmilio López /* Normalize value to a 6M multiple */
38cfa63688SChen-Yu Tsai div = req->rate / 6000000;
39cfa63688SChen-Yu Tsai req->rate = 6000000 * div;
40e874a669SEmilio López
41e874a669SEmilio López /* m is always zero for pll1 */
42cfa63688SChen-Yu Tsai req->m = 0;
43e874a669SEmilio López
44e874a669SEmilio López /* k is 1 only on these cases */
45cfa63688SChen-Yu Tsai if (req->rate >= 768000000 || req->rate == 42000000 ||
46cfa63688SChen-Yu Tsai req->rate == 54000000)
47cfa63688SChen-Yu Tsai req->k = 1;
48e874a669SEmilio López else
49cfa63688SChen-Yu Tsai req->k = 0;
50e874a669SEmilio López
51e874a669SEmilio López /* p will be 3 for divs under 10 */
52e874a669SEmilio López if (div < 10)
53cfa63688SChen-Yu Tsai req->p = 3;
54e874a669SEmilio López
55e874a669SEmilio López /* p will be 2 for divs between 10 - 20 and odd divs under 32 */
56e874a669SEmilio López else if (div < 20 || (div < 32 && (div & 1)))
57cfa63688SChen-Yu Tsai req->p = 2;
58e874a669SEmilio López
59e874a669SEmilio López /* p will be 1 for even divs under 32, divs under 40 and odd pairs
60e874a669SEmilio López * of divs between 40-62 */
61e874a669SEmilio López else if (div < 40 || (div < 64 && (div & 2)))
62cfa63688SChen-Yu Tsai req->p = 1;
63e874a669SEmilio López
64e874a669SEmilio López /* any other entries have p = 0 */
65e874a669SEmilio López else
66cfa63688SChen-Yu Tsai req->p = 0;
67e874a669SEmilio López
68e874a669SEmilio López /* calculate a suitable n based on k and p */
69cfa63688SChen-Yu Tsai div <<= req->p;
70cfa63688SChen-Yu Tsai div /= (req->k + 1);
71cfa63688SChen-Yu Tsai req->n = div / 4;
72e874a669SEmilio López }
73e874a669SEmilio López
74*58fdf74dSLee Jones /*
756a721db1SMaxime Ripard * sun6i_a31_get_pll1_factors() - calculates n, k and m factors for PLL1
766a721db1SMaxime Ripard * PLL1 rate is calculated as follows
776a721db1SMaxime Ripard * rate = parent_rate * (n + 1) * (k + 1) / (m + 1);
786a721db1SMaxime Ripard * parent_rate should always be 24MHz
796a721db1SMaxime Ripard */
sun6i_a31_get_pll1_factors(struct factors_request * req)80cfa63688SChen-Yu Tsai static void sun6i_a31_get_pll1_factors(struct factors_request *req)
816a721db1SMaxime Ripard {
826a721db1SMaxime Ripard /*
836a721db1SMaxime Ripard * We can operate only on MHz, this will make our life easier
846a721db1SMaxime Ripard * later.
856a721db1SMaxime Ripard */
86cfa63688SChen-Yu Tsai u32 freq_mhz = req->rate / 1000000;
87cfa63688SChen-Yu Tsai u32 parent_freq_mhz = req->parent_rate / 1000000;
88e874a669SEmilio López
896a721db1SMaxime Ripard /*
906a721db1SMaxime Ripard * Round down the frequency to the closest multiple of either
916a721db1SMaxime Ripard * 6 or 16
926a721db1SMaxime Ripard */
93ee25d974SRikard Falkeborn u32 round_freq_6 = rounddown(freq_mhz, 6);
946a721db1SMaxime Ripard u32 round_freq_16 = round_down(freq_mhz, 16);
956a721db1SMaxime Ripard
966a721db1SMaxime Ripard if (round_freq_6 > round_freq_16)
976a721db1SMaxime Ripard freq_mhz = round_freq_6;
986a721db1SMaxime Ripard else
996a721db1SMaxime Ripard freq_mhz = round_freq_16;
1006a721db1SMaxime Ripard
101cfa63688SChen-Yu Tsai req->rate = freq_mhz * 1000000;
1026a721db1SMaxime Ripard
1036a721db1SMaxime Ripard /* If the frequency is a multiple of 32 MHz, k is always 3 */
1046a721db1SMaxime Ripard if (!(freq_mhz % 32))
105cfa63688SChen-Yu Tsai req->k = 3;
1066a721db1SMaxime Ripard /* If the frequency is a multiple of 9 MHz, k is always 2 */
1076a721db1SMaxime Ripard else if (!(freq_mhz % 9))
108cfa63688SChen-Yu Tsai req->k = 2;
1096a721db1SMaxime Ripard /* If the frequency is a multiple of 8 MHz, k is always 1 */
1106a721db1SMaxime Ripard else if (!(freq_mhz % 8))
111cfa63688SChen-Yu Tsai req->k = 1;
1126a721db1SMaxime Ripard /* Otherwise, we don't use the k factor */
1136a721db1SMaxime Ripard else
114cfa63688SChen-Yu Tsai req->k = 0;
1156a721db1SMaxime Ripard
1166a721db1SMaxime Ripard /*
1176a721db1SMaxime Ripard * If the frequency is a multiple of 2 but not a multiple of
1186a721db1SMaxime Ripard * 3, m is 3. This is the first time we use 6 here, yet we
1196a721db1SMaxime Ripard * will use it on several other places.
1206a721db1SMaxime Ripard * We use this number because it's the lowest frequency we can
1216a721db1SMaxime Ripard * generate (with n = 0, k = 0, m = 3), so every other frequency
1226a721db1SMaxime Ripard * somehow relates to this frequency.
1236a721db1SMaxime Ripard */
1246a721db1SMaxime Ripard if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4)
125cfa63688SChen-Yu Tsai req->m = 2;
1266a721db1SMaxime Ripard /*
1276a721db1SMaxime Ripard * If the frequency is a multiple of 6MHz, but the factor is
1286a721db1SMaxime Ripard * odd, m will be 3
1296a721db1SMaxime Ripard */
1306a721db1SMaxime Ripard else if ((freq_mhz / 6) & 1)
131cfa63688SChen-Yu Tsai req->m = 3;
1326a721db1SMaxime Ripard /* Otherwise, we end up with m = 1 */
1336a721db1SMaxime Ripard else
134cfa63688SChen-Yu Tsai req->m = 1;
1356a721db1SMaxime Ripard
1366a721db1SMaxime Ripard /* Calculate n thanks to the above factors we already got */
137cfa63688SChen-Yu Tsai req->n = freq_mhz * (req->m + 1) / ((req->k + 1) * parent_freq_mhz)
138cfa63688SChen-Yu Tsai - 1;
1396a721db1SMaxime Ripard
1406a721db1SMaxime Ripard /*
1416a721db1SMaxime Ripard * If n end up being outbound, and that we can still decrease
1426a721db1SMaxime Ripard * m, do it.
1436a721db1SMaxime Ripard */
144cfa63688SChen-Yu Tsai if ((req->n + 1) > 31 && (req->m + 1) > 1) {
145cfa63688SChen-Yu Tsai req->n = (req->n + 1) / 2 - 1;
146cfa63688SChen-Yu Tsai req->m = (req->m + 1) / 2 - 1;
1476a721db1SMaxime Ripard }
1486a721db1SMaxime Ripard }
149e874a669SEmilio López
150*58fdf74dSLee Jones /*
151515c1a4bSChen-Yu Tsai * sun8i_a23_get_pll1_factors() - calculates n, k, m, p factors for PLL1
152515c1a4bSChen-Yu Tsai * PLL1 rate is calculated as follows
153515c1a4bSChen-Yu Tsai * rate = (parent_rate * (n + 1) * (k + 1) >> p) / (m + 1);
154515c1a4bSChen-Yu Tsai * parent_rate is always 24Mhz
155515c1a4bSChen-Yu Tsai */
156515c1a4bSChen-Yu Tsai
sun8i_a23_get_pll1_factors(struct factors_request * req)157cfa63688SChen-Yu Tsai static void sun8i_a23_get_pll1_factors(struct factors_request *req)
158515c1a4bSChen-Yu Tsai {
159515c1a4bSChen-Yu Tsai u8 div;
160515c1a4bSChen-Yu Tsai
161515c1a4bSChen-Yu Tsai /* Normalize value to a 6M multiple */
162cfa63688SChen-Yu Tsai div = req->rate / 6000000;
163cfa63688SChen-Yu Tsai req->rate = 6000000 * div;
164515c1a4bSChen-Yu Tsai
165515c1a4bSChen-Yu Tsai /* m is always zero for pll1 */
166cfa63688SChen-Yu Tsai req->m = 0;
167515c1a4bSChen-Yu Tsai
168515c1a4bSChen-Yu Tsai /* k is 1 only on these cases */
169cfa63688SChen-Yu Tsai if (req->rate >= 768000000 || req->rate == 42000000 ||
170cfa63688SChen-Yu Tsai req->rate == 54000000)
171cfa63688SChen-Yu Tsai req->k = 1;
172515c1a4bSChen-Yu Tsai else
173cfa63688SChen-Yu Tsai req->k = 0;
174515c1a4bSChen-Yu Tsai
175515c1a4bSChen-Yu Tsai /* p will be 2 for divs under 20 and odd divs under 32 */
176515c1a4bSChen-Yu Tsai if (div < 20 || (div < 32 && (div & 1)))
177cfa63688SChen-Yu Tsai req->p = 2;
178515c1a4bSChen-Yu Tsai
179515c1a4bSChen-Yu Tsai /* p will be 1 for even divs under 32, divs under 40 and odd pairs
180515c1a4bSChen-Yu Tsai * of divs between 40-62 */
181515c1a4bSChen-Yu Tsai else if (div < 40 || (div < 64 && (div & 2)))
182cfa63688SChen-Yu Tsai req->p = 1;
183515c1a4bSChen-Yu Tsai
184515c1a4bSChen-Yu Tsai /* any other entries have p = 0 */
185515c1a4bSChen-Yu Tsai else
186cfa63688SChen-Yu Tsai req->p = 0;
187515c1a4bSChen-Yu Tsai
188515c1a4bSChen-Yu Tsai /* calculate a suitable n based on k and p */
189cfa63688SChen-Yu Tsai div <<= req->p;
190cfa63688SChen-Yu Tsai div /= (req->k + 1);
191cfa63688SChen-Yu Tsai req->n = div / 4 - 1;
192515c1a4bSChen-Yu Tsai }
193515c1a4bSChen-Yu Tsai
194*58fdf74dSLee Jones /*
195d584c133SEmilio López * sun4i_get_pll5_factors() - calculates n, k factors for PLL5
196d584c133SEmilio López * PLL5 rate is calculated as follows
197d584c133SEmilio López * rate = parent_rate * n * (k + 1)
198d584c133SEmilio López * parent_rate is always 24Mhz
199d584c133SEmilio López */
200d584c133SEmilio López
sun4i_get_pll5_factors(struct factors_request * req)201cfa63688SChen-Yu Tsai static void sun4i_get_pll5_factors(struct factors_request *req)
202d584c133SEmilio López {
203d584c133SEmilio López u8 div;
204d584c133SEmilio López
205d584c133SEmilio López /* Normalize value to a parent_rate multiple (24M) */
206cfa63688SChen-Yu Tsai div = req->rate / req->parent_rate;
207cfa63688SChen-Yu Tsai req->rate = req->parent_rate * div;
208d584c133SEmilio López
209d584c133SEmilio López if (div < 31)
210cfa63688SChen-Yu Tsai req->k = 0;
211d584c133SEmilio López else if (div / 2 < 31)
212cfa63688SChen-Yu Tsai req->k = 1;
213d584c133SEmilio López else if (div / 3 < 31)
214cfa63688SChen-Yu Tsai req->k = 2;
215d584c133SEmilio López else
216cfa63688SChen-Yu Tsai req->k = 3;
217d584c133SEmilio López
218cfa63688SChen-Yu Tsai req->n = DIV_ROUND_UP(div, (req->k + 1));
219d584c133SEmilio López }
220d584c133SEmilio López
221*58fdf74dSLee Jones /*
22295e94c1fSChen-Yu Tsai * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6x2
22395e94c1fSChen-Yu Tsai * PLL6x2 rate is calculated as follows
22495e94c1fSChen-Yu Tsai * rate = parent_rate * (n + 1) * (k + 1)
22592ef67c5SMaxime Ripard * parent_rate is always 24Mhz
22692ef67c5SMaxime Ripard */
227d584c133SEmilio López
sun6i_a31_get_pll6_factors(struct factors_request * req)228cfa63688SChen-Yu Tsai static void sun6i_a31_get_pll6_factors(struct factors_request *req)
22992ef67c5SMaxime Ripard {
23092ef67c5SMaxime Ripard u8 div;
23192ef67c5SMaxime Ripard
23295e94c1fSChen-Yu Tsai /* Normalize value to a parent_rate multiple (24M) */
233cfa63688SChen-Yu Tsai div = req->rate / req->parent_rate;
234cfa63688SChen-Yu Tsai req->rate = req->parent_rate * div;
23592ef67c5SMaxime Ripard
236cfa63688SChen-Yu Tsai req->k = div / 32;
237cfa63688SChen-Yu Tsai if (req->k > 3)
238cfa63688SChen-Yu Tsai req->k = 3;
23992ef67c5SMaxime Ripard
240cfa63688SChen-Yu Tsai req->n = DIV_ROUND_UP(div, (req->k + 1)) - 1;
24192ef67c5SMaxime Ripard }
242d584c133SEmilio López
243*58fdf74dSLee Jones /*
2449f243097SChen-Yu Tsai * sun5i_a13_get_ahb_factors() - calculates m, p factors for AHB
2459f243097SChen-Yu Tsai * AHB rate is calculated as follows
2469f243097SChen-Yu Tsai * rate = parent_rate >> p
2479f243097SChen-Yu Tsai */
2489f243097SChen-Yu Tsai
sun5i_a13_get_ahb_factors(struct factors_request * req)249cfa63688SChen-Yu Tsai static void sun5i_a13_get_ahb_factors(struct factors_request *req)
2509f243097SChen-Yu Tsai {
2519f243097SChen-Yu Tsai u32 div;
2529f243097SChen-Yu Tsai
2539f243097SChen-Yu Tsai /* divide only */
254cfa63688SChen-Yu Tsai if (req->parent_rate < req->rate)
255cfa63688SChen-Yu Tsai req->rate = req->parent_rate;
2569f243097SChen-Yu Tsai
2579f243097SChen-Yu Tsai /*
2589f243097SChen-Yu Tsai * user manual says valid speed is 8k ~ 276M, but tests show it
2599f243097SChen-Yu Tsai * can work at speeds up to 300M, just after reparenting to pll6
2609f243097SChen-Yu Tsai */
261cfa63688SChen-Yu Tsai if (req->rate < 8000)
262cfa63688SChen-Yu Tsai req->rate = 8000;
263cfa63688SChen-Yu Tsai if (req->rate > 300000000)
264cfa63688SChen-Yu Tsai req->rate = 300000000;
2659f243097SChen-Yu Tsai
266cfa63688SChen-Yu Tsai div = order_base_2(DIV_ROUND_UP(req->parent_rate, req->rate));
2679f243097SChen-Yu Tsai
2689f243097SChen-Yu Tsai /* p = 0 ~ 3 */
2699f243097SChen-Yu Tsai if (div > 3)
2709f243097SChen-Yu Tsai div = 3;
2719f243097SChen-Yu Tsai
272cfa63688SChen-Yu Tsai req->rate = req->parent_rate >> div;
2739f243097SChen-Yu Tsai
274cfa63688SChen-Yu Tsai req->p = div;
2759f243097SChen-Yu Tsai }
2769f243097SChen-Yu Tsai
277a78bb355SChen-Yu Tsai #define SUN6I_AHB1_PARENT_PLL6 3
278a78bb355SChen-Yu Tsai
279*58fdf74dSLee Jones /*
280a78bb355SChen-Yu Tsai * sun6i_a31_get_ahb_factors() - calculates m, p factors for AHB
281a78bb355SChen-Yu Tsai * AHB rate is calculated as follows
282a78bb355SChen-Yu Tsai * rate = parent_rate >> p
283a78bb355SChen-Yu Tsai *
284a78bb355SChen-Yu Tsai * if parent is pll6, then
285a78bb355SChen-Yu Tsai * parent_rate = pll6 rate / (m + 1)
286a78bb355SChen-Yu Tsai */
287a78bb355SChen-Yu Tsai
sun6i_get_ahb1_factors(struct factors_request * req)288a78bb355SChen-Yu Tsai static void sun6i_get_ahb1_factors(struct factors_request *req)
289a78bb355SChen-Yu Tsai {
290a78bb355SChen-Yu Tsai u8 div, calcp, calcm = 1;
291a78bb355SChen-Yu Tsai
292a78bb355SChen-Yu Tsai /*
293a78bb355SChen-Yu Tsai * clock can only divide, so we will never be able to achieve
294a78bb355SChen-Yu Tsai * frequencies higher than the parent frequency
295a78bb355SChen-Yu Tsai */
296a78bb355SChen-Yu Tsai if (req->parent_rate && req->rate > req->parent_rate)
297a78bb355SChen-Yu Tsai req->rate = req->parent_rate;
298a78bb355SChen-Yu Tsai
299a78bb355SChen-Yu Tsai div = DIV_ROUND_UP(req->parent_rate, req->rate);
300a78bb355SChen-Yu Tsai
301a78bb355SChen-Yu Tsai /* calculate pre-divider if parent is pll6 */
302a78bb355SChen-Yu Tsai if (req->parent_index == SUN6I_AHB1_PARENT_PLL6) {
303a78bb355SChen-Yu Tsai if (div < 4)
304a78bb355SChen-Yu Tsai calcp = 0;
305a78bb355SChen-Yu Tsai else if (div / 2 < 4)
306a78bb355SChen-Yu Tsai calcp = 1;
307a78bb355SChen-Yu Tsai else if (div / 4 < 4)
308a78bb355SChen-Yu Tsai calcp = 2;
309a78bb355SChen-Yu Tsai else
310a78bb355SChen-Yu Tsai calcp = 3;
311a78bb355SChen-Yu Tsai
312a78bb355SChen-Yu Tsai calcm = DIV_ROUND_UP(div, 1 << calcp);
313a78bb355SChen-Yu Tsai } else {
314a78bb355SChen-Yu Tsai calcp = __roundup_pow_of_two(div);
315a78bb355SChen-Yu Tsai calcp = calcp > 3 ? 3 : calcp;
316a78bb355SChen-Yu Tsai }
317a78bb355SChen-Yu Tsai
318a78bb355SChen-Yu Tsai req->rate = (req->parent_rate / calcm) >> calcp;
319a78bb355SChen-Yu Tsai req->p = calcp;
320a78bb355SChen-Yu Tsai req->m = calcm - 1;
321a78bb355SChen-Yu Tsai }
322a78bb355SChen-Yu Tsai
323*58fdf74dSLee Jones /*
324a78bb355SChen-Yu Tsai * sun6i_ahb1_recalc() - calculates AHB clock rate from m, p factors and
325a78bb355SChen-Yu Tsai * parent index
326a78bb355SChen-Yu Tsai */
sun6i_ahb1_recalc(struct factors_request * req)327a78bb355SChen-Yu Tsai static void sun6i_ahb1_recalc(struct factors_request *req)
328a78bb355SChen-Yu Tsai {
329a78bb355SChen-Yu Tsai req->rate = req->parent_rate;
330a78bb355SChen-Yu Tsai
331a78bb355SChen-Yu Tsai /* apply pre-divider first if parent is pll6 */
332a78bb355SChen-Yu Tsai if (req->parent_index == SUN6I_AHB1_PARENT_PLL6)
333a78bb355SChen-Yu Tsai req->rate /= req->m + 1;
334a78bb355SChen-Yu Tsai
335a78bb355SChen-Yu Tsai /* clk divider */
336a78bb355SChen-Yu Tsai req->rate >>= req->p;
337a78bb355SChen-Yu Tsai }
338a78bb355SChen-Yu Tsai
339*58fdf74dSLee Jones /*
34081ba6c5eSMaxime Ripard * sun4i_get_apb1_factors() - calculates m, p factors for APB1
341e874a669SEmilio López * APB1 rate is calculated as follows
342e874a669SEmilio López * rate = (parent_rate >> p) / (m + 1);
343e874a669SEmilio López */
344e874a669SEmilio López
sun4i_get_apb1_factors(struct factors_request * req)345cfa63688SChen-Yu Tsai static void sun4i_get_apb1_factors(struct factors_request *req)
346e874a669SEmilio López {
347e874a669SEmilio López u8 calcm, calcp;
348cfa63688SChen-Yu Tsai int div;
349e874a669SEmilio López
350cfa63688SChen-Yu Tsai if (req->parent_rate < req->rate)
351cfa63688SChen-Yu Tsai req->rate = req->parent_rate;
352e874a669SEmilio López
353cfa63688SChen-Yu Tsai div = DIV_ROUND_UP(req->parent_rate, req->rate);
354e874a669SEmilio López
355e874a669SEmilio López /* Invalid rate! */
356cfa63688SChen-Yu Tsai if (div > 32)
357e874a669SEmilio López return;
358e874a669SEmilio López
359cfa63688SChen-Yu Tsai if (div <= 4)
360e874a669SEmilio López calcp = 0;
361cfa63688SChen-Yu Tsai else if (div <= 8)
362e874a669SEmilio López calcp = 1;
363cfa63688SChen-Yu Tsai else if (div <= 16)
364e874a669SEmilio López calcp = 2;
365e874a669SEmilio López else
366e874a669SEmilio López calcp = 3;
367e874a669SEmilio López
368ac95330bSStéphan Rafin calcm = (div >> calcp) - 1;
369e874a669SEmilio López
370cfa63688SChen-Yu Tsai req->rate = (req->parent_rate >> calcp) / (calcm + 1);
371cfa63688SChen-Yu Tsai req->m = calcm;
372cfa63688SChen-Yu Tsai req->p = calcp;
373e874a669SEmilio López }
374e874a669SEmilio López
375e874a669SEmilio López
376e874a669SEmilio López
3777551769aSEmilio López
378*58fdf74dSLee Jones /*
3796f863417SChen-Yu Tsai * sun7i_a20_get_out_factors() - calculates m, p factors for CLK_OUT_A/B
3806f863417SChen-Yu Tsai * CLK_OUT rate is calculated as follows
3816f863417SChen-Yu Tsai * rate = (parent_rate >> p) / (m + 1);
3826f863417SChen-Yu Tsai */
3836f863417SChen-Yu Tsai
sun7i_a20_get_out_factors(struct factors_request * req)384cfa63688SChen-Yu Tsai static void sun7i_a20_get_out_factors(struct factors_request *req)
3856f863417SChen-Yu Tsai {
3866f863417SChen-Yu Tsai u8 div, calcm, calcp;
3876f863417SChen-Yu Tsai
3886f863417SChen-Yu Tsai /* These clocks can only divide, so we will never be able to achieve
3896f863417SChen-Yu Tsai * frequencies higher than the parent frequency */
390cfa63688SChen-Yu Tsai if (req->rate > req->parent_rate)
391cfa63688SChen-Yu Tsai req->rate = req->parent_rate;
3926f863417SChen-Yu Tsai
393cfa63688SChen-Yu Tsai div = DIV_ROUND_UP(req->parent_rate, req->rate);
3946f863417SChen-Yu Tsai
3956f863417SChen-Yu Tsai if (div < 32)
3966f863417SChen-Yu Tsai calcp = 0;
3976f863417SChen-Yu Tsai else if (div / 2 < 32)
3986f863417SChen-Yu Tsai calcp = 1;
3996f863417SChen-Yu Tsai else if (div / 4 < 32)
4006f863417SChen-Yu Tsai calcp = 2;
4016f863417SChen-Yu Tsai else
4026f863417SChen-Yu Tsai calcp = 3;
4036f863417SChen-Yu Tsai
4046f863417SChen-Yu Tsai calcm = DIV_ROUND_UP(div, 1 << calcp);
4056f863417SChen-Yu Tsai
406cfa63688SChen-Yu Tsai req->rate = (req->parent_rate >> calcp) / calcm;
407cfa63688SChen-Yu Tsai req->m = calcm - 1;
408cfa63688SChen-Yu Tsai req->p = calcp;
4096f863417SChen-Yu Tsai }
4106f863417SChen-Yu Tsai
411*58fdf74dSLee Jones /*
412e874a669SEmilio López * sunxi_factors_clk_setup() - Setup function for factor clocks
413e874a669SEmilio López */
414e874a669SEmilio López
415b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun4i_pll1_config = {
416e874a669SEmilio López .nshift = 8,
417e874a669SEmilio López .nwidth = 5,
418e874a669SEmilio López .kshift = 4,
419e874a669SEmilio López .kwidth = 2,
420e874a669SEmilio López .mshift = 0,
421e874a669SEmilio López .mwidth = 2,
422e874a669SEmilio López .pshift = 16,
423e874a669SEmilio López .pwidth = 2,
424e874a669SEmilio López };
425e874a669SEmilio López
426b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun6i_a31_pll1_config = {
4276a721db1SMaxime Ripard .nshift = 8,
4286a721db1SMaxime Ripard .nwidth = 5,
4296a721db1SMaxime Ripard .kshift = 4,
4306a721db1SMaxime Ripard .kwidth = 2,
4316a721db1SMaxime Ripard .mshift = 0,
4326a721db1SMaxime Ripard .mwidth = 2,
43376820fcfSHans de Goede .n_start = 1,
4346a721db1SMaxime Ripard };
4356a721db1SMaxime Ripard
436b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun8i_a23_pll1_config = {
437515c1a4bSChen-Yu Tsai .nshift = 8,
438515c1a4bSChen-Yu Tsai .nwidth = 5,
439515c1a4bSChen-Yu Tsai .kshift = 4,
440515c1a4bSChen-Yu Tsai .kwidth = 2,
441515c1a4bSChen-Yu Tsai .mshift = 0,
442515c1a4bSChen-Yu Tsai .mwidth = 2,
443515c1a4bSChen-Yu Tsai .pshift = 16,
444515c1a4bSChen-Yu Tsai .pwidth = 2,
445515c1a4bSChen-Yu Tsai .n_start = 1,
446515c1a4bSChen-Yu Tsai };
447515c1a4bSChen-Yu Tsai
448b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun4i_pll5_config = {
449d584c133SEmilio López .nshift = 8,
450d584c133SEmilio López .nwidth = 5,
451d584c133SEmilio López .kshift = 4,
452d584c133SEmilio López .kwidth = 2,
453d584c133SEmilio López };
454d584c133SEmilio López
455b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun6i_a31_pll6_config = {
45692ef67c5SMaxime Ripard .nshift = 8,
45792ef67c5SMaxime Ripard .nwidth = 5,
45892ef67c5SMaxime Ripard .kshift = 4,
45992ef67c5SMaxime Ripard .kwidth = 2,
46095e94c1fSChen-Yu Tsai .n_start = 1,
46192ef67c5SMaxime Ripard };
46292ef67c5SMaxime Ripard
463b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun5i_a13_ahb_config = {
4649f243097SChen-Yu Tsai .pshift = 4,
4659f243097SChen-Yu Tsai .pwidth = 2,
4669f243097SChen-Yu Tsai };
4679f243097SChen-Yu Tsai
468a78bb355SChen-Yu Tsai static const struct clk_factors_config sun6i_ahb1_config = {
469a78bb355SChen-Yu Tsai .mshift = 6,
470a78bb355SChen-Yu Tsai .mwidth = 2,
471a78bb355SChen-Yu Tsai .pshift = 4,
472a78bb355SChen-Yu Tsai .pwidth = 2,
473a78bb355SChen-Yu Tsai };
474a78bb355SChen-Yu Tsai
475b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun4i_apb1_config = {
476e874a669SEmilio López .mshift = 0,
477e874a669SEmilio López .mwidth = 5,
478e874a669SEmilio López .pshift = 16,
479e874a669SEmilio López .pwidth = 2,
480e874a669SEmilio López };
481e874a669SEmilio López
4827551769aSEmilio López /* user manual says "n" but it's really "p" */
483b3e919e0SChen-Yu Tsai static const struct clk_factors_config sun7i_a20_out_config = {
4846f863417SChen-Yu Tsai .mshift = 8,
4856f863417SChen-Yu Tsai .mwidth = 5,
4866f863417SChen-Yu Tsai .pshift = 20,
4876f863417SChen-Yu Tsai .pwidth = 2,
4886f863417SChen-Yu Tsai };
4896f863417SChen-Yu Tsai
49052be7cc8SSachin Kamat static const struct factors_data sun4i_pll1_data __initconst = {
491d838ff33SEmilio López .enable = 31,
49281ba6c5eSMaxime Ripard .table = &sun4i_pll1_config,
49381ba6c5eSMaxime Ripard .getter = sun4i_get_pll1_factors,
494e874a669SEmilio López };
495e874a669SEmilio López
49652be7cc8SSachin Kamat static const struct factors_data sun6i_a31_pll1_data __initconst = {
497d838ff33SEmilio López .enable = 31,
4986a721db1SMaxime Ripard .table = &sun6i_a31_pll1_config,
4996a721db1SMaxime Ripard .getter = sun6i_a31_get_pll1_factors,
5006a721db1SMaxime Ripard };
5016a721db1SMaxime Ripard
502515c1a4bSChen-Yu Tsai static const struct factors_data sun8i_a23_pll1_data __initconst = {
503515c1a4bSChen-Yu Tsai .enable = 31,
504515c1a4bSChen-Yu Tsai .table = &sun8i_a23_pll1_config,
505515c1a4bSChen-Yu Tsai .getter = sun8i_a23_get_pll1_factors,
506515c1a4bSChen-Yu Tsai };
507515c1a4bSChen-Yu Tsai
5085a8ddf26SEmilio López static const struct factors_data sun7i_a20_pll4_data __initconst = {
5095a8ddf26SEmilio López .enable = 31,
5105a8ddf26SEmilio López .table = &sun4i_pll5_config,
5115a8ddf26SEmilio López .getter = sun4i_get_pll5_factors,
5125a8ddf26SEmilio López };
5135a8ddf26SEmilio López
514d584c133SEmilio López static const struct factors_data sun4i_pll5_data __initconst = {
515d584c133SEmilio López .enable = 31,
516d584c133SEmilio López .table = &sun4i_pll5_config,
517d584c133SEmilio López .getter = sun4i_get_pll5_factors,
518d584c133SEmilio López };
519d584c133SEmilio López
52092ef67c5SMaxime Ripard static const struct factors_data sun6i_a31_pll6_data __initconst = {
52192ef67c5SMaxime Ripard .enable = 31,
52292ef67c5SMaxime Ripard .table = &sun6i_a31_pll6_config,
52392ef67c5SMaxime Ripard .getter = sun6i_a31_get_pll6_factors,
52492ef67c5SMaxime Ripard };
52592ef67c5SMaxime Ripard
5269f243097SChen-Yu Tsai static const struct factors_data sun5i_a13_ahb_data __initconst = {
5279f243097SChen-Yu Tsai .mux = 6,
5289f243097SChen-Yu Tsai .muxmask = BIT(1) | BIT(0),
5299f243097SChen-Yu Tsai .table = &sun5i_a13_ahb_config,
5309f243097SChen-Yu Tsai .getter = sun5i_a13_get_ahb_factors,
5319f243097SChen-Yu Tsai };
5329f243097SChen-Yu Tsai
533a78bb355SChen-Yu Tsai static const struct factors_data sun6i_ahb1_data __initconst = {
534a78bb355SChen-Yu Tsai .mux = 12,
535a78bb355SChen-Yu Tsai .muxmask = BIT(1) | BIT(0),
536a78bb355SChen-Yu Tsai .table = &sun6i_ahb1_config,
537a78bb355SChen-Yu Tsai .getter = sun6i_get_ahb1_factors,
538a78bb355SChen-Yu Tsai .recalc = sun6i_ahb1_recalc,
539a78bb355SChen-Yu Tsai };
540a78bb355SChen-Yu Tsai
54152be7cc8SSachin Kamat static const struct factors_data sun4i_apb1_data __initconst = {
54293746e70SEmilio López .mux = 24,
54393746e70SEmilio López .muxmask = BIT(1) | BIT(0),
54481ba6c5eSMaxime Ripard .table = &sun4i_apb1_config,
54581ba6c5eSMaxime Ripard .getter = sun4i_get_apb1_factors,
546e874a669SEmilio López };
547e874a669SEmilio López
5486f863417SChen-Yu Tsai static const struct factors_data sun7i_a20_out_data __initconst = {
5496f863417SChen-Yu Tsai .enable = 31,
5506f863417SChen-Yu Tsai .mux = 24,
551e94f8cb3SChen-Yu Tsai .muxmask = BIT(1) | BIT(0),
5526f863417SChen-Yu Tsai .table = &sun7i_a20_out_config,
5536f863417SChen-Yu Tsai .getter = sun7i_a20_get_out_factors,
5546f863417SChen-Yu Tsai };
5556f863417SChen-Yu Tsai
sunxi_factors_clk_setup(struct device_node * node,const struct factors_data * data)5565f4e0be3SEmilio López static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
5575f4e0be3SEmilio López const struct factors_data *data)
558e874a669SEmilio López {
5597c74c220SHans de Goede void __iomem *reg;
5607c74c220SHans de Goede
5617c74c220SHans de Goede reg = of_iomap(node, 0);
5627c74c220SHans de Goede if (!reg) {
563e665f029SRob Herring pr_err("Could not get registers for factors-clk: %pOFn\n",
564e665f029SRob Herring node);
5657c74c220SHans de Goede return NULL;
5667c74c220SHans de Goede }
5677c74c220SHans de Goede
5687c74c220SHans de Goede return sunxi_factors_register(node, data, &clk_lock, reg);
569e874a669SEmilio López }
570e874a669SEmilio López
sun4i_pll1_clk_setup(struct device_node * node)571c0872308SMaxime Ripard static void __init sun4i_pll1_clk_setup(struct device_node *node)
572c0872308SMaxime Ripard {
573c0872308SMaxime Ripard sunxi_factors_clk_setup(node, &sun4i_pll1_data);
574c0872308SMaxime Ripard }
575c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_pll1, "allwinner,sun4i-a10-pll1-clk",
576c0872308SMaxime Ripard sun4i_pll1_clk_setup);
577c0872308SMaxime Ripard
sun6i_pll1_clk_setup(struct device_node * node)578c0872308SMaxime Ripard static void __init sun6i_pll1_clk_setup(struct device_node *node)
579c0872308SMaxime Ripard {
580c0872308SMaxime Ripard sunxi_factors_clk_setup(node, &sun6i_a31_pll1_data);
581c0872308SMaxime Ripard }
582c0872308SMaxime Ripard CLK_OF_DECLARE(sun6i_pll1, "allwinner,sun6i-a31-pll1-clk",
583c0872308SMaxime Ripard sun6i_pll1_clk_setup);
584c0872308SMaxime Ripard
sun8i_pll1_clk_setup(struct device_node * node)585c0872308SMaxime Ripard static void __init sun8i_pll1_clk_setup(struct device_node *node)
586c0872308SMaxime Ripard {
587c0872308SMaxime Ripard sunxi_factors_clk_setup(node, &sun8i_a23_pll1_data);
588c0872308SMaxime Ripard }
589c0872308SMaxime Ripard CLK_OF_DECLARE(sun8i_pll1, "allwinner,sun8i-a23-pll1-clk",
590c0872308SMaxime Ripard sun8i_pll1_clk_setup);
591c0872308SMaxime Ripard
sun7i_pll4_clk_setup(struct device_node * node)592c0872308SMaxime Ripard static void __init sun7i_pll4_clk_setup(struct device_node *node)
593c0872308SMaxime Ripard {
594c0872308SMaxime Ripard sunxi_factors_clk_setup(node, &sun7i_a20_pll4_data);
595c0872308SMaxime Ripard }
596c0872308SMaxime Ripard CLK_OF_DECLARE(sun7i_pll4, "allwinner,sun7i-a20-pll4-clk",
597c0872308SMaxime Ripard sun7i_pll4_clk_setup);
598c0872308SMaxime Ripard
sun5i_ahb_clk_setup(struct device_node * node)599c0872308SMaxime Ripard static void __init sun5i_ahb_clk_setup(struct device_node *node)
600c0872308SMaxime Ripard {
601c0872308SMaxime Ripard sunxi_factors_clk_setup(node, &sun5i_a13_ahb_data);
602c0872308SMaxime Ripard }
603c0872308SMaxime Ripard CLK_OF_DECLARE(sun5i_ahb, "allwinner,sun5i-a13-ahb-clk",
604c0872308SMaxime Ripard sun5i_ahb_clk_setup);
605c0872308SMaxime Ripard
sun6i_ahb1_clk_setup(struct device_node * node)606a78bb355SChen-Yu Tsai static void __init sun6i_ahb1_clk_setup(struct device_node *node)
607a78bb355SChen-Yu Tsai {
608a78bb355SChen-Yu Tsai sunxi_factors_clk_setup(node, &sun6i_ahb1_data);
609a78bb355SChen-Yu Tsai }
610a78bb355SChen-Yu Tsai CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-clk",
611a78bb355SChen-Yu Tsai sun6i_ahb1_clk_setup);
612e874a669SEmilio López
sun4i_apb1_clk_setup(struct device_node * node)613c0872308SMaxime Ripard static void __init sun4i_apb1_clk_setup(struct device_node *node)
614c0872308SMaxime Ripard {
615c0872308SMaxime Ripard sunxi_factors_clk_setup(node, &sun4i_apb1_data);
616c0872308SMaxime Ripard }
617c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_apb1, "allwinner,sun4i-a10-apb1-clk",
618c0872308SMaxime Ripard sun4i_apb1_clk_setup);
619c0872308SMaxime Ripard
sun7i_out_clk_setup(struct device_node * node)620c0872308SMaxime Ripard static void __init sun7i_out_clk_setup(struct device_node *node)
621c0872308SMaxime Ripard {
622c0872308SMaxime Ripard sunxi_factors_clk_setup(node, &sun7i_a20_out_data);
623c0872308SMaxime Ripard }
624c0872308SMaxime Ripard CLK_OF_DECLARE(sun7i_out, "allwinner,sun7i-a20-out-clk",
625c0872308SMaxime Ripard sun7i_out_clk_setup);
626c0872308SMaxime Ripard
627e874a669SEmilio López
628*58fdf74dSLee Jones /*
629e874a669SEmilio López * sunxi_mux_clk_setup() - Setup function for muxes
630e874a669SEmilio López */
631e874a669SEmilio López
632e874a669SEmilio López #define SUNXI_MUX_GATE_WIDTH 2
633e874a669SEmilio López
634e874a669SEmilio López struct mux_data {
635e874a669SEmilio López u8 shift;
636e874a669SEmilio López };
637e874a669SEmilio López
63852be7cc8SSachin Kamat static const struct mux_data sun4i_cpu_mux_data __initconst = {
639e874a669SEmilio López .shift = 16,
640e874a669SEmilio López };
641e874a669SEmilio López
64252be7cc8SSachin Kamat static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = {
6436a721db1SMaxime Ripard .shift = 12,
6446a721db1SMaxime Ripard };
6456a721db1SMaxime Ripard
646ab6e23a4SJens Kuske static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = {
647ab6e23a4SJens Kuske .shift = 0,
648ab6e23a4SJens Kuske };
649ab6e23a4SJens Kuske
sunxi_mux_clk_setup(struct device_node * node,const struct mux_data * data,unsigned long flags)65096f185acSMaxime Ripard static struct clk * __init sunxi_mux_clk_setup(struct device_node *node,
6519919d44fSStephen Boyd const struct mux_data *data,
6529919d44fSStephen Boyd unsigned long flags)
653e874a669SEmilio López {
654e874a669SEmilio López struct clk *clk;
655e874a669SEmilio López const char *clk_name = node->name;
656edaf3fb5SEmilio López const char *parents[SUNXI_MAX_PARENTS];
65789a9456dSEmilio López void __iomem *reg;
6588a53fb2bSDinh Nguyen int i;
659e874a669SEmilio López
660e874a669SEmilio López reg = of_iomap(node, 0);
66172360b91SAndre Przywara if (!reg) {
66216673931SRob Herring pr_err("Could not map registers for mux-clk: %pOF\n", node);
66372360b91SAndre Przywara return NULL;
66472360b91SAndre Przywara }
665e874a669SEmilio López
6668a53fb2bSDinh Nguyen i = of_clk_parent_fill(node, parents, SUNXI_MAX_PARENTS);
667d221b7a8SAndre Przywara if (of_property_read_string(node, "clock-output-names", &clk_name)) {
66816673931SRob Herring pr_err("%s: could not read clock-output-names from \"%pOF\"\n",
66916673931SRob Herring __func__, node);
670d221b7a8SAndre Przywara goto out_unmap;
671d221b7a8SAndre Przywara }
672f64111ebSChen-Yu Tsai
673819c1de3SJames Hogan clk = clk_register_mux(NULL, clk_name, parents, i,
6749919d44fSStephen Boyd CLK_SET_RATE_PARENT | flags, reg,
675e874a669SEmilio López data->shift, SUNXI_MUX_GATE_WIDTH,
676e874a669SEmilio López 0, &clk_lock);
677e874a669SEmilio López
678d221b7a8SAndre Przywara if (IS_ERR(clk)) {
67972360b91SAndre Przywara pr_err("%s: failed to register mux clock %s: %ld\n", __func__,
680d221b7a8SAndre Przywara clk_name, PTR_ERR(clk));
681d221b7a8SAndre Przywara goto out_unmap;
682d221b7a8SAndre Przywara }
683d221b7a8SAndre Przywara
68472360b91SAndre Przywara if (of_clk_add_provider(node, of_clk_src_simple_get, clk)) {
68572360b91SAndre Przywara pr_err("%s: failed to add clock provider for %s\n",
68672360b91SAndre Przywara __func__, clk_name);
68772360b91SAndre Przywara clk_unregister_divider(clk);
68872360b91SAndre Przywara goto out_unmap;
68972360b91SAndre Przywara }
69096f185acSMaxime Ripard
69196f185acSMaxime Ripard return clk;
692d221b7a8SAndre Przywara out_unmap:
693d221b7a8SAndre Przywara iounmap(reg);
69496f185acSMaxime Ripard return NULL;
695e874a669SEmilio López }
696e874a669SEmilio López
sun4i_cpu_clk_setup(struct device_node * node)697c0872308SMaxime Ripard static void __init sun4i_cpu_clk_setup(struct device_node *node)
698c0872308SMaxime Ripard {
699c0872308SMaxime Ripard /* Protect CPU clock */
7009919d44fSStephen Boyd sunxi_mux_clk_setup(node, &sun4i_cpu_mux_data, CLK_IS_CRITICAL);
701c0872308SMaxime Ripard }
702c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_cpu, "allwinner,sun4i-a10-cpu-clk",
703c0872308SMaxime Ripard sun4i_cpu_clk_setup);
704c0872308SMaxime Ripard
sun6i_ahb1_mux_clk_setup(struct device_node * node)705c0872308SMaxime Ripard static void __init sun6i_ahb1_mux_clk_setup(struct device_node *node)
706c0872308SMaxime Ripard {
7079919d44fSStephen Boyd sunxi_mux_clk_setup(node, &sun6i_a31_ahb1_mux_data, 0);
708c0872308SMaxime Ripard }
709c0872308SMaxime Ripard CLK_OF_DECLARE(sun6i_ahb1_mux, "allwinner,sun6i-a31-ahb1-mux-clk",
710c0872308SMaxime Ripard sun6i_ahb1_mux_clk_setup);
711c0872308SMaxime Ripard
sun8i_ahb2_clk_setup(struct device_node * node)712c0872308SMaxime Ripard static void __init sun8i_ahb2_clk_setup(struct device_node *node)
713c0872308SMaxime Ripard {
7149919d44fSStephen Boyd sunxi_mux_clk_setup(node, &sun8i_h3_ahb2_mux_data, 0);
715c0872308SMaxime Ripard }
716c0872308SMaxime Ripard CLK_OF_DECLARE(sun8i_ahb2, "allwinner,sun8i-h3-ahb2-clk",
717c0872308SMaxime Ripard sun8i_ahb2_clk_setup);
718e874a669SEmilio López
719e874a669SEmilio López
720*58fdf74dSLee Jones /*
721e874a669SEmilio López * sunxi_divider_clk_setup() - Setup function for simple divider clocks
722e874a669SEmilio López */
723e874a669SEmilio López
724e874a669SEmilio López struct div_data {
725e874a669SEmilio López u8 shift;
726e874a669SEmilio López u8 pow;
72770855bb5SMaxime Ripard u8 width;
728ea5671bfSChen-Yu Tsai const struct clk_div_table *table;
729e874a669SEmilio López };
730e874a669SEmilio López
73152be7cc8SSachin Kamat static const struct div_data sun4i_axi_data __initconst = {
732e874a669SEmilio López .shift = 0,
733e874a669SEmilio López .pow = 0,
73470855bb5SMaxime Ripard .width = 2,
735e874a669SEmilio López };
736e874a669SEmilio López
737515c1a4bSChen-Yu Tsai static const struct clk_div_table sun8i_a23_axi_table[] __initconst = {
738515c1a4bSChen-Yu Tsai { .val = 0, .div = 1 },
739515c1a4bSChen-Yu Tsai { .val = 1, .div = 2 },
740515c1a4bSChen-Yu Tsai { .val = 2, .div = 3 },
741515c1a4bSChen-Yu Tsai { .val = 3, .div = 4 },
742515c1a4bSChen-Yu Tsai { .val = 4, .div = 4 },
743515c1a4bSChen-Yu Tsai { .val = 5, .div = 4 },
744515c1a4bSChen-Yu Tsai { .val = 6, .div = 4 },
745515c1a4bSChen-Yu Tsai { .val = 7, .div = 4 },
746515c1a4bSChen-Yu Tsai { } /* sentinel */
747515c1a4bSChen-Yu Tsai };
748515c1a4bSChen-Yu Tsai
749515c1a4bSChen-Yu Tsai static const struct div_data sun8i_a23_axi_data __initconst = {
750515c1a4bSChen-Yu Tsai .width = 3,
751515c1a4bSChen-Yu Tsai .table = sun8i_a23_axi_table,
752515c1a4bSChen-Yu Tsai };
753515c1a4bSChen-Yu Tsai
75452be7cc8SSachin Kamat static const struct div_data sun4i_ahb_data __initconst = {
755e874a669SEmilio López .shift = 4,
756e874a669SEmilio López .pow = 1,
75770855bb5SMaxime Ripard .width = 2,
758e874a669SEmilio López };
759e874a669SEmilio López
760cfe4c93bSChen-Yu Tsai static const struct clk_div_table sun4i_apb0_table[] __initconst = {
761cfe4c93bSChen-Yu Tsai { .val = 0, .div = 2 },
762cfe4c93bSChen-Yu Tsai { .val = 1, .div = 2 },
763cfe4c93bSChen-Yu Tsai { .val = 2, .div = 4 },
764cfe4c93bSChen-Yu Tsai { .val = 3, .div = 8 },
765cfe4c93bSChen-Yu Tsai { } /* sentinel */
766cfe4c93bSChen-Yu Tsai };
767cfe4c93bSChen-Yu Tsai
76852be7cc8SSachin Kamat static const struct div_data sun4i_apb0_data __initconst = {
769e874a669SEmilio López .shift = 8,
770e874a669SEmilio López .pow = 1,
77170855bb5SMaxime Ripard .width = 2,
772cfe4c93bSChen-Yu Tsai .table = sun4i_apb0_table,
773e874a669SEmilio López };
774e874a669SEmilio López
sunxi_divider_clk_setup(struct device_node * node,const struct div_data * data)775e874a669SEmilio López static void __init sunxi_divider_clk_setup(struct device_node *node,
7765b5226d1SMaxime Ripard const struct div_data *data)
777e874a669SEmilio López {
778e874a669SEmilio López struct clk *clk;
779e874a669SEmilio López const char *clk_name = node->name;
780e874a669SEmilio López const char *clk_parent;
78189a9456dSEmilio López void __iomem *reg;
782e874a669SEmilio López
783e874a669SEmilio López reg = of_iomap(node, 0);
784b26803ebSAndre Przywara if (!reg) {
78516673931SRob Herring pr_err("Could not map registers for mux-clk: %pOF\n", node);
786b26803ebSAndre Przywara return;
787b26803ebSAndre Przywara }
788e874a669SEmilio López
789e874a669SEmilio López clk_parent = of_clk_get_parent_name(node, 0);
790e874a669SEmilio López
791b26803ebSAndre Przywara if (of_property_read_string(node, "clock-output-names", &clk_name)) {
79216673931SRob Herring pr_err("%s: could not read clock-output-names from \"%pOF\"\n",
79316673931SRob Herring __func__, node);
794b26803ebSAndre Przywara goto out_unmap;
795b26803ebSAndre Przywara }
796f64111ebSChen-Yu Tsai
797ea5671bfSChen-Yu Tsai clk = clk_register_divider_table(NULL, clk_name, clk_parent, 0,
79870855bb5SMaxime Ripard reg, data->shift, data->width,
799e874a669SEmilio López data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
800ea5671bfSChen-Yu Tsai data->table, &clk_lock);
801b26803ebSAndre Przywara if (IS_ERR(clk)) {
802b26803ebSAndre Przywara pr_err("%s: failed to register divider clock %s: %ld\n",
803b26803ebSAndre Przywara __func__, clk_name, PTR_ERR(clk));
804b26803ebSAndre Przywara goto out_unmap;
805b26803ebSAndre Przywara }
806b26803ebSAndre Przywara
807b26803ebSAndre Przywara if (of_clk_add_provider(node, of_clk_src_simple_get, clk)) {
808b26803ebSAndre Przywara pr_err("%s: failed to add clock provider for %s\n",
809b26803ebSAndre Przywara __func__, clk_name);
810b26803ebSAndre Przywara goto out_unregister;
811b26803ebSAndre Przywara }
812b26803ebSAndre Przywara
813b26803ebSAndre Przywara if (clk_register_clkdev(clk, clk_name, NULL)) {
814b26803ebSAndre Przywara of_clk_del_provider(node);
815b26803ebSAndre Przywara goto out_unregister;
816b26803ebSAndre Przywara }
817b26803ebSAndre Przywara
818b26803ebSAndre Przywara return;
819b26803ebSAndre Przywara out_unregister:
820b26803ebSAndre Przywara clk_unregister_divider(clk);
821b26803ebSAndre Przywara
822b26803ebSAndre Przywara out_unmap:
823b26803ebSAndre Przywara iounmap(reg);
824e874a669SEmilio López }
825e874a669SEmilio López
sun4i_ahb_clk_setup(struct device_node * node)826c0872308SMaxime Ripard static void __init sun4i_ahb_clk_setup(struct device_node *node)
827c0872308SMaxime Ripard {
828c0872308SMaxime Ripard sunxi_divider_clk_setup(node, &sun4i_ahb_data);
829c0872308SMaxime Ripard }
830c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_ahb, "allwinner,sun4i-a10-ahb-clk",
831c0872308SMaxime Ripard sun4i_ahb_clk_setup);
832c0872308SMaxime Ripard
sun4i_apb0_clk_setup(struct device_node * node)833c0872308SMaxime Ripard static void __init sun4i_apb0_clk_setup(struct device_node *node)
834c0872308SMaxime Ripard {
835c0872308SMaxime Ripard sunxi_divider_clk_setup(node, &sun4i_apb0_data);
836c0872308SMaxime Ripard }
837c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_apb0, "allwinner,sun4i-a10-apb0-clk",
838c0872308SMaxime Ripard sun4i_apb0_clk_setup);
839c0872308SMaxime Ripard
sun4i_axi_clk_setup(struct device_node * node)840c0872308SMaxime Ripard static void __init sun4i_axi_clk_setup(struct device_node *node)
841c0872308SMaxime Ripard {
842c0872308SMaxime Ripard sunxi_divider_clk_setup(node, &sun4i_axi_data);
843c0872308SMaxime Ripard }
844c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_axi, "allwinner,sun4i-a10-axi-clk",
845c0872308SMaxime Ripard sun4i_axi_clk_setup);
846c0872308SMaxime Ripard
sun8i_axi_clk_setup(struct device_node * node)847c0872308SMaxime Ripard static void __init sun8i_axi_clk_setup(struct device_node *node)
848c0872308SMaxime Ripard {
849c0872308SMaxime Ripard sunxi_divider_clk_setup(node, &sun8i_a23_axi_data);
850c0872308SMaxime Ripard }
851c0872308SMaxime Ripard CLK_OF_DECLARE(sun8i_axi, "allwinner,sun8i-a23-axi-clk",
852c0872308SMaxime Ripard sun8i_axi_clk_setup);
853c0872308SMaxime Ripard
854e874a669SEmilio López
85513569a70SEmilio López
856*58fdf74dSLee Jones /*
85713569a70SEmilio López * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks
85813569a70SEmilio López */
85913569a70SEmilio López
86013569a70SEmilio López #define SUNXI_GATES_MAX_SIZE 64
86113569a70SEmilio López
86213569a70SEmilio López struct gates_data {
86313569a70SEmilio López DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
86413569a70SEmilio López };
86513569a70SEmilio López
866*58fdf74dSLee Jones /*
867d584c133SEmilio López * sunxi_divs_clk_setup() helper data
868d584c133SEmilio López */
869d584c133SEmilio López
870934fe5f4SChen-Yu Tsai #define SUNXI_DIVS_MAX_QTY 4
871d584c133SEmilio López #define SUNXI_DIVISOR_WIDTH 2
872d584c133SEmilio López
873d584c133SEmilio López struct divs_data {
874d584c133SEmilio López const struct factors_data *factors; /* data for the factor clock */
875934fe5f4SChen-Yu Tsai int ndivs; /* number of outputs */
876934fe5f4SChen-Yu Tsai /*
877934fe5f4SChen-Yu Tsai * List of outputs. Refer to the diagram for sunxi_divs_clk_setup():
878934fe5f4SChen-Yu Tsai * self or base factor clock refers to the output from the pll
879934fe5f4SChen-Yu Tsai * itself. The remaining refer to fixed or configurable divider
880934fe5f4SChen-Yu Tsai * outputs.
881934fe5f4SChen-Yu Tsai */
882d584c133SEmilio López struct {
883934fe5f4SChen-Yu Tsai u8 self; /* is it the base factor clock? (only one) */
884d584c133SEmilio López u8 fixed; /* is it a fixed divisor? if not... */
885d584c133SEmilio López struct clk_div_table *table; /* is it a table based divisor? */
886d584c133SEmilio López u8 shift; /* otherwise it's a normal divisor with this shift */
887d584c133SEmilio López u8 pow; /* is it power-of-two based? */
888d584c133SEmilio López u8 gate; /* is it independently gateable? */
8899919d44fSStephen Boyd bool critical;
890d584c133SEmilio López } div[SUNXI_DIVS_MAX_QTY];
891d584c133SEmilio López };
892d584c133SEmilio López
893d584c133SEmilio López static struct clk_div_table pll6_sata_tbl[] = {
894d584c133SEmilio López { .val = 0, .div = 6, },
895d584c133SEmilio López { .val = 1, .div = 12, },
896d584c133SEmilio López { .val = 2, .div = 18, },
897d584c133SEmilio López { .val = 3, .div = 24, },
898d584c133SEmilio López { } /* sentinel */
899d584c133SEmilio López };
900d584c133SEmilio López
901d584c133SEmilio López static const struct divs_data pll5_divs_data __initconst = {
902d584c133SEmilio López .factors = &sun4i_pll5_data,
90313d52f61SChen-Yu Tsai .ndivs = 2,
904d584c133SEmilio López .div = {
9059919d44fSStephen Boyd /* Protect PLL5_DDR */
9069919d44fSStephen Boyd { .shift = 0, .pow = 0, .critical = true }, /* M, DDR */
907d584c133SEmilio López { .shift = 16, .pow = 1, }, /* P, other */
908934fe5f4SChen-Yu Tsai /* No output for the base factor clock */
909d584c133SEmilio López }
910d584c133SEmilio López };
911d584c133SEmilio López
912d584c133SEmilio López static const struct divs_data pll6_divs_data __initconst = {
913ff2bb893SJens Kuske .factors = &sun4i_pll5_data,
914f1017969SChen-Yu Tsai .ndivs = 4,
915d584c133SEmilio López .div = {
916d584c133SEmilio López { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */
917d584c133SEmilio López { .fixed = 2 }, /* P, other */
918934fe5f4SChen-Yu Tsai { .self = 1 }, /* base factor clock, 2x */
919f1017969SChen-Yu Tsai { .fixed = 4 }, /* pll6 / 4, used as ahb input */
920d584c133SEmilio López }
921d584c133SEmilio López };
922d584c133SEmilio López
92395e94c1fSChen-Yu Tsai static const struct divs_data sun6i_a31_pll6_divs_data __initconst = {
92495e94c1fSChen-Yu Tsai .factors = &sun6i_a31_pll6_data,
925934fe5f4SChen-Yu Tsai .ndivs = 2,
92695e94c1fSChen-Yu Tsai .div = {
92795e94c1fSChen-Yu Tsai { .fixed = 2 }, /* normal output */
928934fe5f4SChen-Yu Tsai { .self = 1 }, /* base factor clock, 2x */
92995e94c1fSChen-Yu Tsai }
93095e94c1fSChen-Yu Tsai };
93195e94c1fSChen-Yu Tsai
932*58fdf74dSLee Jones /*
933d584c133SEmilio López * sunxi_divs_clk_setup() - Setup function for leaf divisors on clocks
934d584c133SEmilio López *
935d584c133SEmilio López * These clocks look something like this
936d584c133SEmilio López * ________________________
937d584c133SEmilio López * | ___divisor 1---|----> to consumer
938d584c133SEmilio López * parent >--| pll___/___divisor 2---|----> to consumer
939d584c133SEmilio López * | \_______________|____> to consumer
940d584c133SEmilio López * |________________________|
941d584c133SEmilio López */
942d584c133SEmilio López
sunxi_divs_clk_setup(struct device_node * node,const struct divs_data * data)94396f185acSMaxime Ripard static struct clk ** __init sunxi_divs_clk_setup(struct device_node *node,
9445b5226d1SMaxime Ripard const struct divs_data *data)
945d584c133SEmilio López {
946d584c133SEmilio López struct clk_onecell_data *clk_data;
94797e36b3cSChen-Yu Tsai const char *parent;
948d584c133SEmilio López const char *clk_name;
949d584c133SEmilio López struct clk **clks, *pclk;
950d584c133SEmilio López struct clk_hw *gate_hw, *rate_hw;
951d584c133SEmilio López const struct clk_ops *rate_ops;
952d584c133SEmilio López struct clk_gate *gate = NULL;
953d584c133SEmilio López struct clk_fixed_factor *fix_factor;
954d584c133SEmilio López struct clk_divider *divider;
955ff2bb893SJens Kuske struct factors_data factors = *data->factors;
956ff2bb893SJens Kuske char *derived_name = NULL;
95789a9456dSEmilio López void __iomem *reg;
95813d52f61SChen-Yu Tsai int ndivs = SUNXI_DIVS_MAX_QTY, i = 0;
959d584c133SEmilio López int flags, clkflags;
960d584c133SEmilio López
961934fe5f4SChen-Yu Tsai /* if number of children known, use it */
962934fe5f4SChen-Yu Tsai if (data->ndivs)
963934fe5f4SChen-Yu Tsai ndivs = data->ndivs;
964934fe5f4SChen-Yu Tsai
965ff2bb893SJens Kuske /* Try to find a name for base factor clock */
966ff2bb893SJens Kuske for (i = 0; i < ndivs; i++) {
967ff2bb893SJens Kuske if (data->div[i].self) {
968ff2bb893SJens Kuske of_property_read_string_index(node, "clock-output-names",
969ff2bb893SJens Kuske i, &factors.name);
970ff2bb893SJens Kuske break;
971ff2bb893SJens Kuske }
972ff2bb893SJens Kuske }
973ff2bb893SJens Kuske /* If we don't have a .self clk use the first output-name up to '_' */
974ff2bb893SJens Kuske if (factors.name == NULL) {
975ff2bb893SJens Kuske char *endp;
976ff2bb893SJens Kuske
977ff2bb893SJens Kuske of_property_read_string_index(node, "clock-output-names",
978ff2bb893SJens Kuske 0, &clk_name);
979ff2bb893SJens Kuske endp = strchr(clk_name, '_');
980ff2bb893SJens Kuske if (endp) {
981ff2bb893SJens Kuske derived_name = kstrndup(clk_name, endp - clk_name,
982ff2bb893SJens Kuske GFP_KERNEL);
983fcdf445fSGen Zhang if (!derived_name)
984fcdf445fSGen Zhang return NULL;
985ff2bb893SJens Kuske factors.name = derived_name;
986ff2bb893SJens Kuske } else {
987ff2bb893SJens Kuske factors.name = clk_name;
988ff2bb893SJens Kuske }
989ff2bb893SJens Kuske }
990ff2bb893SJens Kuske
991d584c133SEmilio López /* Set up factor clock that we will be dividing */
992ff2bb893SJens Kuske pclk = sunxi_factors_clk_setup(node, &factors);
993d331328dSAndre Przywara if (!pclk)
994d331328dSAndre Przywara return NULL;
995ff2bb893SJens Kuske
99697e36b3cSChen-Yu Tsai parent = __clk_get_name(pclk);
997ff2bb893SJens Kuske kfree(derived_name);
998d584c133SEmilio López
999d584c133SEmilio López reg = of_iomap(node, 0);
1000d331328dSAndre Przywara if (!reg) {
100116673931SRob Herring pr_err("Could not map registers for divs-clk: %pOF\n", node);
1002d331328dSAndre Przywara return NULL;
1003d331328dSAndre Przywara }
1004d584c133SEmilio López
1005d584c133SEmilio López clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
1006d584c133SEmilio López if (!clk_data)
1007d331328dSAndre Przywara goto out_unmap;
1008d584c133SEmilio López
1009934fe5f4SChen-Yu Tsai clks = kcalloc(ndivs, sizeof(*clks), GFP_KERNEL);
1010d584c133SEmilio López if (!clks)
1011d584c133SEmilio López goto free_clkdata;
1012d584c133SEmilio López
1013d584c133SEmilio López clk_data->clks = clks;
1014d584c133SEmilio López
1015d584c133SEmilio López /* It's not a good idea to have automatic reparenting changing
1016d584c133SEmilio López * our RAM clock! */
1017d584c133SEmilio López clkflags = !strcmp("pll5", parent) ? 0 : CLK_SET_RATE_PARENT;
1018d584c133SEmilio López
101913d52f61SChen-Yu Tsai for (i = 0; i < ndivs; i++) {
1020d584c133SEmilio López if (of_property_read_string_index(node, "clock-output-names",
1021d584c133SEmilio López i, &clk_name) != 0)
1022d584c133SEmilio López break;
1023d584c133SEmilio López
1024934fe5f4SChen-Yu Tsai /* If this is the base factor clock, only update clks */
1025934fe5f4SChen-Yu Tsai if (data->div[i].self) {
1026934fe5f4SChen-Yu Tsai clk_data->clks[i] = pclk;
1027934fe5f4SChen-Yu Tsai continue;
1028934fe5f4SChen-Yu Tsai }
1029934fe5f4SChen-Yu Tsai
1030d584c133SEmilio López gate_hw = NULL;
1031d584c133SEmilio López rate_hw = NULL;
1032d584c133SEmilio López rate_ops = NULL;
1033d584c133SEmilio López
1034d584c133SEmilio López /* If this leaf clock can be gated, create a gate */
1035d584c133SEmilio López if (data->div[i].gate) {
1036d584c133SEmilio López gate = kzalloc(sizeof(*gate), GFP_KERNEL);
1037d584c133SEmilio López if (!gate)
1038d584c133SEmilio López goto free_clks;
1039d584c133SEmilio López
1040d584c133SEmilio López gate->reg = reg;
1041d584c133SEmilio López gate->bit_idx = data->div[i].gate;
1042d584c133SEmilio López gate->lock = &clk_lock;
1043d584c133SEmilio López
1044d584c133SEmilio López gate_hw = &gate->hw;
1045d584c133SEmilio López }
1046d584c133SEmilio López
1047d584c133SEmilio López /* Leaves can be fixed or configurable divisors */
1048d584c133SEmilio López if (data->div[i].fixed) {
1049d584c133SEmilio López fix_factor = kzalloc(sizeof(*fix_factor), GFP_KERNEL);
1050d584c133SEmilio López if (!fix_factor)
1051d584c133SEmilio López goto free_gate;
1052d584c133SEmilio López
1053d584c133SEmilio López fix_factor->mult = 1;
1054d584c133SEmilio López fix_factor->div = data->div[i].fixed;
1055d584c133SEmilio López
1056d584c133SEmilio López rate_hw = &fix_factor->hw;
1057d584c133SEmilio López rate_ops = &clk_fixed_factor_ops;
1058d584c133SEmilio López } else {
1059d584c133SEmilio López divider = kzalloc(sizeof(*divider), GFP_KERNEL);
1060d584c133SEmilio López if (!divider)
1061d584c133SEmilio López goto free_gate;
1062d584c133SEmilio López
1063d584c133SEmilio López flags = data->div[i].pow ? CLK_DIVIDER_POWER_OF_TWO : 0;
1064d584c133SEmilio López
1065d584c133SEmilio López divider->reg = reg;
1066d584c133SEmilio López divider->shift = data->div[i].shift;
1067d584c133SEmilio López divider->width = SUNXI_DIVISOR_WIDTH;
1068d584c133SEmilio López divider->flags = flags;
1069d584c133SEmilio López divider->lock = &clk_lock;
1070d584c133SEmilio López divider->table = data->div[i].table;
1071d584c133SEmilio López
1072d584c133SEmilio López rate_hw = ÷r->hw;
1073d584c133SEmilio López rate_ops = &clk_divider_ops;
1074d584c133SEmilio López }
1075d584c133SEmilio López
1076d584c133SEmilio López /* Wrap the (potential) gate and the divisor on a composite
1077d584c133SEmilio López * clock to unify them */
1078d584c133SEmilio López clks[i] = clk_register_composite(NULL, clk_name, &parent, 1,
1079d584c133SEmilio López NULL, NULL,
1080d584c133SEmilio López rate_hw, rate_ops,
1081d584c133SEmilio López gate_hw, &clk_gate_ops,
10829919d44fSStephen Boyd clkflags |
1083afdc74edSNathan Chancellor (data->div[i].critical ?
1084afdc74edSNathan Chancellor CLK_IS_CRITICAL : 0));
1085d584c133SEmilio López
1086d584c133SEmilio López WARN_ON(IS_ERR(clk_data->clks[i]));
1087d584c133SEmilio López }
1088d584c133SEmilio López
1089d584c133SEmilio López /* Adjust to the real max */
1090d584c133SEmilio López clk_data->clk_num = i;
1091d584c133SEmilio López
1092d331328dSAndre Przywara if (of_clk_add_provider(node, of_clk_src_onecell_get, clk_data)) {
1093d331328dSAndre Przywara pr_err("%s: failed to add clock provider for %s\n",
1094d331328dSAndre Przywara __func__, clk_name);
1095d331328dSAndre Przywara goto free_gate;
1096d331328dSAndre Przywara }
1097d584c133SEmilio López
109896f185acSMaxime Ripard return clks;
1099d584c133SEmilio López free_gate:
1100d584c133SEmilio López kfree(gate);
1101d584c133SEmilio López free_clks:
1102d584c133SEmilio López kfree(clks);
1103d584c133SEmilio López free_clkdata:
1104d584c133SEmilio López kfree(clk_data);
1105d331328dSAndre Przywara out_unmap:
1106d331328dSAndre Przywara iounmap(reg);
110796f185acSMaxime Ripard return NULL;
1108d584c133SEmilio López }
1109d584c133SEmilio López
sun4i_pll5_clk_setup(struct device_node * node)1110c0872308SMaxime Ripard static void __init sun4i_pll5_clk_setup(struct device_node *node)
1111c0872308SMaxime Ripard {
11129919d44fSStephen Boyd sunxi_divs_clk_setup(node, &pll5_divs_data);
1113c0872308SMaxime Ripard }
1114c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_pll5, "allwinner,sun4i-a10-pll5-clk",
1115c0872308SMaxime Ripard sun4i_pll5_clk_setup);
1116c0872308SMaxime Ripard
sun4i_pll6_clk_setup(struct device_node * node)1117c0872308SMaxime Ripard static void __init sun4i_pll6_clk_setup(struct device_node *node)
1118c0872308SMaxime Ripard {
1119c0872308SMaxime Ripard sunxi_divs_clk_setup(node, &pll6_divs_data);
1120c0872308SMaxime Ripard }
1121c0872308SMaxime Ripard CLK_OF_DECLARE(sun4i_pll6, "allwinner,sun4i-a10-pll6-clk",
1122c0872308SMaxime Ripard sun4i_pll6_clk_setup);
1123c0872308SMaxime Ripard
sun6i_pll6_clk_setup(struct device_node * node)1124c0872308SMaxime Ripard static void __init sun6i_pll6_clk_setup(struct device_node *node)
1125c0872308SMaxime Ripard {
1126c0872308SMaxime Ripard sunxi_divs_clk_setup(node, &sun6i_a31_pll6_divs_data);
1127c0872308SMaxime Ripard }
1128c0872308SMaxime Ripard CLK_OF_DECLARE(sun6i_pll6, "allwinner,sun6i-a31-pll6-clk",
1129c0872308SMaxime Ripard sun6i_pll6_clk_setup);
11305ed400ddSJean-Francois Moine
11315ed400ddSJean-Francois Moine /*
11325ed400ddSJean-Francois Moine * sun6i display
11335ed400ddSJean-Francois Moine *
11345ed400ddSJean-Francois Moine * rate = parent_rate / (m + 1);
11355ed400ddSJean-Francois Moine */
sun6i_display_factors(struct factors_request * req)11365ed400ddSJean-Francois Moine static void sun6i_display_factors(struct factors_request *req)
11375ed400ddSJean-Francois Moine {
11385ed400ddSJean-Francois Moine u8 m;
11395ed400ddSJean-Francois Moine
11405ed400ddSJean-Francois Moine if (req->rate > req->parent_rate)
11415ed400ddSJean-Francois Moine req->rate = req->parent_rate;
11425ed400ddSJean-Francois Moine
11435ed400ddSJean-Francois Moine m = DIV_ROUND_UP(req->parent_rate, req->rate);
11445ed400ddSJean-Francois Moine
11455ed400ddSJean-Francois Moine req->rate = req->parent_rate / m;
11465ed400ddSJean-Francois Moine req->m = m - 1;
11475ed400ddSJean-Francois Moine }
11485ed400ddSJean-Francois Moine
11495ed400ddSJean-Francois Moine static const struct clk_factors_config sun6i_display_config = {
11505ed400ddSJean-Francois Moine .mshift = 0,
11515ed400ddSJean-Francois Moine .mwidth = 4,
11525ed400ddSJean-Francois Moine };
11535ed400ddSJean-Francois Moine
11545ed400ddSJean-Francois Moine static const struct factors_data sun6i_display_data __initconst = {
11555ed400ddSJean-Francois Moine .enable = 31,
11565ed400ddSJean-Francois Moine .mux = 24,
11575ed400ddSJean-Francois Moine .muxmask = BIT(2) | BIT(1) | BIT(0),
11585ed400ddSJean-Francois Moine .table = &sun6i_display_config,
11595ed400ddSJean-Francois Moine .getter = sun6i_display_factors,
11605ed400ddSJean-Francois Moine };
11615ed400ddSJean-Francois Moine
sun6i_display_setup(struct device_node * node)11625ed400ddSJean-Francois Moine static void __init sun6i_display_setup(struct device_node *node)
11635ed400ddSJean-Francois Moine {
11645ed400ddSJean-Francois Moine sunxi_factors_clk_setup(node, &sun6i_display_data);
11655ed400ddSJean-Francois Moine }
11665ed400ddSJean-Francois Moine CLK_OF_DECLARE(sun6i_display, "allwinner,sun6i-a31-display-clk",
11675ed400ddSJean-Francois Moine sun6i_display_setup);
1168