ARM: 6145/1: ux500 MTU clockrate correction

This adjusts the clockrate for the MTU timer. On the different
UX500 variants this rate is different. The platform can also have
been set up at hardware initialization, bootloader or early init
for different clock speeds. To have the clock framework available
early so the timers can use them, the clock initialization for
Nomadik and ux500 is moved to IRQ init time. A custom per-clock
callback is added to handle special cases like this.

This solves a user-visible bug: without this patch the current
UX500 platforms will not be synchronized to wall-clock time and
the platform will drift in time.

Acked-by: Rabin Vincent <rabin.vincent@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index 0ff3798..08aaa4a 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -13,7 +13,9 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/clockchips.h>
+#include <linux/clk.h>
 #include <linux/jiffies.h>
+#include <linux/err.h>
 #include <asm/mach/time.h>
 
 #include <plat/mtu.h>
@@ -124,13 +126,25 @@
 void __init nmdk_timer_init(void)
 {
 	unsigned long rate;
-	u32 cr = MTU_CRn_32BITS;;
+	struct clk *clk0;
+	struct clk *clk1;
+	u32 cr;
+
+	clk0 = clk_get_sys("mtu0", NULL);
+	BUG_ON(IS_ERR(clk0));
+
+	clk1 = clk_get_sys("mtu1", NULL);
+	BUG_ON(IS_ERR(clk1));
+
+	clk_enable(clk0);
+	clk_enable(clk1);
 
 	/*
 	 * Tick rate is 2.4MHz for Nomadik and 110MHz for ux500:
 	 * use a divide-by-16 counter if it's more than 16MHz
 	 */
-	rate = CLOCK_TICK_RATE;
+	cr = MTU_CRn_32BITS;;
+	rate = clk_get_rate(clk0);
 	if (rate > 16 << 20) {
 		rate /= 16;
 		cr |= MTU_CRn_PRESCALE_16;
@@ -153,6 +167,14 @@
 		       nmdk_clksrc.name);
 
 	/* Timer 1 is used for events, fix according to rate */
+	cr = MTU_CRn_32BITS;
+	rate = clk_get_rate(clk1);
+	if (rate > 16 << 20) {
+		rate /= 16;
+		cr |= MTU_CRn_PRESCALE_16;
+	} else {
+		cr |= MTU_CRn_PRESCALE_1;
+	}
 	writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */
 	nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
 	nmdk_clkevt.max_delta_ns =