xref: /openbmc/linux/drivers/clk/sunxi/clk-sunxi.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
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 = &divider->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