summaryrefslogtreecommitdiff
path: root/arch/arm/kernel/smp_twd.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2011-12-13 12:47:31 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-12-23 22:54:50 +0000
commit5def51b0f827931bb559e6195060d774894fc9f9 (patch)
tree5be35f870a5e18f0a27eb9b35a61ea2b8b171574 /arch/arm/kernel/smp_twd.c
parent54d15b1d7ac550ecd8ab6b04309c2def614f8c80 (diff)
ARM: 7211/1: smp_twd: get the rate from a clock
This break-out from Colin Cross' cpufreq-aware TWD patch will optionally retrieve the clock rate of the TWD from an external clock. A variant of this patch has been proposed by Rob Herring as well. The basic idea is to avoid recalibrating the rate of the clock at boot if the platform already know what rate the clock to the TWD block has. ChangeLog v1->v2: added clk_[prepare|unprepare] calls. [Broke out of larger SMP TWD patch] Signed-off-by: Colin Cross <ccross@android.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Rob Herring <rob.herring@calxeda.com> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel/smp_twd.c')
-rw-r--r--arch/arm/kernel/smp_twd.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index f0575610b17e..a9783947c086 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -10,8 +10,10 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/smp.h>
#include <linux/jiffies.h>
#include <linux/clockchips.h>
@@ -25,6 +27,7 @@
/* set up by the platform code */
void __iomem *twd_base;
+static struct clk *twd_clk;
static unsigned long twd_timer_rate;
static struct clock_event_device __percpu **twd_evt;
@@ -140,6 +143,35 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
return IRQ_NONE;
}
+static struct clk *twd_get_clock(void)
+{
+ struct clk *clk;
+ int err;
+
+ clk = clk_get_sys("smp_twd", NULL);
+ if (IS_ERR(clk)) {
+ pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
+ return clk;
+ }
+
+ err = clk_prepare(clk);
+ if (err) {
+ pr_err("smp_twd: clock failed to prepare: %d\n", err);
+ clk_put(clk);
+ return ERR_PTR(err);
+ }
+
+ err = clk_enable(clk);
+ if (err) {
+ pr_err("smp_twd: clock failed to enable: %d\n", err);
+ clk_unprepare(clk);
+ clk_put(clk);
+ return ERR_PTR(err);
+ }
+
+ return clk;
+}
+
/*
* Setup the local clock events for a CPU.
*/
@@ -165,7 +197,13 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
}
}
- twd_calibrate_rate();
+ if (!twd_clk)
+ twd_clk = twd_get_clock();
+
+ if (!IS_ERR_OR_NULL(twd_clk))
+ twd_timer_rate = clk_get_rate(twd_clk);
+ else
+ twd_calibrate_rate();
clk->name = "local_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |