Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+102 -20
+1
arch/arm/Kconfig
··· 1173 1173 config ARM_TIMER_SP804 1174 1174 bool 1175 1175 select CLKSRC_MMIO 1176 + select CLKSRC_OF if OF 1176 1177 select HAVE_SCHED_CLOCK 1177 1178 1178 1179 source arch/arm/mm/Kconfig
+89 -16
arch/arm/common/timer-sp.c
··· 25 25 #include <linux/interrupt.h> 26 26 #include <linux/irq.h> 27 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 32 #include <asm/sched_clock.h> 30 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 37 long rate; 36 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 40 err = clk_prepare(clk); 46 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 43 clk_put(clk); 49 44 return err; 50 45 } 51 46 52 47 err = clk_enable(clk); 53 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 50 clk_unprepare(clk); 56 51 clk_put(clk); 57 52 return err; ··· 54 59 55 60 rate = clk_get_rate(clk); 56 61 if (rate < 0) { 57 - pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate); 62 + pr_err("sp804: clock failed to get rate: %ld\n", rate); 58 63 clk_disable(clk); 59 64 clk_unprepare(clk); 60 65 clk_put(clk); ··· 72 77 73 78 void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base, 74 79 const char *name, 80 + struct clk *clk, 75 81 int use_sched_clock) 76 82 { 77 - long rate = sp804_get_clock_rate(name); 83 + long rate; 84 + 85 + if (!clk) { 86 + clk = clk_get_sys("sp804", name); 87 + if (IS_ERR(clk)) { 88 + pr_err("sp804: clock not found: %d\n", 89 + (int)PTR_ERR(clk)); 90 + return; 91 + } 92 + } 93 + 94 + rate = sp804_get_clock_rate(clk); 78 95 79 96 if (rate < 0) 80 97 return; ··· 178 171 .dev_id = &sp804_clockevent, 179 172 }; 180 173 181 - void __init sp804_clockevents_init(void __iomem *base, unsigned int irq, 182 - const char *name) 174 + void __init __sp804_clockevents_init(void __iomem *base, unsigned int irq, struct clk *clk, const char *name) 183 175 { 184 176 struct clock_event_device *evt = &sp804_clockevent; 185 - long rate = sp804_get_clock_rate(name); 177 + long rate; 186 178 179 + if (!clk) 180 + clk = clk_get_sys("sp804", name); 181 + if (IS_ERR(clk)) { 182 + pr_err("sp804: %s clock not found: %d\n", name, 183 + (int)PTR_ERR(clk)); 184 + return; 185 + } 186 + 187 + rate = sp804_get_clock_rate(clk); 187 188 if (rate < 0) 188 189 return; 189 190 ··· 201 186 evt->irq = irq; 202 187 evt->cpumask = cpu_possible_mask; 203 188 189 + writel(0, base + TIMER_CTRL); 190 + 204 191 setup_irq(irq, &sp804_timer_irq); 205 192 clockevents_config_and_register(evt, rate, 0xf, 0xffffffff); 206 193 } 194 + 195 + static void __init sp804_of_init(struct device_node *np) 196 + { 197 + static bool initialized = false; 198 + void __iomem *base; 199 + int irq; 200 + u32 irq_num = 0; 201 + struct clk *clk1, *clk2; 202 + const char *name = of_get_property(np, "compatible", NULL); 203 + 204 + base = of_iomap(np, 0); 205 + if (WARN_ON(!base)) 206 + return; 207 + 208 + /* Ensure timers are disabled */ 209 + writel(0, base + TIMER_CTRL); 210 + writel(0, base + TIMER_2_BASE + TIMER_CTRL); 211 + 212 + if (initialized || !of_device_is_available(np)) 213 + goto err; 214 + 215 + clk1 = of_clk_get(np, 0); 216 + if (IS_ERR(clk1)) 217 + clk1 = NULL; 218 + 219 + /* Get the 2nd clock if the timer has 2 timer clocks */ 220 + if (of_count_phandle_with_args(np, "clocks", "#clock-cells") == 3) { 221 + clk2 = of_clk_get(np, 1); 222 + if (IS_ERR(clk2)) { 223 + pr_err("sp804: %s clock not found: %d\n", np->name, 224 + (int)PTR_ERR(clk2)); 225 + goto err; 226 + } 227 + } else 228 + clk2 = clk1; 229 + 230 + irq = irq_of_parse_and_map(np, 0); 231 + if (irq <= 0) 232 + goto err; 233 + 234 + of_property_read_u32(np, "arm,sp804-has-irq", &irq_num); 235 + if (irq_num == 2) { 236 + __sp804_clockevents_init(base + TIMER_2_BASE, irq, clk2, name); 237 + __sp804_clocksource_and_sched_clock_init(base, name, clk1, 1); 238 + } else { 239 + __sp804_clockevents_init(base, irq, clk1 , name); 240 + __sp804_clocksource_and_sched_clock_init(base + TIMER_2_BASE, 241 + name, clk2, 1); 242 + } 243 + initialized = true; 244 + 245 + return; 246 + err: 247 + iounmap(base); 248 + } 249 + CLOCKSOURCE_OF_DECLARE(sp804, "arm,sp804", sp804_of_init);
+12 -4
arch/arm/include/asm/hardware/timer-sp.h
··· 1 + struct clk; 2 + 1 3 void __sp804_clocksource_and_sched_clock_init(void __iomem *, 2 - const char *, int); 4 + const char *, struct clk *, int); 5 + void __sp804_clockevents_init(void __iomem *, unsigned int, 6 + struct clk *, const char *); 3 7 4 8 static 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 9 13 static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base, 10 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 15 - void sp804_clockevents_init(void __iomem *, unsigned int, const char *); 19 + static 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 + }