aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/smp_twd.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@linaro.org>2011-12-13 06:47:31 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-12-23 17:54:50 -0500
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 @@
10 */ 10 */
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/clk.h>
13#include <linux/delay.h> 14#include <linux/delay.h>
14#include <linux/device.h> 15#include <linux/device.h>
16#include <linux/err.h>
15#include <linux/smp.h> 17#include <linux/smp.h>
16#include <linux/jiffies.h> 18#include <linux/jiffies.h>
17#include <linux/clockchips.h> 19#include <linux/clockchips.h>
@@ -25,6 +27,7 @@
25/* set up by the platform code */ 27/* set up by the platform code */
26void __iomem *twd_base; 28void __iomem *twd_base;
27 29
30static struct clk *twd_clk;
28static unsigned long twd_timer_rate; 31static unsigned long twd_timer_rate;
29 32
30static struct clock_event_device __percpu **twd_evt; 33static struct clock_event_device __percpu **twd_evt;
@@ -140,6 +143,35 @@ static irqreturn_t twd_handler(int irq, void *dev_id)
140 return IRQ_NONE; 143 return IRQ_NONE;
141} 144}
142 145
146static struct clk *twd_get_clock(void)
147{
148 struct clk *clk;
149 int err;
150
151 clk = clk_get_sys("smp_twd", NULL);
152 if (IS_ERR(clk)) {
153 pr_err("smp_twd: clock not found: %d\n", (int)PTR_ERR(clk));
154 return clk;
155 }
156
157 err = clk_prepare(clk);
158 if (err) {
159 pr_err("smp_twd: clock failed to prepare: %d\n", err);
160 clk_put(clk);
161 return ERR_PTR(err);
162 }
163
164 err = clk_enable(clk);
165 if (err) {
166 pr_err("smp_twd: clock failed to enable: %d\n", err);
167 clk_unprepare(clk);
168 clk_put(clk);
169 return ERR_PTR(err);
170 }
171
172 return clk;
173}
174
143/* 175/*
144 * Setup the local clock events for a CPU. 176 * Setup the local clock events for a CPU.
145 */ 177 */
@@ -165,7 +197,13 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
165 } 197 }
166 } 198 }
167 199
168 twd_calibrate_rate(); 200 if (!twd_clk)
201 twd_clk = twd_get_clock();
202
203 if (!IS_ERR_OR_NULL(twd_clk))
204 twd_timer_rate = clk_get_rate(twd_clk);
205 else
206 twd_calibrate_rate();
169 207
170 clk->name = "local_timer"; 208 clk->name = "local_timer";
171 clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | 209 clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |