aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorMaxime Ripard <maxime.ripard@free-electrons.com>2013-07-23 17:34:10 -0400
committerMaxime Ripard <maxime.ripard@free-electrons.com>2013-08-26 04:58:11 -0400
commit6a721db180a22d8e2d59d864446309bc7a09c26f (patch)
tree9da6f6cccba5a87a701bcc87c9157a1717d7f0dc /drivers/clk
parent70855bb5c608e4ac9dde5b669c3cf56914b713a2 (diff)
clk: sunxi: Add A31 clocks support
The A31 has a mostly different clock set compared to the other older SoCs currently supported in the Allwinner clock driver. Add support for the basic useful clocks. The other ones will come in eventually. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Reviewed-by: Emilio López <emilio@elopez.com.ar>
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 2cafda88b7f6..6fd02042c13b 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -125,7 +125,89 @@ static void sun4i_get_pll1_factors(u32 *freq, u32 parent_rate,
125 *n = div / 4; 125 *n = div / 4;
126} 126}
127 127
128/**
129 * sun6i_a31_get_pll1_factors() - calculates n, k and m factors for PLL1
130 * PLL1 rate is calculated as follows
131 * rate = parent_rate * (n + 1) * (k + 1) / (m + 1);
132 * parent_rate should always be 24MHz
133 */
134static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
135 u8 *n, u8 *k, u8 *m, u8 *p)
136{
137 /*
138 * We can operate only on MHz, this will make our life easier
139 * later.
140 */
141 u32 freq_mhz = *freq / 1000000;
142 u32 parent_freq_mhz = parent_rate / 1000000;
143
144 /*
145 * Round down the frequency to the closest multiple of either
146 * 6 or 16
147 */
148 u32 round_freq_6 = round_down(freq_mhz, 6);
149 u32 round_freq_16 = round_down(freq_mhz, 16);
150
151 if (round_freq_6 > round_freq_16)
152 freq_mhz = round_freq_6;
153 else
154 freq_mhz = round_freq_16;
128 155
156 *freq = freq_mhz * 1000000;
157
158 /*
159 * If the factors pointer are null, we were just called to
160 * round down the frequency.
161 * Exit.
162 */
163 if (n == NULL)
164 return;
165
166 /* If the frequency is a multiple of 32 MHz, k is always 3 */
167 if (!(freq_mhz % 32))
168 *k = 3;
169 /* If the frequency is a multiple of 9 MHz, k is always 2 */
170 else if (!(freq_mhz % 9))
171 *k = 2;
172 /* If the frequency is a multiple of 8 MHz, k is always 1 */
173 else if (!(freq_mhz % 8))
174 *k = 1;
175 /* Otherwise, we don't use the k factor */
176 else
177 *k = 0;
178
179 /*
180 * If the frequency is a multiple of 2 but not a multiple of
181 * 3, m is 3. This is the first time we use 6 here, yet we
182 * will use it on several other places.
183 * We use this number because it's the lowest frequency we can
184 * generate (with n = 0, k = 0, m = 3), so every other frequency
185 * somehow relates to this frequency.
186 */
187 if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4)
188 *m = 2;
189 /*
190 * If the frequency is a multiple of 6MHz, but the factor is
191 * odd, m will be 3
192 */
193 else if ((freq_mhz / 6) & 1)
194 *m = 3;
195 /* Otherwise, we end up with m = 1 */
196 else
197 *m = 1;
198
199 /* Calculate n thanks to the above factors we already got */
200 *n = freq_mhz * (*m + 1) / ((*k + 1) * parent_freq_mhz) - 1;
201
202 /*
203 * If n end up being outbound, and that we can still decrease
204 * m, do it.
205 */
206 if ((*n + 1) > 31 && (*m + 1) > 1) {
207 *n = (*n + 1) / 2 - 1;
208 *m = (*m + 1) / 2 - 1;
209 }
210}
129 211
130/** 212/**
131 * sun4i_get_apb1_factors() - calculates m, p factors for APB1 213 * sun4i_get_apb1_factors() - calculates m, p factors for APB1
@@ -190,6 +272,15 @@ static struct clk_factors_config sun4i_pll1_config = {
190 .pwidth = 2, 272 .pwidth = 2,
191}; 273};
192 274
275static struct clk_factors_config sun6i_a31_pll1_config = {
276 .nshift = 8,
277 .nwidth = 5,
278 .kshift = 4,
279 .kwidth = 2,
280 .mshift = 0,
281 .mwidth = 2,
282};
283
193static struct clk_factors_config sun4i_apb1_config = { 284static struct clk_factors_config sun4i_apb1_config = {
194 .mshift = 0, 285 .mshift = 0,
195 .mwidth = 5, 286 .mwidth = 5,
@@ -202,6 +293,11 @@ static const __initconst struct factors_data sun4i_pll1_data = {
202 .getter = sun4i_get_pll1_factors, 293 .getter = sun4i_get_pll1_factors,
203}; 294};
204 295
296static const __initconst struct factors_data sun6i_a31_pll1_data = {
297 .table = &sun6i_a31_pll1_config,
298 .getter = sun6i_a31_get_pll1_factors,
299};
300
205static const __initconst struct factors_data sun4i_apb1_data = { 301static const __initconst struct factors_data sun4i_apb1_data = {
206 .table = &sun4i_apb1_config, 302 .table = &sun4i_apb1_config,
207 .getter = sun4i_get_apb1_factors, 303 .getter = sun4i_get_apb1_factors,
@@ -244,6 +340,10 @@ static const __initconst struct mux_data sun4i_cpu_mux_data = {
244 .shift = 16, 340 .shift = 16,
245}; 341};
246 342
343static const __initconst struct mux_data sun6i_a31_ahb1_mux_data = {
344 .shift = 12,
345};
346
247static const __initconst struct mux_data sun4i_apb1_mux_data = { 347static const __initconst struct mux_data sun4i_apb1_mux_data = {
248 .shift = 24, 348 .shift = 24,
249}; 349};
@@ -303,6 +403,12 @@ static const __initconst struct div_data sun4i_apb0_data = {
303 .width = 2, 403 .width = 2,
304}; 404};
305 405
406static const __initconst struct div_data sun6i_a31_apb2_div_data = {
407 .shift = 0,
408 .pow = 0,
409 .width = 4,
410};
411
306static void __init sunxi_divider_clk_setup(struct device_node *node, 412static void __init sunxi_divider_clk_setup(struct device_node *node,
307 struct div_data *data) 413 struct div_data *data)
308{ 414{
@@ -353,6 +459,10 @@ static const __initconst struct gates_data sun5i_a13_ahb_gates_data = {
353 .mask = {0x107067e7, 0x185111}, 459 .mask = {0x107067e7, 0x185111},
354}; 460};
355 461
462static const __initconst struct gates_data sun6i_a31_ahb1_gates_data = {
463 .mask = {0xEDFE7F62, 0x794F931},
464};
465
356static const __initconst struct gates_data sun4i_apb0_gates_data = { 466static const __initconst struct gates_data sun4i_apb0_gates_data = {
357 .mask = {0x4EF}, 467 .mask = {0x4EF},
358}; 468};
@@ -377,6 +487,14 @@ static const __initconst struct gates_data sun5i_a13_apb1_gates_data = {
377 .mask = {0xa0007}, 487 .mask = {0xa0007},
378}; 488};
379 489
490static const __initconst struct gates_data sun6i_a31_apb1_gates_data = {
491 .mask = {0x3031},
492};
493
494static const __initconst struct gates_data sun6i_a31_apb2_gates_data = {
495 .mask = {0x3F000F},
496};
497
380static void __init sunxi_gates_clk_setup(struct device_node *node, 498static void __init sunxi_gates_clk_setup(struct device_node *node,
381 struct gates_data *data) 499 struct gates_data *data)
382{ 500{
@@ -429,6 +547,7 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
429/* Matches for factors clocks */ 547/* Matches for factors clocks */
430static const __initconst struct of_device_id clk_factors_match[] = { 548static const __initconst struct of_device_id clk_factors_match[] = {
431 {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,}, 549 {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
550 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
432 {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,}, 551 {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
433 {} 552 {}
434}; 553};
@@ -438,6 +557,7 @@ static const __initconst struct of_device_id clk_div_match[] = {
438 {.compatible = "allwinner,sun4i-axi-clk", .data = &sun4i_axi_data,}, 557 {.compatible = "allwinner,sun4i-axi-clk", .data = &sun4i_axi_data,},
439 {.compatible = "allwinner,sun4i-ahb-clk", .data = &sun4i_ahb_data,}, 558 {.compatible = "allwinner,sun4i-ahb-clk", .data = &sun4i_ahb_data,},
440 {.compatible = "allwinner,sun4i-apb0-clk", .data = &sun4i_apb0_data,}, 559 {.compatible = "allwinner,sun4i-apb0-clk", .data = &sun4i_apb0_data,},
560 {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
441 {} 561 {}
442}; 562};
443 563
@@ -445,6 +565,7 @@ static const __initconst struct of_device_id clk_div_match[] = {
445static const __initconst struct of_device_id clk_mux_match[] = { 565static const __initconst struct of_device_id clk_mux_match[] = {
446 {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,}, 566 {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,},
447 {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &sun4i_apb1_mux_data,}, 567 {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
568 {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
448 {} 569 {}
449}; 570};
450 571
@@ -454,12 +575,15 @@ static const __initconst struct of_device_id clk_gates_match[] = {
454 {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,}, 575 {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
455 {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,}, 576 {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,},
456 {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, 577 {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
578 {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
457 {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, 579 {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
458 {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,}, 580 {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
459 {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, 581 {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
460 {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,}, 582 {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
461 {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,}, 583 {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,},
462 {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, 584 {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
585 {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
586 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
463 {} 587 {}
464}; 588};
465 589