aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2013-05-22 18:10:00 -0400
committerSimon Horman <horms+renesas@verge.net.au>2013-06-07 01:24:52 -0400
commit413bfd0e67894c930242482cd15ac09a800e2ab8 (patch)
treed23c871588e579baaf0e07cdabb63c55ca7caad1
parent3b207a45f909a73b6d7fbdcef49e9287ad7385af (diff)
ARM: shmobile: sh73a0: div4 clocks must check the kick bit before changing rate
According to the datasheet, it is not allowed to change div4 clock rates if an earlier rate change operation is still in progress, as indicated by a set kick bit. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski+renesas@gmail.com> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
-rw-r--r--arch/arm/mach-shmobile/clock-sh73a0.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index d05cf9039788..d9fd0336b910 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -257,7 +257,7 @@ static struct clk twd_clk = {
257 .ops = &twd_clk_ops, 257 .ops = &twd_clk_ops,
258}; 258};
259 259
260static struct sh_clk_ops zclk_ops; 260static struct sh_clk_ops zclk_ops, kicker_ops;
261static const struct sh_clk_ops *div4_clk_ops; 261static const struct sh_clk_ops *div4_clk_ops;
262 262
263static int zclk_set_rate(struct clk *clk, unsigned long rate) 263static int zclk_set_rate(struct clk *clk, unsigned long rate)
@@ -324,18 +324,32 @@ static unsigned long zclk_recalc(struct clk *clk)
324 return clk_get_rate(clk->parent); 324 return clk_get_rate(clk->parent);
325} 325}
326 326
327static void zclk_extend(void) 327static int kicker_set_rate(struct clk *clk, unsigned long rate)
328{ 328{
329 div4_clk_ops = div4_clks[DIV4_Z].ops; 329 if (__raw_readl(FRQCRB) & (1 << 31))
330 return -EBUSY;
331
332 return div4_clk_ops->set_rate(clk, rate);
333}
334
335static void div4_clk_extend(void)
336{
337 int i;
338
339 div4_clk_ops = div4_clks[0].ops;
330 340
341 /* Add a kicker-busy check before changing the rate */
342 kicker_ops = *div4_clk_ops;
331 /* We extend the DIV4 clock with a 1:1 pass-through case */ 343 /* We extend the DIV4 clock with a 1:1 pass-through case */
332 zclk_ops = *div4_clk_ops; 344 zclk_ops = *div4_clk_ops;
333 345
346 kicker_ops.set_rate = kicker_set_rate;
334 zclk_ops.set_rate = zclk_set_rate; 347 zclk_ops.set_rate = zclk_set_rate;
335 zclk_ops.round_rate = zclk_round_rate; 348 zclk_ops.round_rate = zclk_round_rate;
336 zclk_ops.recalc = zclk_recalc; 349 zclk_ops.recalc = zclk_recalc;
337 350
338 div4_clks[DIV4_Z].ops = &zclk_ops; 351 for (i = 0; i < DIV4_NR; i++)
352 div4_clks[i].ops = i == DIV4_Z ? &zclk_ops : &kicker_ops;
339} 353}
340 354
341enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1, 355enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1,
@@ -697,7 +711,7 @@ void __init sh73a0_clock_init(void)
697 if (!ret) { 711 if (!ret) {
698 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); 712 ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
699 if (!ret) 713 if (!ret)
700 zclk_extend(); 714 div4_clk_extend();
701 } 715 }
702 716
703 if (!ret) 717 if (!ret)