* [PATCH 0/2] clk: vt8500: updates for 3.11
@ 2013-05-13 8:20 Tony Prisk
2013-05-13 8:20 ` [PATCH 1/2] clk: vt8500: Add support for clocks on the WM8850 SoCs Tony Prisk
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Tony Prisk @ 2013-05-13 8:20 UTC (permalink / raw)
To: linux-arm-kernel
Hi Mike,
Two updates for the arch-vt8500 clock code:
#1: Add support for the WM8850 PLL.
#2: Remove a second divisor check in vt8500_dclk_set_rate() which causes the
divisor to be round-down too low.
Regards
Tony Prisk
Tony Prisk (2):
clk: vt8500: Add support for clocks on the WM8850 SoCs
clk: vt8500: Remove unnecessary divisor adjustment in
vtwm_dclk_set_rate()
Documentation/devicetree/bindings/clock/vt8500.txt | 2 +
drivers/clk/clk-vt8500.c | 75 ++++++++++++++++++--
2 files changed, 73 insertions(+), 4 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] clk: vt8500: Add support for clocks on the WM8850 SoCs
2013-05-13 8:20 [PATCH 0/2] clk: vt8500: updates for 3.11 Tony Prisk
@ 2013-05-13 8:20 ` Tony Prisk
2013-05-13 8:21 ` [PATCH 2/2] clk: vt8500: Remove unnecessary divisor adjustment in vtwm_dclk_set_rate() Tony Prisk
2013-05-29 21:48 ` [PATCH 0/2] clk: vt8500: updates for 3.11 Mike Turquette
2 siblings, 0 replies; 4+ messages in thread
From: Tony Prisk @ 2013-05-13 8:20 UTC (permalink / raw)
To: linux-arm-kernel
The WM8850 has a different PLL clock to the previous versions. This
patch adds support for the WM8850-style PLL clocks.
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
Documentation/devicetree/bindings/clock/vt8500.txt | 2 +
drivers/clk/clk-vt8500.c | 71 ++++++++++++++++++++
2 files changed, 73 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/vt8500.txt b/Documentation/devicetree/bindings/clock/vt8500.txt
index a880c70..91d71cc 100644
--- a/Documentation/devicetree/bindings/clock/vt8500.txt
+++ b/Documentation/devicetree/bindings/clock/vt8500.txt
@@ -8,6 +8,8 @@ Required properties:
- compatible : shall be one of the following:
"via,vt8500-pll-clock" - for a VT8500/WM8505 PLL clock
"wm,wm8650-pll-clock" - for a WM8650 PLL clock
+ "wm,wm8750-pll-clock" - for a WM8750 PLL clock
+ "wm,wm8850-pll-clock" - for a WM8850 PLL clock
"via,vt8500-device-clock" - for a VT/WM device clock
Required properties for PLL clocks:
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index debf688..6d5b6e9 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -42,6 +42,7 @@ struct clk_device {
#define PLL_TYPE_VT8500 0
#define PLL_TYPE_WM8650 1
#define PLL_TYPE_WM8750 2
+#define PLL_TYPE_WM8850 3
struct clk_pll {
struct clk_hw hw;
@@ -327,6 +328,15 @@ CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
#define WM8750_BITS_TO_VAL(f, m, d1, d2) \
((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2)
+/* Helper macros for PLL_WM8850 */
+#define WM8850_PLL_MUL(x) ((((x >> 16) & 0x7F) + 1) * 2)
+#define WM8850_PLL_DIV(x) ((((x >> 8) & 1) + 1) * (1 << (x & 3)))
+
+#define WM8850_BITS_TO_FREQ(r, m, d1, d2) \
+ (r * ((m + 1) * 2) / ((d1+1) * (1 << d2)))
+
+#define WM8850_BITS_TO_VAL(m, d1, d2) \
+ ((((m / 2) - 1) << 16) | ((d1 - 1) << 8) | d2)
static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
u32 *multiplier, u32 *prediv)
@@ -466,6 +476,49 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
*divisor2 = best_div2;
}
+static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate,
+ u32 *multiplier, u32 *divisor1, u32 *divisor2)
+{
+ u32 mul, div1, div2;
+ u32 best_mul, best_div1, best_div2;
+ unsigned long tclk, rate_err, best_err;
+
+ best_err = (unsigned long)-1;
+
+ /* Find the closest match (lower or equal to requested) */
+ for (div1 = 1; div1 >= 0; div1--)
+ for (div2 = 3; div2 >= 0; div2--)
+ for (mul = 0; mul <= 127; mul++) {
+ tclk = parent_rate * ((mul + 1) * 2) /
+ ((div1 + 1) * (1 << div2));
+ if (tclk > rate)
+ continue;
+ /* error will always be +ve */
+ rate_err = rate - tclk;
+ if (rate_err == 0) {
+ *multiplier = mul;
+ *divisor1 = div1;
+ *divisor2 = div2;
+ return;
+ }
+
+ if (rate_err < best_err) {
+ best_err = rate_err;
+ best_mul = mul;
+ best_div1 = div1;
+ best_div2 = div2;
+ }
+ }
+
+ /* if we got here, it wasn't an exact match */
+ pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
+ rate - best_err);
+
+ *multiplier = best_mul;
+ *divisor1 = best_div1;
+ *divisor2 = best_div2;
+}
+
static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -489,6 +542,10 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
break;
+ case PLL_TYPE_WM8850:
+ wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
+ pll_val = WM8850_BITS_TO_VAL(mul, div1, div2);
+ break;
default:
pr_err("%s: invalid pll type\n", __func__);
return 0;
@@ -525,6 +582,10 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
break;
+ case PLL_TYPE_WM8850:
+ wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2);
+ round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2);
+ break;
default:
round_rate = 0;
}
@@ -552,6 +613,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
pll_freq /= WM8750_PLL_DIV(pll_val);
break;
+ case PLL_TYPE_WM8850:
+ pll_freq = parent_rate * WM8850_PLL_MUL(pll_val);
+ pll_freq /= WM8850_PLL_DIV(pll_val);
+ break;
default:
pll_freq = 0;
}
@@ -628,6 +693,12 @@ static void __init wm8750_pll_init(struct device_node *node)
}
CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
+static void __init wm8850_pll_init(struct device_node *node)
+{
+ vtwm_pll_clk_init(node, PLL_TYPE_WM8850);
+}
+CLK_OF_DECLARE(wm8850_pll, "wm,wm8850-pll-clock", wm8850_pll_init);
+
void __init vtwm_clk_init(void __iomem *base)
{
if (!base)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/2] clk: vt8500: Remove unnecessary divisor adjustment in vtwm_dclk_set_rate()
2013-05-13 8:20 [PATCH 0/2] clk: vt8500: updates for 3.11 Tony Prisk
2013-05-13 8:20 ` [PATCH 1/2] clk: vt8500: Add support for clocks on the WM8850 SoCs Tony Prisk
@ 2013-05-13 8:21 ` Tony Prisk
2013-05-29 21:48 ` [PATCH 0/2] clk: vt8500: updates for 3.11 Mike Turquette
2 siblings, 0 replies; 4+ messages in thread
From: Tony Prisk @ 2013-05-13 8:21 UTC (permalink / raw)
To: linux-arm-kernel
The divisor adjustment code to ensure that a divisor is not rounded down,
thereby giving a rate higher than requested, is unnecessary and in some
instances results in the actual rate being much lower than requested due to
rounding errors.
The test is already performed in vtwm_dclk_round_rate(), which is always
called when clk_set_rate is called. Due to rounding errors in the line:
divisor = parent_rate / rate (clk-vt8500.c:160) we will sometimes end up
adjusting the divisor twice - first in round_rate and then again in set_rate.
This patch removes the test/adjustment in vtwm_dclk_set_rate.
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
drivers/clk/clk-vt8500.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index 6d5b6e9..d8fd085 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -157,10 +157,6 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
divisor = parent_rate / rate;
- /* If prate / rate would be decimal, incr the divisor */
- if (rate * divisor < parent_rate)
- divisor++;
-
if (divisor == cdev->div_mask + 1)
divisor = 0;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 0/2] clk: vt8500: updates for 3.11
2013-05-13 8:20 [PATCH 0/2] clk: vt8500: updates for 3.11 Tony Prisk
2013-05-13 8:20 ` [PATCH 1/2] clk: vt8500: Add support for clocks on the WM8850 SoCs Tony Prisk
2013-05-13 8:21 ` [PATCH 2/2] clk: vt8500: Remove unnecessary divisor adjustment in vtwm_dclk_set_rate() Tony Prisk
@ 2013-05-29 21:48 ` Mike Turquette
2 siblings, 0 replies; 4+ messages in thread
From: Mike Turquette @ 2013-05-29 21:48 UTC (permalink / raw)
To: linux-arm-kernel
Quoting Tony Prisk (2013-05-13 01:20:58)
> Hi Mike,
>
> Two updates for the arch-vt8500 clock code:
>
> #1: Add support for the WM8850 PLL.
> #2: Remove a second divisor check in vt8500_dclk_set_rate() which causes the
> divisor to be round-down too low.
>
Taken both into clk-next.
Thanks,
Mike
> Regards
> Tony Prisk
>
> Tony Prisk (2):
> clk: vt8500: Add support for clocks on the WM8850 SoCs
> clk: vt8500: Remove unnecessary divisor adjustment in
> vtwm_dclk_set_rate()
>
> Documentation/devicetree/bindings/clock/vt8500.txt | 2 +
> drivers/clk/clk-vt8500.c | 75 ++++++++++++++++++--
> 2 files changed, 73 insertions(+), 4 deletions(-)
>
> --
> 1.7.9.5
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-05-29 21:48 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-13 8:20 [PATCH 0/2] clk: vt8500: updates for 3.11 Tony Prisk
2013-05-13 8:20 ` [PATCH 1/2] clk: vt8500: Add support for clocks on the WM8850 SoCs Tony Prisk
2013-05-13 8:21 ` [PATCH 2/2] clk: vt8500: Remove unnecessary divisor adjustment in vtwm_dclk_set_rate() Tony Prisk
2013-05-29 21:48 ` [PATCH 0/2] clk: vt8500: updates for 3.11 Mike Turquette
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).