diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 14:54:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 14:54:50 -0400 |
commit | 92295f632cefbdf15d46e9ac5f0fc3cfade35259 (patch) | |
tree | 5b3820d4ed135ccbef540781d99a46137959bbb6 /drivers/clk/clk-vt8500.c | |
parent | 750b2d7b93f2ba19f4f238cc641bda22fe07c155 (diff) | |
parent | 45e3ec3784aec0d194740b75b547bfabca448ff3 (diff) |
Merge tag 'clk-for-linus-3.11' of git://git.linaro.org/people/mturquette/linux
Pull clock framework updates from Mike Turquette:
"The common clock framework changes for 3.11 include new clock drivers
across several different platforms and architectures, fixes to
existing drivers, a MAINTAINERS file fix and improvements to the basic
clock types that allow them to be of use to more platforms than before.
Only a few fixes to the core framework are included with most all of
the changes landing in the various clock drivers themselves."
* tag 'clk-for-linus-3.11' of git://git.linaro.org/people/mturquette/linux: (55 commits)
clk: tegra: fix ifdef for tegra_periph_reset_assert inline
clk: tegra: provide tegra_periph_reset_assert alternative
clk: exynos4: Fix clock aliases for cpufreq related clocks
clk: samsung: Add MUX_FA macro to pass flag and alias
clk: add support for Rockchip gate clocks
clk: vexpress: Make the clock drivers directly available for arm64
clk: vexpress: Use full node name to identify individual clocks
clk: tegra: T114: add DFLL DVCO reset control
clk: tegra: T114: add DFLL source clocks
clk: tegra: T114: add FCPU clock shaper programming, needed by the DFLL
clk: gate: add CLK_GATE_HIWORD_MASK
clk: divider: add CLK_DIVIDER_HIWORD_MASK flag
clk: mux: add CLK_MUX_HIWORD_MASK
clk: Always notify whole subtree when reparenting
MAINTAINERS: make drivers/clk entry match subdirs
clk: honor CLK_GET_RATE_NOCACHE in clk_set_rate
clk: use clk_get_rate() for debugfs
clk: tegra: Use override bits when needed
clk: tegra: override bits for Tegra30 PLLM
clk: tegra: override bits for Tegra114 PLLM
...
Diffstat (limited to 'drivers/clk/clk-vt8500.c')
-rw-r--r-- | drivers/clk/clk-vt8500.c | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index 553ac35bcc91..82306f5fb9c2 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c | |||
@@ -42,6 +42,7 @@ struct clk_device { | |||
42 | #define PLL_TYPE_VT8500 0 | 42 | #define PLL_TYPE_VT8500 0 |
43 | #define PLL_TYPE_WM8650 1 | 43 | #define PLL_TYPE_WM8650 1 |
44 | #define PLL_TYPE_WM8750 2 | 44 | #define PLL_TYPE_WM8750 2 |
45 | #define PLL_TYPE_WM8850 3 | ||
45 | 46 | ||
46 | struct clk_pll { | 47 | struct clk_pll { |
47 | struct clk_hw hw; | 48 | struct clk_hw hw; |
@@ -156,10 +157,6 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate, | |||
156 | 157 | ||
157 | divisor = parent_rate / rate; | 158 | divisor = parent_rate / rate; |
158 | 159 | ||
159 | /* If prate / rate would be decimal, incr the divisor */ | ||
160 | if (rate * divisor < parent_rate) | ||
161 | divisor++; | ||
162 | |||
163 | if (divisor == cdev->div_mask + 1) | 160 | if (divisor == cdev->div_mask + 1) |
164 | divisor = 0; | 161 | divisor = 0; |
165 | 162 | ||
@@ -327,6 +324,15 @@ CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init); | |||
327 | #define WM8750_BITS_TO_VAL(f, m, d1, d2) \ | 324 | #define WM8750_BITS_TO_VAL(f, m, d1, d2) \ |
328 | ((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2) | 325 | ((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2) |
329 | 326 | ||
327 | /* Helper macros for PLL_WM8850 */ | ||
328 | #define WM8850_PLL_MUL(x) ((((x >> 16) & 0x7F) + 1) * 2) | ||
329 | #define WM8850_PLL_DIV(x) ((((x >> 8) & 1) + 1) * (1 << (x & 3))) | ||
330 | |||
331 | #define WM8850_BITS_TO_FREQ(r, m, d1, d2) \ | ||
332 | (r * ((m + 1) * 2) / ((d1+1) * (1 << d2))) | ||
333 | |||
334 | #define WM8850_BITS_TO_VAL(m, d1, d2) \ | ||
335 | ((((m / 2) - 1) << 16) | ((d1 - 1) << 8) | d2) | ||
330 | 336 | ||
331 | static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, | 337 | static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate, |
332 | u32 *multiplier, u32 *prediv) | 338 | u32 *multiplier, u32 *prediv) |
@@ -466,6 +472,49 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate, | |||
466 | *divisor2 = best_div2; | 472 | *divisor2 = best_div2; |
467 | } | 473 | } |
468 | 474 | ||
475 | static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate, | ||
476 | u32 *multiplier, u32 *divisor1, u32 *divisor2) | ||
477 | { | ||
478 | u32 mul, div1, div2; | ||
479 | u32 best_mul, best_div1, best_div2; | ||
480 | unsigned long tclk, rate_err, best_err; | ||
481 | |||
482 | best_err = (unsigned long)-1; | ||
483 | |||
484 | /* Find the closest match (lower or equal to requested) */ | ||
485 | for (div1 = 1; div1 >= 0; div1--) | ||
486 | for (div2 = 3; div2 >= 0; div2--) | ||
487 | for (mul = 0; mul <= 127; mul++) { | ||
488 | tclk = parent_rate * ((mul + 1) * 2) / | ||
489 | ((div1 + 1) * (1 << div2)); | ||
490 | if (tclk > rate) | ||
491 | continue; | ||
492 | /* error will always be +ve */ | ||
493 | rate_err = rate - tclk; | ||
494 | if (rate_err == 0) { | ||
495 | *multiplier = mul; | ||
496 | *divisor1 = div1; | ||
497 | *divisor2 = div2; | ||
498 | return; | ||
499 | } | ||
500 | |||
501 | if (rate_err < best_err) { | ||
502 | best_err = rate_err; | ||
503 | best_mul = mul; | ||
504 | best_div1 = div1; | ||
505 | best_div2 = div2; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | /* if we got here, it wasn't an exact match */ | ||
510 | pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, | ||
511 | rate - best_err); | ||
512 | |||
513 | *multiplier = best_mul; | ||
514 | *divisor1 = best_div1; | ||
515 | *divisor2 = best_div2; | ||
516 | } | ||
517 | |||
469 | static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, | 518 | static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, |
470 | unsigned long parent_rate) | 519 | unsigned long parent_rate) |
471 | { | 520 | { |
@@ -489,6 +538,10 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |||
489 | wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2); | 538 | wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2); |
490 | pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2); | 539 | pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2); |
491 | break; | 540 | break; |
541 | case PLL_TYPE_WM8850: | ||
542 | wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2); | ||
543 | pll_val = WM8850_BITS_TO_VAL(mul, div1, div2); | ||
544 | break; | ||
492 | default: | 545 | default: |
493 | pr_err("%s: invalid pll type\n", __func__); | 546 | pr_err("%s: invalid pll type\n", __func__); |
494 | return 0; | 547 | return 0; |
@@ -525,6 +578,10 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, | |||
525 | wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2); | 578 | wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2); |
526 | round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2); | 579 | round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2); |
527 | break; | 580 | break; |
581 | case PLL_TYPE_WM8850: | ||
582 | wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2); | ||
583 | round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2); | ||
584 | break; | ||
528 | default: | 585 | default: |
529 | round_rate = 0; | 586 | round_rate = 0; |
530 | } | 587 | } |
@@ -552,6 +609,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw, | |||
552 | pll_freq = parent_rate * WM8750_PLL_MUL(pll_val); | 609 | pll_freq = parent_rate * WM8750_PLL_MUL(pll_val); |
553 | pll_freq /= WM8750_PLL_DIV(pll_val); | 610 | pll_freq /= WM8750_PLL_DIV(pll_val); |
554 | break; | 611 | break; |
612 | case PLL_TYPE_WM8850: | ||
613 | pll_freq = parent_rate * WM8850_PLL_MUL(pll_val); | ||
614 | pll_freq /= WM8850_PLL_DIV(pll_val); | ||
615 | break; | ||
555 | default: | 616 | default: |
556 | pll_freq = 0; | 617 | pll_freq = 0; |
557 | } | 618 | } |
@@ -628,6 +689,12 @@ static void __init wm8750_pll_init(struct device_node *node) | |||
628 | } | 689 | } |
629 | CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init); | 690 | CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init); |
630 | 691 | ||
692 | static void __init wm8850_pll_init(struct device_node *node) | ||
693 | { | ||
694 | vtwm_pll_clk_init(node, PLL_TYPE_WM8850); | ||
695 | } | ||
696 | CLK_OF_DECLARE(wm8850_pll, "wm,wm8850-pll-clock", wm8850_pll_init); | ||
697 | |||
631 | void __init vtwm_clk_init(void __iomem *base) | 698 | void __init vtwm_clk_init(void __iomem *base) |
632 | { | 699 | { |
633 | if (!base) | 700 | if (!base) |