aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk
diff options
context:
space:
mode:
authorMike Turquette <mturquette@linaro.org>2013-08-27 21:07:46 -0400
committerMike Turquette <mturquette@linaro.org>2013-08-27 21:07:46 -0400
commitc045ddeb3893c4614e6ab694b8d297e3badc23af (patch)
tree6e13aa83c08809b9d082511b43270da8d11551e5 /drivers/clk
parentaa514ce34b65e3dc01f95a0b470b39bbb7e09998 (diff)
parent1fb2e4aab8b31b15e6be5debacb4203333360fd2 (diff)
Merge tag 'sunxi-clk-for-3.12' of https://github.com/mripard/linux into clk-next-sunxi
Allwinner clock changes for 3.12 These patches mostly do some cleanup to introduce the basic gated clocks for the Allwinner A10s, A20 and A31 SoCs. Conflicts: drivers/clk/sunxi/clk-sunxi.c
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c232
1 files changed, 194 insertions, 38 deletions
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 3bbfca5850fd..d39f213f0fbe 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -25,12 +25,12 @@
25static DEFINE_SPINLOCK(clk_lock); 25static DEFINE_SPINLOCK(clk_lock);
26 26
27/** 27/**
28 * sunxi_osc_clk_setup() - Setup function for gatable oscillator 28 * sun4i_osc_clk_setup() - Setup function for gatable oscillator
29 */ 29 */
30 30
31#define SUNXI_OSC24M_GATE 0 31#define SUNXI_OSC24M_GATE 0
32 32
33static void __init sunxi_osc_clk_setup(struct device_node *node) 33static void __init sun4i_osc_clk_setup(struct device_node *node)
34{ 34{
35 struct clk *clk; 35 struct clk *clk;
36 struct clk_fixed_rate *fixed; 36 struct clk_fixed_rate *fixed;
@@ -69,18 +69,18 @@ static void __init sunxi_osc_clk_setup(struct device_node *node)
69 clk_register_clkdev(clk, clk_name, NULL); 69 clk_register_clkdev(clk, clk_name, NULL);
70 } 70 }
71} 71}
72CLK_OF_DECLARE(sunxi_osc, "allwinner,sun4i-osc-clk", sunxi_osc_clk_setup); 72CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup);
73 73
74 74
75 75
76/** 76/**
77 * sunxi_get_pll1_factors() - calculates n, k, m, p factors for PLL1 77 * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1
78 * PLL1 rate is calculated as follows 78 * PLL1 rate is calculated as follows
79 * rate = (parent_rate * n * (k + 1) >> p) / (m + 1); 79 * rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
80 * parent_rate is always 24Mhz 80 * parent_rate is always 24Mhz
81 */ 81 */
82 82
83static void sunxi_get_pll1_factors(u32 *freq, u32 parent_rate, 83static void sun4i_get_pll1_factors(u32 *freq, u32 parent_rate,
84 u8 *n, u8 *k, u8 *m, u8 *p) 84 u8 *n, u8 *k, u8 *m, u8 *p)
85{ 85{
86 u8 div; 86 u8 div;
@@ -125,15 +125,97 @@ static void sunxi_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 * sunxi_get_apb1_factors() - calculates m, p factors for APB1 213 * sun4i_get_apb1_factors() - calculates m, p factors for APB1
132 * APB1 rate is calculated as follows 214 * APB1 rate is calculated as follows
133 * rate = (parent_rate >> p) / (m + 1); 215 * rate = (parent_rate >> p) / (m + 1);
134 */ 216 */
135 217
136static void sunxi_get_apb1_factors(u32 *freq, u32 parent_rate, 218static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate,
137 u8 *n, u8 *k, u8 *m, u8 *p) 219 u8 *n, u8 *k, u8 *m, u8 *p)
138{ 220{
139 u8 calcm, calcp; 221 u8 calcm, calcp;
@@ -179,7 +261,7 @@ struct factors_data {
179 void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p); 261 void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
180}; 262};
181 263
182static struct clk_factors_config pll1_config = { 264static struct clk_factors_config sun4i_pll1_config = {
183 .nshift = 8, 265 .nshift = 8,
184 .nwidth = 5, 266 .nwidth = 5,
185 .kshift = 4, 267 .kshift = 4,
@@ -190,21 +272,35 @@ static struct clk_factors_config pll1_config = {
190 .pwidth = 2, 272 .pwidth = 2,
191}; 273};
192 274
193static struct clk_factors_config apb1_config = { 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
284static struct clk_factors_config sun4i_apb1_config = {
194 .mshift = 0, 285 .mshift = 0,
195 .mwidth = 5, 286 .mwidth = 5,
196 .pshift = 16, 287 .pshift = 16,
197 .pwidth = 2, 288 .pwidth = 2,
198}; 289};
199 290
200static const __initconst struct factors_data pll1_data = { 291static const __initconst struct factors_data sun4i_pll1_data = {
201 .table = &pll1_config, 292 .table = &sun4i_pll1_config,
202 .getter = sunxi_get_pll1_factors, 293 .getter = sun4i_get_pll1_factors,
294};
295
296static const __initconst struct factors_data sun6i_a31_pll1_data = {
297 .table = &sun6i_a31_pll1_config,
298 .getter = sun6i_a31_get_pll1_factors,
203}; 299};
204 300
205static const __initconst struct factors_data apb1_data = { 301static const __initconst struct factors_data sun4i_apb1_data = {
206 .table = &apb1_config, 302 .table = &sun4i_apb1_config,
207 .getter = sunxi_get_apb1_factors, 303 .getter = sun4i_get_apb1_factors,
208}; 304};
209 305
210static void __init sunxi_factors_clk_setup(struct device_node *node, 306static void __init sunxi_factors_clk_setup(struct device_node *node,
@@ -240,11 +336,15 @@ struct mux_data {
240 u8 shift; 336 u8 shift;
241}; 337};
242 338
243static const __initconst struct mux_data cpu_mux_data = { 339static const __initconst struct mux_data sun4i_cpu_mux_data = {
244 .shift = 16, 340 .shift = 16,
245}; 341};
246 342
247static const __initconst struct mux_data apb1_mux_data = { 343static const __initconst struct mux_data sun6i_a31_ahb1_mux_data = {
344 .shift = 12,
345};
346
347static const __initconst struct mux_data sun4i_apb1_mux_data = {
248 .shift = 24, 348 .shift = 24,
249}; 349};
250 350
@@ -279,26 +379,34 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
279 * sunxi_divider_clk_setup() - Setup function for simple divider clocks 379 * sunxi_divider_clk_setup() - Setup function for simple divider clocks
280 */ 380 */
281 381
282#define SUNXI_DIVISOR_WIDTH 2
283
284struct div_data { 382struct div_data {
285 u8 shift; 383 u8 shift;
286 u8 pow; 384 u8 pow;
385 u8 width;
386};
387
388static const __initconst struct div_data sun4i_axi_data = {
389 .shift = 0,
390 .pow = 0,
391 .width = 2,
287}; 392};
288 393
289static const __initconst struct div_data axi_data = { 394static const __initconst struct div_data sun4i_ahb_data = {
290 .shift = 0, 395 .shift = 4,
291 .pow = 0, 396 .pow = 1,
397 .width = 2,
292}; 398};
293 399
294static const __initconst struct div_data ahb_data = { 400static const __initconst struct div_data sun4i_apb0_data = {
295 .shift = 4, 401 .shift = 8,
296 .pow = 1, 402 .pow = 1,
403 .width = 2,
297}; 404};
298 405
299static const __initconst struct div_data apb0_data = { 406static const __initconst struct div_data sun6i_a31_apb2_div_data = {
300 .shift = 8, 407 .shift = 0,
301 .pow = 1, 408 .pow = 0,
409 .width = 4,
302}; 410};
303 411
304static void __init sunxi_divider_clk_setup(struct device_node *node, 412static void __init sunxi_divider_clk_setup(struct device_node *node,
@@ -314,7 +422,7 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
314 clk_parent = of_clk_get_parent_name(node, 0); 422 clk_parent = of_clk_get_parent_name(node, 0);
315 423
316 clk = clk_register_divider(NULL, clk_name, clk_parent, 0, 424 clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
317 reg, data->shift, SUNXI_DIVISOR_WIDTH, 425 reg, data->shift, data->width,
318 data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0, 426 data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
319 &clk_lock); 427 &clk_lock);
320 if (clk) { 428 if (clk) {
@@ -343,26 +451,62 @@ static const __initconst struct gates_data sun4i_ahb_gates_data = {
343 .mask = {0x7F77FFF, 0x14FB3F}, 451 .mask = {0x7F77FFF, 0x14FB3F},
344}; 452};
345 453
454static const __initconst struct gates_data sun5i_a10s_ahb_gates_data = {
455 .mask = {0x147667e7, 0x185915},
456};
457
346static const __initconst struct gates_data sun5i_a13_ahb_gates_data = { 458static const __initconst struct gates_data sun5i_a13_ahb_gates_data = {
347 .mask = {0x107067e7, 0x185111}, 459 .mask = {0x107067e7, 0x185111},
348}; 460};
349 461
462static const __initconst struct gates_data sun6i_a31_ahb1_gates_data = {
463 .mask = {0xEDFE7F62, 0x794F931},
464};
465
466static const __initconst struct gates_data sun7i_a20_ahb_gates_data = {
467 .mask = { 0x12f77fff, 0x16ff3f },
468};
469
350static const __initconst struct gates_data sun4i_apb0_gates_data = { 470static const __initconst struct gates_data sun4i_apb0_gates_data = {
351 .mask = {0x4EF}, 471 .mask = {0x4EF},
352}; 472};
353 473
474static const __initconst struct gates_data sun5i_a10s_apb0_gates_data = {
475 .mask = {0x469},
476};
477
354static const __initconst struct gates_data sun5i_a13_apb0_gates_data = { 478static const __initconst struct gates_data sun5i_a13_apb0_gates_data = {
355 .mask = {0x61}, 479 .mask = {0x61},
356}; 480};
357 481
482static const __initconst struct gates_data sun7i_a20_apb0_gates_data = {
483 .mask = { 0x4ff },
484};
485
358static const __initconst struct gates_data sun4i_apb1_gates_data = { 486static const __initconst struct gates_data sun4i_apb1_gates_data = {
359 .mask = {0xFF00F7}, 487 .mask = {0xFF00F7},
360}; 488};
361 489
490static const __initconst struct gates_data sun5i_a10s_apb1_gates_data = {
491 .mask = {0xf0007},
492};
493
362static const __initconst struct gates_data sun5i_a13_apb1_gates_data = { 494static const __initconst struct gates_data sun5i_a13_apb1_gates_data = {
363 .mask = {0xa0007}, 495 .mask = {0xa0007},
364}; 496};
365 497
498static const __initconst struct gates_data sun6i_a31_apb1_gates_data = {
499 .mask = {0x3031},
500};
501
502static const __initconst struct gates_data sun6i_a31_apb2_gates_data = {
503 .mask = {0x3F000F},
504};
505
506static const __initconst struct gates_data sun7i_a20_apb1_gates_data = {
507 .mask = { 0xff80ff },
508};
509
366static void __init sunxi_gates_clk_setup(struct device_node *node, 510static void __init sunxi_gates_clk_setup(struct device_node *node,
367 struct gates_data *data) 511 struct gates_data *data)
368{ 512{
@@ -414,23 +558,26 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
414 558
415/* Matches for factors clocks */ 559/* Matches for factors clocks */
416static const __initconst struct of_device_id clk_factors_match[] = { 560static const __initconst struct of_device_id clk_factors_match[] = {
417 {.compatible = "allwinner,sun4i-pll1-clk", .data = &pll1_data,}, 561 {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
418 {.compatible = "allwinner,sun4i-apb1-clk", .data = &apb1_data,}, 562 {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
563 {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
419 {} 564 {}
420}; 565};
421 566
422/* Matches for divider clocks */ 567/* Matches for divider clocks */
423static const __initconst struct of_device_id clk_div_match[] = { 568static const __initconst struct of_device_id clk_div_match[] = {
424 {.compatible = "allwinner,sun4i-axi-clk", .data = &axi_data,}, 569 {.compatible = "allwinner,sun4i-axi-clk", .data = &sun4i_axi_data,},
425 {.compatible = "allwinner,sun4i-ahb-clk", .data = &ahb_data,}, 570 {.compatible = "allwinner,sun4i-ahb-clk", .data = &sun4i_ahb_data,},
426 {.compatible = "allwinner,sun4i-apb0-clk", .data = &apb0_data,}, 571 {.compatible = "allwinner,sun4i-apb0-clk", .data = &sun4i_apb0_data,},
572 {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
427 {} 573 {}
428}; 574};
429 575
430/* Matches for mux clocks */ 576/* Matches for mux clocks */
431static const __initconst struct of_device_id clk_mux_match[] = { 577static const __initconst struct of_device_id clk_mux_match[] = {
432 {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_mux_data,}, 578 {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,},
433 {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,}, 579 {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
580 {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
434 {} 581 {}
435}; 582};
436 583
@@ -438,11 +585,20 @@ static const __initconst struct of_device_id clk_mux_match[] = {
438static const __initconst struct of_device_id clk_gates_match[] = { 585static const __initconst struct of_device_id clk_gates_match[] = {
439 {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,}, 586 {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,},
440 {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,}, 587 {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
588 {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,},
441 {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,}, 589 {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
590 {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
591 {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
442 {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,}, 592 {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
593 {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
443 {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,}, 594 {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
595 {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,},
444 {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,}, 596 {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
597 {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,},
445 {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,}, 598 {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
599 {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
600 {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
601 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
446 {} 602 {}
447}; 603};
448 604