aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRob Herring <rob.herring@calxeda.com>2013-03-25 12:23:52 -0400
committerRob Herring <rob.herring@calxeda.com>2013-04-11 16:11:17 -0400
commit7a0eca712118862a2ac25413b7ee24deb27808ea (patch)
tree9ad5dec4526b8b65077e5e128c16607512b35904 /arch
parentd71956960c9dafaafeb19ea010c234abe9d25f10 (diff)
ARM: timer-sp: convert to use CLKSRC_OF init
This adds CLKSRC_OF based init for sp804 timer. The clock initialization is refactored to support retrieving the clock(s) from the DT. Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/common/timer-sp.c105
-rw-r--r--arch/arm/include/asm/hardware/timer-sp.h16
3 files changed, 102 insertions, 20 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 5bfd584929c8..10e3053b7d8a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1173,6 +1173,7 @@ config PLAT_VERSATILE
1173config ARM_TIMER_SP804 1173config ARM_TIMER_SP804
1174 bool 1174 bool
1175 select CLKSRC_MMIO 1175 select CLKSRC_MMIO
1176 select CLKSRC_OF if OF
1176 select HAVE_SCHED_CLOCK 1177 select HAVE_SCHED_CLOCK
1177 1178
1178source arch/arm/mm/Kconfig 1179source arch/arm/mm/Kconfig
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index 9d2d3ba339ff..ded926f7c4e8 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -25,33 +25,28 @@
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/irq.h> 26#include <linux/irq.h>
27#include <linux/io.h> 27#include <linux/io.h>
28#include <linux/of.h>
29#include <linux/of_address.h>
30#include <linux/of_irq.h>
28 31
29#include <asm/sched_clock.h> 32#include <asm/sched_clock.h>
30#include <asm/hardware/arm_timer.h> 33#include <asm/hardware/arm_timer.h>
31 34
32static long __init sp804_get_clock_rate(const char *name) 35static long __init sp804_get_clock_rate(struct clk *clk)
33{ 36{
34 struct clk *clk;
35 long rate; 37 long rate;
36 int err; 38 int err;
37 39
38 clk = clk_get_sys("sp804", name);
39 if (IS_ERR(clk)) {
40 pr_err("sp804: %s clock not found: %d\n", name,
41 (int)PTR_ERR(clk));
42 return PTR_ERR(clk);
43 }
44
45 err = clk_prepare(clk); 40 err = clk_prepare(clk);
46 if (err) { 41 if (err) {
47 pr_err("sp804: %s clock failed to prepare: %d\n", name, err); 42 pr_err("sp804: clock failed to prepare: %d\n", err);
48 clk_put(clk); 43 clk_put(clk);
49 return err; 44 return err;
50 } 45 }
51 46
52 err = clk_enable(clk); 47 err = clk_enable(clk);
53 if (err) { 48 if (err) {
54 pr_err("sp804: %s clock failed to enable: %d\n", name, err); 49 pr_err("sp804: clock failed to enable: %d\n", err);
55 clk_unprepare(clk); 50 clk_unprepare(clk);
56 clk_put(clk); 51 clk_put(clk);
57 return err; 52 return err;
@@ -59,7 +54,7 @@ static long __init sp804_get_clock_rate(const char *name)
59 54
60 rate = clk_get_rate(clk); 55 rate = clk_get_rate(clk);
61 if (rate < 0) { 56 if (rate < 0) {
62 pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate); 57 pr_err("sp804: clock failed to get rate: %ld\n", rate);
63 clk_disable(clk); 58 clk_disable(clk);
64 clk_unprepare(clk); 59 clk_unprepare(clk);
65 clk_put(clk); 60 clk_put(clk);
@@ -77,9 +72,21 @@ static u32 sp804_read(void)
77 72
78void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, 73void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
79 const char *name, 74 const char *name,
75 struct clk *clk,
80 int use_sched_clock) 76 int use_sched_clock)
81{ 77{
82 long rate = sp804_get_clock_rate(name); 78 long rate;
79
80 if (!clk) {
81 clk = clk_get_sys("sp804", name);
82 if (IS_ERR(clk)) {
83 pr_err("sp804: clock not found: %d\n",
84 (int)PTR_ERR(clk));
85 return;
86 }
87 }
88
89 rate = sp804_get_clock_rate(clk);
83 90
84 if (rate < 0) 91 if (rate < 0)
85 return; 92 return;
@@ -171,12 +178,20 @@ static struct irqaction sp804_timer_irq = {
171 .dev_id = &sp804_clockevent, 178 .dev_id = &sp804_clockevent,
172}; 179};
173 180
174void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, 181void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name)
175 const char *name)
176{ 182{
177 struct clock_event_device *evt = &sp804_clockevent; 183 struct clock_event_device *evt = &sp804_clockevent;
178 long rate = sp804_get_clock_rate(name); 184 long rate;
185
186 if (!clk)
187 clk = clk_get_sys("sp804", name);
188 if (IS_ERR(clk)) {
189 pr_err("sp804: %s clock not found: %d\n", name,
190 (int)PTR_ERR(clk));
191 return;
192 }
179 193
194 rate = sp804_get_clock_rate(clk);
180 if (rate < 0) 195 if (rate < 0)
181 return; 196 return;
182 197
@@ -186,6 +201,64 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
186 evt->irq = irq; 201 evt->irq = irq;
187 evt->cpumask = cpu_possible_mask; 202 evt->cpumask = cpu_possible_mask;
188 203
204 writel(0, base + TIMER_CTRL);
205
189 setup_irq(irq, &sp804_timer_irq); 206 setup_irq(irq, &sp804_timer_irq);
190 clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); 207 clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
191} 208}
209
210static void __init sp804_of_init(struct device_node *np)
211{
212 static bool initialized = false;
213 void __iomem *base;
214 int irq;
215 u32 irq_num = 0;
216 struct clk *clk1, *clk2;
217 const char *name = of_get_property(np, "compatible", NULL);
218
219 base = of_iomap(np, 0);
220 if (WARN_ON(!base))
221 return;
222
223 /* Ensure timers are disabled */
224 writel(0, base + TIMER_CTRL);
225 writel(0, base + TIMER_2_BASE + TIMER_CTRL);
226
227 if (initialized || !of_device_is_available(np))
228 goto err;
229
230 clk1 = of_clk_get(np, 0);
231 if (IS_ERR(clk1))
232 clk1 = NULL;
233
234 /* Get the 2nd clock if the timer has 2 timer clocks */
235 if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) {
236 clk2 = of_clk_get(np, 1);
237 if (IS_ERR(clk2)) {
238 pr_err("sp804: %s clock not found: %d\n", np->name,
239 (int)PTR_ERR(clk2));
240 goto err;
241 }
242 } else
243 clk2 = clk1;
244
245 irq = irq_of_parse_and_map(np, 0);
246 if (irq <= 0)
247 goto err;
248
249 of_property_read_u32(np, "arm,sp804-has-irq", &irq_num);
250 if (irq_num == 2) {
251 __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name);
252 __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1);
253 } else {
254 __sp804_clockevents_init(base, irq, clk1 , name);
255 __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE,
256 name, clk2, 1);
257 }
258 initialized = true;
259
260 return;
261err:
262 iounmap(base);
263}
264CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h
index 2dd9d3f83f29..bb28af7c32de 100644
--- a/arch/arm/include/asm/hardware/timer-sp.h
+++ b/arch/arm/include/asm/hardware/timer-sp.h
@@ -1,15 +1,23 @@
1struct clk;
2
1void __sp804_clocksource_and_sched_clock_init(void __iomem *, 3void __sp804_clocksource_and_sched_clock_init(void __iomem *,
2 const char *, int); 4 const char *, struct clk *, int);
5void __sp804_clockevents_init(void __iomem *, unsigned int,
6 struct clk *, const char *);
3 7
4static inline void sp804_clocksource_init(void __iomem *base, const char *name) 8static inline void sp804_clocksource_init(void __iomem *base, const char *name)
5{ 9{
6 __sp804_clocksource_and_sched_clock_init(base, name, 0); 10 __sp804_clocksource_and_sched_clock_init(base, name, NULL, 0);
7} 11}
8 12
9static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base, 13static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base,
10 const char *name) 14 const char *name)
11{ 15{
12 __sp804_clocksource_and_sched_clock_init(base, name, 1); 16 __sp804_clocksource_and_sched_clock_init(base, name, NULL, 1);
13} 17}
14 18
15void sp804_clockevents_init(void __iomem *, unsigned int, const char *); 19static inline void sp804_clockevents_init(void __iomem *base, unsigned int irq, const char *name)
20{
21 __sp804_clockevents_init(base, irq, NULL, name);
22
23}