diff options
author | Rob Herring <rob.herring@calxeda.com> | 2013-03-25 12:23:52 -0400 |
---|---|---|
committer | Rob Herring <rob.herring@calxeda.com> | 2013-04-11 16:11:17 -0400 |
commit | 7a0eca712118862a2ac25413b7ee24deb27808ea (patch) | |
tree | 9ad5dec4526b8b65077e5e128c16607512b35904 /arch/arm/common | |
parent | d71956960c9dafaafeb19ea010c234abe9d25f10 (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/arm/common')
-rw-r--r-- | arch/arm/common/timer-sp.c | 105 |
1 files changed, 89 insertions, 16 deletions
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 | ||
32 | static long __init sp804_get_clock_rate(const char *name) | 35 | static 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 | ||
78 | void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, | 73 | void __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 | ||
174 | void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, | 181 | void __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 | |||
210 | static 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; | ||
261 | err: | ||
262 | iounmap(base); | ||
263 | } | ||
264 | CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init); | ||