diff options
25 files changed, 527 insertions, 486 deletions
diff --git a/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt b/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt new file mode 100644 index 000000000000..993695c659e1 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/cadence,ttc-timer.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | Cadence TTC - Triple Timer Counter | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : Should be "cdns,ttc". | ||
5 | - reg : Specifies base physical address and size of the registers. | ||
6 | - interrupts : A list of 3 interrupts; one per timer channel. | ||
7 | - clocks: phandle to the source clock | ||
8 | |||
9 | Example: | ||
10 | |||
11 | ttc0: ttc0@f8001000 { | ||
12 | interrupt-parent = <&intc>; | ||
13 | interrupts = < 0 10 4 0 11 4 0 12 4 >; | ||
14 | compatible = "cdns,ttc"; | ||
15 | reg = <0xF8001000 0x1000>; | ||
16 | clocks = <&cpu_clk 3>; | ||
17 | }; | ||
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c6a82c74fcbb..eb91022b90ba 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1598,6 +1598,7 @@ config HAVE_ARM_ARCH_TIMER | |||
1598 | config HAVE_ARM_TWD | 1598 | config HAVE_ARM_TWD |
1599 | bool | 1599 | bool |
1600 | depends on SMP | 1600 | depends on SMP |
1601 | select CLKSRC_OF if OF | ||
1601 | help | 1602 | help |
1602 | This options enables support for the ARM timer and watchdog unit | 1603 | This options enables support for the ARM timer and watchdog unit |
1603 | 1604 | ||
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi index 5914b5654591..51243db2e9e4 100644 --- a/arch/arm/boot/dts/zynq-7000.dtsi +++ b/arch/arm/boot/dts/zynq-7000.dtsi | |||
@@ -111,56 +111,23 @@ | |||
111 | }; | 111 | }; |
112 | 112 | ||
113 | ttc0: ttc0@f8001000 { | 113 | ttc0: ttc0@f8001000 { |
114 | #address-cells = <1>; | 114 | interrupt-parent = <&intc>; |
115 | #size-cells = <0>; | 115 | interrupts = < 0 10 4 0 11 4 0 12 4 >; |
116 | compatible = "xlnx,ttc"; | 116 | compatible = "cdns,ttc"; |
117 | reg = <0xF8001000 0x1000>; | 117 | reg = <0xF8001000 0x1000>; |
118 | clocks = <&cpu_clk 3>; | 118 | clocks = <&cpu_clk 3>; |
119 | clock-names = "cpu_1x"; | 119 | clock-names = "cpu_1x"; |
120 | clock-ranges; | 120 | clock-ranges; |
121 | |||
122 | ttc0_0: ttc0.0 { | ||
123 | status = "disabled"; | ||
124 | reg = <0>; | ||
125 | interrupts = <0 10 4>; | ||
126 | }; | ||
127 | ttc0_1: ttc0.1 { | ||
128 | status = "disabled"; | ||
129 | reg = <1>; | ||
130 | interrupts = <0 11 4>; | ||
131 | }; | ||
132 | ttc0_2: ttc0.2 { | ||
133 | status = "disabled"; | ||
134 | reg = <2>; | ||
135 | interrupts = <0 12 4>; | ||
136 | }; | ||
137 | }; | 121 | }; |
138 | 122 | ||
139 | ttc1: ttc1@f8002000 { | 123 | ttc1: ttc1@f8002000 { |
140 | #interrupt-parent = <&intc>; | 124 | interrupt-parent = <&intc>; |
141 | #address-cells = <1>; | 125 | interrupts = < 0 37 4 0 38 4 0 39 4 >; |
142 | #size-cells = <0>; | 126 | compatible = "cdns,ttc"; |
143 | compatible = "xlnx,ttc"; | ||
144 | reg = <0xF8002000 0x1000>; | 127 | reg = <0xF8002000 0x1000>; |
145 | clocks = <&cpu_clk 3>; | 128 | clocks = <&cpu_clk 3>; |
146 | clock-names = "cpu_1x"; | 129 | clock-names = "cpu_1x"; |
147 | clock-ranges; | 130 | clock-ranges; |
148 | |||
149 | ttc1_0: ttc1.0 { | ||
150 | status = "disabled"; | ||
151 | reg = <0>; | ||
152 | interrupts = <0 37 4>; | ||
153 | }; | ||
154 | ttc1_1: ttc1.1 { | ||
155 | status = "disabled"; | ||
156 | reg = <1>; | ||
157 | interrupts = <0 38 4>; | ||
158 | }; | ||
159 | ttc1_2: ttc1.2 { | ||
160 | status = "disabled"; | ||
161 | reg = <2>; | ||
162 | interrupts = <0 39 4>; | ||
163 | }; | ||
164 | }; | 131 | }; |
165 | }; | 132 | }; |
166 | }; | 133 | }; |
diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts index c772942a399a..86f44d5b0265 100644 --- a/arch/arm/boot/dts/zynq-zc702.dts +++ b/arch/arm/boot/dts/zynq-zc702.dts | |||
@@ -32,13 +32,3 @@ | |||
32 | &ps_clk { | 32 | &ps_clk { |
33 | clock-frequency = <33333330>; | 33 | clock-frequency = <33333330>; |
34 | }; | 34 | }; |
35 | |||
36 | &ttc0_0 { | ||
37 | status = "ok"; | ||
38 | compatible = "xlnx,ttc-counter-clocksource"; | ||
39 | }; | ||
40 | |||
41 | &ttc0_1 { | ||
42 | status = "ok"; | ||
43 | compatible = "xlnx,ttc-counter-clockevent"; | ||
44 | }; | ||
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h index 0f01f4677bd2..7b2899c2f7fc 100644 --- a/arch/arm/include/asm/smp_twd.h +++ b/arch/arm/include/asm/smp_twd.h | |||
@@ -34,12 +34,4 @@ struct twd_local_timer name __initdata = { \ | |||
34 | 34 | ||
35 | int twd_local_timer_register(struct twd_local_timer *); | 35 | int twd_local_timer_register(struct twd_local_timer *); |
36 | 36 | ||
37 | #ifdef CONFIG_HAVE_ARM_TWD | ||
38 | void twd_local_timer_of_register(void); | ||
39 | #else | ||
40 | static inline void twd_local_timer_of_register(void) | ||
41 | { | ||
42 | } | ||
43 | #endif | ||
44 | |||
45 | #endif | 37 | #endif |
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 3f2565037480..90525d9d290b 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c | |||
@@ -362,25 +362,13 @@ int __init twd_local_timer_register(struct twd_local_timer *tlt) | |||
362 | } | 362 | } |
363 | 363 | ||
364 | #ifdef CONFIG_OF | 364 | #ifdef CONFIG_OF |
365 | const static struct of_device_id twd_of_match[] __initconst = { | 365 | static void __init twd_local_timer_of_register(struct device_node *np) |
366 | { .compatible = "arm,cortex-a9-twd-timer", }, | ||
367 | { .compatible = "arm,cortex-a5-twd-timer", }, | ||
368 | { .compatible = "arm,arm11mp-twd-timer", }, | ||
369 | { }, | ||
370 | }; | ||
371 | |||
372 | void __init twd_local_timer_of_register(void) | ||
373 | { | 366 | { |
374 | struct device_node *np; | ||
375 | int err; | 367 | int err; |
376 | 368 | ||
377 | if (!is_smp() || !setup_max_cpus) | 369 | if (!is_smp() || !setup_max_cpus) |
378 | return; | 370 | return; |
379 | 371 | ||
380 | np = of_find_matching_node(NULL, twd_of_match); | ||
381 | if (!np) | ||
382 | return; | ||
383 | |||
384 | twd_ppi = irq_of_parse_and_map(np, 0); | 372 | twd_ppi = irq_of_parse_and_map(np, 0); |
385 | if (!twd_ppi) { | 373 | if (!twd_ppi) { |
386 | err = -EINVAL; | 374 | err = -EINVAL; |
@@ -398,4 +386,7 @@ void __init twd_local_timer_of_register(void) | |||
398 | out: | 386 | out: |
399 | WARN(err, "twd_local_timer_of_register failed (%d)\n", err); | 387 | WARN(err, "twd_local_timer_of_register failed (%d)\n", err); |
400 | } | 388 | } |
389 | CLOCKSOURCE_OF_DECLARE(arm_twd_a9, "arm,cortex-a9-twd-timer", twd_local_timer_of_register); | ||
390 | CLOCKSOURCE_OF_DECLARE(arm_twd_a5, "arm,cortex-a5-twd-timer", twd_local_timer_of_register); | ||
391 | CLOCKSOURCE_OF_DECLARE(arm_twd_11mp, "arm,arm11mp-twd-timer", twd_local_timer_of_register); | ||
401 | #endif | 392 | #endif |
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index a4f9f50247d4..76c1170b3528 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
33 | #include <asm/cputype.h> | 33 | #include <asm/cputype.h> |
34 | #include <asm/smp_plat.h> | 34 | #include <asm/smp_plat.h> |
35 | #include <asm/smp_twd.h> | ||
36 | #include <asm/hardware/arm_timer.h> | 35 | #include <asm/hardware/arm_timer.h> |
37 | #include <asm/hardware/timer-sp.h> | 36 | #include <asm/hardware/timer-sp.h> |
38 | #include <asm/hardware/cache-l2x0.h> | 37 | #include <asm/hardware/cache-l2x0.h> |
@@ -119,10 +118,10 @@ static void __init highbank_timer_init(void) | |||
119 | sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); | 118 | sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); |
120 | sp804_clockevents_init(timer_base, irq, "timer0"); | 119 | sp804_clockevents_init(timer_base, irq, "timer0"); |
121 | 120 | ||
122 | twd_local_timer_of_register(); | ||
123 | |||
124 | arch_timer_of_register(); | 121 | arch_timer_of_register(); |
125 | arch_timer_sched_clock_init(); | 122 | arch_timer_sched_clock_init(); |
123 | |||
124 | clocksource_of_init(); | ||
126 | } | 125 | } |
127 | 126 | ||
128 | static void highbank_power_off(void) | 127 | static void highbank_power_off(void) |
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 9ffd103b27e4..b59ddcb57c78 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c | |||
@@ -12,6 +12,7 @@ | |||
12 | 12 | ||
13 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
14 | #include <linux/clkdev.h> | 14 | #include <linux/clkdev.h> |
15 | #include <linux/clocksource.h> | ||
15 | #include <linux/cpu.h> | 16 | #include <linux/cpu.h> |
16 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
17 | #include <linux/export.h> | 18 | #include <linux/export.h> |
@@ -28,11 +29,9 @@ | |||
28 | #include <linux/regmap.h> | 29 | #include <linux/regmap.h> |
29 | #include <linux/micrel_phy.h> | 30 | #include <linux/micrel_phy.h> |
30 | #include <linux/mfd/syscon.h> | 31 | #include <linux/mfd/syscon.h> |
31 | #include <asm/smp_twd.h> | ||
32 | #include <asm/hardware/cache-l2x0.h> | 32 | #include <asm/hardware/cache-l2x0.h> |
33 | #include <asm/mach/arch.h> | 33 | #include <asm/mach/arch.h> |
34 | #include <asm/mach/map.h> | 34 | #include <asm/mach/map.h> |
35 | #include <asm/mach/time.h> | ||
36 | #include <asm/system_misc.h> | 35 | #include <asm/system_misc.h> |
37 | 36 | ||
38 | #include "common.h" | 37 | #include "common.h" |
@@ -292,7 +291,7 @@ static void __init imx6q_init_irq(void) | |||
292 | static void __init imx6q_timer_init(void) | 291 | static void __init imx6q_timer_init(void) |
293 | { | 292 | { |
294 | mx6q_clocks_init(); | 293 | mx6q_clocks_init(); |
295 | twd_local_timer_of_register(); | 294 | clocksource_of_init(); |
296 | imx_print_silicon_rev("i.MX6Q", imx6q_revision()); | 295 | imx_print_silicon_rev("i.MX6Q", imx6q_revision()); |
297 | } | 296 | } |
298 | 297 | ||
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 2bdd4cf17a8f..4fd80257c73e 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -597,7 +597,7 @@ void __init omap4_local_timer_init(void) | |||
597 | int err; | 597 | int err; |
598 | 598 | ||
599 | if (of_have_populated_dt()) { | 599 | if (of_have_populated_dt()) { |
600 | twd_local_timer_of_register(); | 600 | clocksource_of_init(); |
601 | return; | 601 | return; |
602 | } | 602 | } |
603 | 603 | ||
diff --git a/arch/arm/mach-spear13xx/spear13xx.c b/arch/arm/mach-spear13xx/spear13xx.c index c7d2b4a8d8cc..25a10191b021 100644 --- a/arch/arm/mach-spear13xx/spear13xx.c +++ b/arch/arm/mach-spear13xx/spear13xx.c | |||
@@ -15,12 +15,12 @@ | |||
15 | 15 | ||
16 | #include <linux/amba/pl022.h> | 16 | #include <linux/amba/pl022.h> |
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/clocksource.h> | ||
18 | #include <linux/dw_dmac.h> | 19 | #include <linux/dw_dmac.h> |
19 | #include <linux/err.h> | 20 | #include <linux/err.h> |
20 | #include <linux/of.h> | 21 | #include <linux/of.h> |
21 | #include <asm/hardware/cache-l2x0.h> | 22 | #include <asm/hardware/cache-l2x0.h> |
22 | #include <asm/mach/map.h> | 23 | #include <asm/mach/map.h> |
23 | #include <asm/smp_twd.h> | ||
24 | #include <mach/dma.h> | 24 | #include <mach/dma.h> |
25 | #include <mach/generic.h> | 25 | #include <mach/generic.h> |
26 | #include <mach/spear.h> | 26 | #include <mach/spear.h> |
@@ -179,5 +179,5 @@ void __init spear13xx_timer_init(void) | |||
179 | clk_put(pclk); | 179 | clk_put(pclk); |
180 | 180 | ||
181 | spear_setup_of_timer(); | 181 | spear_setup_of_timer(); |
182 | twd_local_timer_of_register(); | 182 | clocksource_of_init(); |
183 | } | 183 | } |
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c index a6af0b8732ba..d07bbe7f04a6 100644 --- a/arch/arm/mach-ux500/timer.c +++ b/arch/arm/mach-ux500/timer.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/io.h> | 7 | #include <linux/io.h> |
8 | #include <linux/errno.h> | 8 | #include <linux/errno.h> |
9 | #include <linux/clksrc-dbx500-prcmu.h> | 9 | #include <linux/clksrc-dbx500-prcmu.h> |
10 | #include <linux/clocksource.h> | ||
10 | #include <linux/of.h> | 11 | #include <linux/of.h> |
11 | #include <linux/of_address.h> | 12 | #include <linux/of_address.h> |
12 | #include <linux/platform_data/clocksource-nomadik-mtu.h> | 13 | #include <linux/platform_data/clocksource-nomadik-mtu.h> |
@@ -32,7 +33,7 @@ static void __init ux500_twd_init(void) | |||
32 | twd_local_timer = &u8500_twd_local_timer; | 33 | twd_local_timer = &u8500_twd_local_timer; |
33 | 34 | ||
34 | if (of_have_populated_dt()) | 35 | if (of_have_populated_dt()) |
35 | twd_local_timer_of_register(); | 36 | clocksource_of_init(); |
36 | else { | 37 | else { |
37 | err = twd_local_timer_register(twd_local_timer); | 38 | err = twd_local_timer_register(twd_local_timer); |
38 | if (err) | 39 | if (err) |
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c index 915683cb67d6..d0ad78998cb6 100644 --- a/arch/arm/mach-vexpress/v2m.c +++ b/arch/arm/mach-vexpress/v2m.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/amba/bus.h> | 5 | #include <linux/amba/bus.h> |
6 | #include <linux/amba/mmci.h> | 6 | #include <linux/amba/mmci.h> |
7 | #include <linux/io.h> | 7 | #include <linux/io.h> |
8 | #include <linux/clocksource.h> | ||
8 | #include <linux/smp.h> | 9 | #include <linux/smp.h> |
9 | #include <linux/init.h> | 10 | #include <linux/init.h> |
10 | #include <linux/irqchip.h> | 11 | #include <linux/irqchip.h> |
@@ -25,7 +26,6 @@ | |||
25 | #include <asm/arch_timer.h> | 26 | #include <asm/arch_timer.h> |
26 | #include <asm/mach-types.h> | 27 | #include <asm/mach-types.h> |
27 | #include <asm/sizes.h> | 28 | #include <asm/sizes.h> |
28 | #include <asm/smp_twd.h> | ||
29 | #include <asm/mach/arch.h> | 29 | #include <asm/mach/arch.h> |
30 | #include <asm/mach/map.h> | 30 | #include <asm/mach/map.h> |
31 | #include <asm/mach/time.h> | 31 | #include <asm/mach/time.h> |
@@ -435,6 +435,7 @@ static void __init v2m_dt_timer_init(void) | |||
435 | 435 | ||
436 | vexpress_clk_of_init(); | 436 | vexpress_clk_of_init(); |
437 | 437 | ||
438 | clocksource_of_init(); | ||
438 | do { | 439 | do { |
439 | node = of_find_compatible_node(node, NULL, "arm,sp804"); | 440 | node = of_find_compatible_node(node, NULL, "arm,sp804"); |
440 | } while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB); | 441 | } while (node && vexpress_get_site_by_node(node) != VEXPRESS_SITE_MB); |
@@ -445,8 +446,7 @@ static void __init v2m_dt_timer_init(void) | |||
445 | irq_of_parse_and_map(node, 0)); | 446 | irq_of_parse_and_map(node, 0)); |
446 | } | 447 | } |
447 | 448 | ||
448 | if (arch_timer_of_register() != 0) | 449 | arch_timer_of_register(); |
449 | twd_local_timer_of_register(); | ||
450 | 450 | ||
451 | if (arch_timer_sched_clock_init() != 0) | 451 | if (arch_timer_sched_clock_init() != 0) |
452 | versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), | 452 | versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), |
diff --git a/arch/arm/mach-zynq/Kconfig b/arch/arm/mach-zynq/Kconfig index adb6c0ea0e53..d70651e8b705 100644 --- a/arch/arm/mach-zynq/Kconfig +++ b/arch/arm/mach-zynq/Kconfig | |||
@@ -9,5 +9,6 @@ config ARCH_ZYNQ | |||
9 | select MIGHT_HAVE_CACHE_L2X0 | 9 | select MIGHT_HAVE_CACHE_L2X0 |
10 | select USE_OF | 10 | select USE_OF |
11 | select SPARSE_IRQ | 11 | select SPARSE_IRQ |
12 | select CADENCE_TTC_TIMER | ||
12 | help | 13 | help |
13 | Support for Xilinx Zynq ARM Cortex A9 Platform | 14 | Support for Xilinx Zynq ARM Cortex A9 Platform |
diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile index 397268c1b250..320faedeb484 100644 --- a/arch/arm/mach-zynq/Makefile +++ b/arch/arm/mach-zynq/Makefile | |||
@@ -3,4 +3,4 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support | 5 | # Common support |
6 | obj-y := common.o timer.o | 6 | obj-y := common.o |
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 5c8983218183..68e0907de5d0 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/clk.h> | 21 | #include <linux/clk.h> |
22 | #include <linux/clk/zynq.h> | 22 | #include <linux/clk/zynq.h> |
23 | #include <linux/clocksource.h> | ||
23 | #include <linux/of_address.h> | 24 | #include <linux/of_address.h> |
24 | #include <linux/of_irq.h> | 25 | #include <linux/of_irq.h> |
25 | #include <linux/of_platform.h> | 26 | #include <linux/of_platform.h> |
@@ -77,7 +78,7 @@ static void __init xilinx_zynq_timer_init(void) | |||
77 | 78 | ||
78 | xilinx_zynq_clocks_init(slcr); | 79 | xilinx_zynq_clocks_init(slcr); |
79 | 80 | ||
80 | xttcps_timer_init(); | 81 | clocksource_of_init(); |
81 | } | 82 | } |
82 | 83 | ||
83 | /** | 84 | /** |
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h index 8b4dbbaa01cf..5050bb10bb12 100644 --- a/arch/arm/mach-zynq/common.h +++ b/arch/arm/mach-zynq/common.h | |||
@@ -17,6 +17,4 @@ | |||
17 | #ifndef __MACH_ZYNQ_COMMON_H__ | 17 | #ifndef __MACH_ZYNQ_COMMON_H__ |
18 | #define __MACH_ZYNQ_COMMON_H__ | 18 | #define __MACH_ZYNQ_COMMON_H__ |
19 | 19 | ||
20 | void __init xttcps_timer_init(void); | ||
21 | |||
22 | #endif | 20 | #endif |
diff --git a/arch/arm/mach-zynq/timer.c b/arch/arm/mach-zynq/timer.c deleted file mode 100644 index f9fbc9c1e7a6..000000000000 --- a/arch/arm/mach-zynq/timer.c +++ /dev/null | |||
@@ -1,324 +0,0 @@ | |||
1 | /* | ||
2 | * This file contains driver for the Xilinx PS Timer Counter IP. | ||
3 | * | ||
4 | * Copyright (C) 2011 Xilinx | ||
5 | * | ||
6 | * based on arch/mips/kernel/time.c timer driver | ||
7 | * | ||
8 | * This software is licensed under the terms of the GNU General Public | ||
9 | * License version 2, as published by the Free Software Foundation, and | ||
10 | * may be copied, distributed, and modified under those terms. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/clockchips.h> | ||
20 | #include <linux/of_address.h> | ||
21 | #include <linux/of_irq.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/clk-provider.h> | ||
24 | #include "common.h" | ||
25 | |||
26 | /* | ||
27 | * Timer Register Offset Definitions of Timer 1, Increment base address by 4 | ||
28 | * and use same offsets for Timer 2 | ||
29 | */ | ||
30 | #define XTTCPS_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */ | ||
31 | #define XTTCPS_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */ | ||
32 | #define XTTCPS_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */ | ||
33 | #define XTTCPS_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */ | ||
34 | #define XTTCPS_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ | ||
35 | #define XTTCPS_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ | ||
36 | |||
37 | #define XTTCPS_CNT_CNTRL_DISABLE_MASK 0x1 | ||
38 | |||
39 | /* | ||
40 | * Setup the timers to use pre-scaling, using a fixed value for now that will | ||
41 | * work across most input frequency, but it may need to be more dynamic | ||
42 | */ | ||
43 | #define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */ | ||
44 | #define PRESCALE 2048 /* The exponent must match this */ | ||
45 | #define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1) | ||
46 | #define CLK_CNTRL_PRESCALE_EN 1 | ||
47 | #define CNT_CNTRL_RESET (1<<4) | ||
48 | |||
49 | /** | ||
50 | * struct xttcps_timer - This definition defines local timer structure | ||
51 | * | ||
52 | * @base_addr: Base address of timer | ||
53 | **/ | ||
54 | struct xttcps_timer { | ||
55 | void __iomem *base_addr; | ||
56 | }; | ||
57 | |||
58 | struct xttcps_timer_clocksource { | ||
59 | struct xttcps_timer xttc; | ||
60 | struct clocksource cs; | ||
61 | }; | ||
62 | |||
63 | #define to_xttcps_timer_clksrc(x) \ | ||
64 | container_of(x, struct xttcps_timer_clocksource, cs) | ||
65 | |||
66 | struct xttcps_timer_clockevent { | ||
67 | struct xttcps_timer xttc; | ||
68 | struct clock_event_device ce; | ||
69 | struct clk *clk; | ||
70 | }; | ||
71 | |||
72 | #define to_xttcps_timer_clkevent(x) \ | ||
73 | container_of(x, struct xttcps_timer_clockevent, ce) | ||
74 | |||
75 | /** | ||
76 | * xttcps_set_interval - Set the timer interval value | ||
77 | * | ||
78 | * @timer: Pointer to the timer instance | ||
79 | * @cycles: Timer interval ticks | ||
80 | **/ | ||
81 | static void xttcps_set_interval(struct xttcps_timer *timer, | ||
82 | unsigned long cycles) | ||
83 | { | ||
84 | u32 ctrl_reg; | ||
85 | |||
86 | /* Disable the counter, set the counter value and re-enable counter */ | ||
87 | ctrl_reg = __raw_readl(timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); | ||
88 | ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK; | ||
89 | __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); | ||
90 | |||
91 | __raw_writel(cycles, timer->base_addr + XTTCPS_INTR_VAL_OFFSET); | ||
92 | |||
93 | /* | ||
94 | * Reset the counter (0x10) so that it starts from 0, one-shot | ||
95 | * mode makes this needed for timing to be right. | ||
96 | */ | ||
97 | ctrl_reg |= CNT_CNTRL_RESET; | ||
98 | ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK; | ||
99 | __raw_writel(ctrl_reg, timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * xttcps_clock_event_interrupt - Clock event timer interrupt handler | ||
104 | * | ||
105 | * @irq: IRQ number of the Timer | ||
106 | * @dev_id: void pointer to the xttcps_timer instance | ||
107 | * | ||
108 | * returns: Always IRQ_HANDLED - success | ||
109 | **/ | ||
110 | static irqreturn_t xttcps_clock_event_interrupt(int irq, void *dev_id) | ||
111 | { | ||
112 | struct xttcps_timer_clockevent *xttce = dev_id; | ||
113 | struct xttcps_timer *timer = &xttce->xttc; | ||
114 | |||
115 | /* Acknowledge the interrupt and call event handler */ | ||
116 | __raw_readl(timer->base_addr + XTTCPS_ISR_OFFSET); | ||
117 | |||
118 | xttce->ce.event_handler(&xttce->ce); | ||
119 | |||
120 | return IRQ_HANDLED; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * __xttc_clocksource_read - Reads the timer counter register | ||
125 | * | ||
126 | * returns: Current timer counter register value | ||
127 | **/ | ||
128 | static cycle_t __xttc_clocksource_read(struct clocksource *cs) | ||
129 | { | ||
130 | struct xttcps_timer *timer = &to_xttcps_timer_clksrc(cs)->xttc; | ||
131 | |||
132 | return (cycle_t)__raw_readl(timer->base_addr + | ||
133 | XTTCPS_COUNT_VAL_OFFSET); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * xttcps_set_next_event - Sets the time interval for next event | ||
138 | * | ||
139 | * @cycles: Timer interval ticks | ||
140 | * @evt: Address of clock event instance | ||
141 | * | ||
142 | * returns: Always 0 - success | ||
143 | **/ | ||
144 | static int xttcps_set_next_event(unsigned long cycles, | ||
145 | struct clock_event_device *evt) | ||
146 | { | ||
147 | struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt); | ||
148 | struct xttcps_timer *timer = &xttce->xttc; | ||
149 | |||
150 | xttcps_set_interval(timer, cycles); | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * xttcps_set_mode - Sets the mode of timer | ||
156 | * | ||
157 | * @mode: Mode to be set | ||
158 | * @evt: Address of clock event instance | ||
159 | **/ | ||
160 | static void xttcps_set_mode(enum clock_event_mode mode, | ||
161 | struct clock_event_device *evt) | ||
162 | { | ||
163 | struct xttcps_timer_clockevent *xttce = to_xttcps_timer_clkevent(evt); | ||
164 | struct xttcps_timer *timer = &xttce->xttc; | ||
165 | u32 ctrl_reg; | ||
166 | |||
167 | switch (mode) { | ||
168 | case CLOCK_EVT_MODE_PERIODIC: | ||
169 | xttcps_set_interval(timer, | ||
170 | DIV_ROUND_CLOSEST(clk_get_rate(xttce->clk), | ||
171 | PRESCALE * HZ)); | ||
172 | break; | ||
173 | case CLOCK_EVT_MODE_ONESHOT: | ||
174 | case CLOCK_EVT_MODE_UNUSED: | ||
175 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
176 | ctrl_reg = __raw_readl(timer->base_addr + | ||
177 | XTTCPS_CNT_CNTRL_OFFSET); | ||
178 | ctrl_reg |= XTTCPS_CNT_CNTRL_DISABLE_MASK; | ||
179 | __raw_writel(ctrl_reg, | ||
180 | timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); | ||
181 | break; | ||
182 | case CLOCK_EVT_MODE_RESUME: | ||
183 | ctrl_reg = __raw_readl(timer->base_addr + | ||
184 | XTTCPS_CNT_CNTRL_OFFSET); | ||
185 | ctrl_reg &= ~XTTCPS_CNT_CNTRL_DISABLE_MASK; | ||
186 | __raw_writel(ctrl_reg, | ||
187 | timer->base_addr + XTTCPS_CNT_CNTRL_OFFSET); | ||
188 | break; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static void __init zynq_ttc_setup_clocksource(struct device_node *np, | ||
193 | void __iomem *base) | ||
194 | { | ||
195 | struct xttcps_timer_clocksource *ttccs; | ||
196 | struct clk *clk; | ||
197 | int err; | ||
198 | u32 reg; | ||
199 | |||
200 | ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); | ||
201 | if (WARN_ON(!ttccs)) | ||
202 | return; | ||
203 | |||
204 | err = of_property_read_u32(np, "reg", ®); | ||
205 | if (WARN_ON(err)) | ||
206 | return; | ||
207 | |||
208 | clk = of_clk_get_by_name(np, "cpu_1x"); | ||
209 | if (WARN_ON(IS_ERR(clk))) | ||
210 | return; | ||
211 | |||
212 | err = clk_prepare_enable(clk); | ||
213 | if (WARN_ON(err)) | ||
214 | return; | ||
215 | |||
216 | ttccs->xttc.base_addr = base + reg * 4; | ||
217 | |||
218 | ttccs->cs.name = np->name; | ||
219 | ttccs->cs.rating = 200; | ||
220 | ttccs->cs.read = __xttc_clocksource_read; | ||
221 | ttccs->cs.mask = CLOCKSOURCE_MASK(16); | ||
222 | ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
223 | |||
224 | __raw_writel(0x0, ttccs->xttc.base_addr + XTTCPS_IER_OFFSET); | ||
225 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
226 | ttccs->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET); | ||
227 | __raw_writel(CNT_CNTRL_RESET, | ||
228 | ttccs->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET); | ||
229 | |||
230 | err = clocksource_register_hz(&ttccs->cs, clk_get_rate(clk) / PRESCALE); | ||
231 | if (WARN_ON(err)) | ||
232 | return; | ||
233 | } | ||
234 | |||
235 | static void __init zynq_ttc_setup_clockevent(struct device_node *np, | ||
236 | void __iomem *base) | ||
237 | { | ||
238 | struct xttcps_timer_clockevent *ttcce; | ||
239 | int err, irq; | ||
240 | u32 reg; | ||
241 | |||
242 | ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); | ||
243 | if (WARN_ON(!ttcce)) | ||
244 | return; | ||
245 | |||
246 | err = of_property_read_u32(np, "reg", ®); | ||
247 | if (WARN_ON(err)) | ||
248 | return; | ||
249 | |||
250 | ttcce->xttc.base_addr = base + reg * 4; | ||
251 | |||
252 | ttcce->clk = of_clk_get_by_name(np, "cpu_1x"); | ||
253 | if (WARN_ON(IS_ERR(ttcce->clk))) | ||
254 | return; | ||
255 | |||
256 | err = clk_prepare_enable(ttcce->clk); | ||
257 | if (WARN_ON(err)) | ||
258 | return; | ||
259 | |||
260 | irq = irq_of_parse_and_map(np, 0); | ||
261 | if (WARN_ON(!irq)) | ||
262 | return; | ||
263 | |||
264 | ttcce->ce.name = np->name; | ||
265 | ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
266 | ttcce->ce.set_next_event = xttcps_set_next_event; | ||
267 | ttcce->ce.set_mode = xttcps_set_mode; | ||
268 | ttcce->ce.rating = 200; | ||
269 | ttcce->ce.irq = irq; | ||
270 | ttcce->ce.cpumask = cpu_possible_mask; | ||
271 | |||
272 | __raw_writel(0x23, ttcce->xttc.base_addr + XTTCPS_CNT_CNTRL_OFFSET); | ||
273 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
274 | ttcce->xttc.base_addr + XTTCPS_CLK_CNTRL_OFFSET); | ||
275 | __raw_writel(0x1, ttcce->xttc.base_addr + XTTCPS_IER_OFFSET); | ||
276 | |||
277 | err = request_irq(irq, xttcps_clock_event_interrupt, IRQF_TIMER, | ||
278 | np->name, ttcce); | ||
279 | if (WARN_ON(err)) | ||
280 | return; | ||
281 | |||
282 | clockevents_config_and_register(&ttcce->ce, | ||
283 | clk_get_rate(ttcce->clk) / PRESCALE, | ||
284 | 1, 0xfffe); | ||
285 | } | ||
286 | |||
287 | static const __initconst struct of_device_id zynq_ttc_match[] = { | ||
288 | { .compatible = "xlnx,ttc-counter-clocksource", | ||
289 | .data = zynq_ttc_setup_clocksource, }, | ||
290 | { .compatible = "xlnx,ttc-counter-clockevent", | ||
291 | .data = zynq_ttc_setup_clockevent, }, | ||
292 | {} | ||
293 | }; | ||
294 | |||
295 | /** | ||
296 | * xttcps_timer_init - Initialize the timer | ||
297 | * | ||
298 | * Initializes the timer hardware and register the clock source and clock event | ||
299 | * timers with Linux kernal timer framework | ||
300 | **/ | ||
301 | void __init xttcps_timer_init(void) | ||
302 | { | ||
303 | struct device_node *np; | ||
304 | |||
305 | for_each_compatible_node(np, NULL, "xlnx,ttc") { | ||
306 | struct device_node *np_chld; | ||
307 | void __iomem *base; | ||
308 | |||
309 | base = of_iomap(np, 0); | ||
310 | if (WARN_ON(!base)) | ||
311 | return; | ||
312 | |||
313 | for_each_available_child_of_node(np, np_chld) { | ||
314 | int (*cb)(struct device_node *np, void __iomem *base); | ||
315 | const struct of_device_id *match; | ||
316 | |||
317 | match = of_match_node(zynq_ttc_match, np_chld); | ||
318 | if (match) { | ||
319 | cb = match->data; | ||
320 | cb(np_chld, base); | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | } | ||
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e507ab7df60b..3167fda9bbb3 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -31,6 +31,9 @@ config SUNXI_TIMER | |||
31 | config VT8500_TIMER | 31 | config VT8500_TIMER |
32 | bool | 32 | bool |
33 | 33 | ||
34 | config CADENCE_TTC_TIMER | ||
35 | bool | ||
36 | |||
34 | config CLKSRC_NOMADIK_MTU | 37 | config CLKSRC_NOMADIK_MTU |
35 | bool | 38 | bool |
36 | depends on (ARCH_NOMADIK || ARCH_U8500) | 39 | depends on (ARCH_NOMADIK || ARCH_U8500) |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 4d8283aec5b5..e74c8ce26bf0 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o | |||
19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o | 19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o |
20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o | 20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o |
21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o | 21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o |
22 | obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o | ||
22 | 23 | ||
23 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o | 24 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
24 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | 25 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o |
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 50c68fef944b..766611d29945 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c | |||
@@ -95,23 +95,13 @@ static irqreturn_t bcm2835_time_interrupt(int irq, void *dev_id) | |||
95 | } | 95 | } |
96 | } | 96 | } |
97 | 97 | ||
98 | static struct of_device_id bcm2835_time_match[] __initconst = { | 98 | static void __init bcm2835_timer_init(struct device_node *node) |
99 | { .compatible = "brcm,bcm2835-system-timer" }, | ||
100 | {} | ||
101 | }; | ||
102 | |||
103 | static void __init bcm2835_timer_init(void) | ||
104 | { | 99 | { |
105 | struct device_node *node; | ||
106 | void __iomem *base; | 100 | void __iomem *base; |
107 | u32 freq; | 101 | u32 freq; |
108 | int irq; | 102 | int irq; |
109 | struct bcm2835_timer *timer; | 103 | struct bcm2835_timer *timer; |
110 | 104 | ||
111 | node = of_find_matching_node(NULL, bcm2835_time_match); | ||
112 | if (!node) | ||
113 | panic("No bcm2835 timer node"); | ||
114 | |||
115 | base = of_iomap(node, 0); | 105 | base = of_iomap(node, 0); |
116 | if (!base) | 106 | if (!base) |
117 | panic("Can't remap registers"); | 107 | panic("Can't remap registers"); |
diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c new file mode 100644 index 000000000000..685bc60e210a --- /dev/null +++ b/drivers/clocksource/cadence_ttc_timer.c | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * This file contains driver for the Cadence Triple Timer Counter Rev 06 | ||
3 | * | ||
4 | * Copyright (C) 2011-2013 Xilinx | ||
5 | * | ||
6 | * based on arch/mips/kernel/time.c timer driver | ||
7 | * | ||
8 | * This software is licensed under the terms of the GNU General Public | ||
9 | * License version 2, as published by the Free Software Foundation, and | ||
10 | * may be copied, distributed, and modified under those terms. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/clockchips.h> | ||
21 | #include <linux/of_address.h> | ||
22 | #include <linux/of_irq.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/clk-provider.h> | ||
25 | |||
26 | /* | ||
27 | * This driver configures the 2 16-bit count-up timers as follows: | ||
28 | * | ||
29 | * T1: Timer 1, clocksource for generic timekeeping | ||
30 | * T2: Timer 2, clockevent source for hrtimers | ||
31 | * T3: Timer 3, <unused> | ||
32 | * | ||
33 | * The input frequency to the timer module for emulation is 2.5MHz which is | ||
34 | * common to all the timer channels (T1, T2, and T3). With a pre-scaler of 32, | ||
35 | * the timers are clocked at 78.125KHz (12.8 us resolution). | ||
36 | |||
37 | * The input frequency to the timer module in silicon is configurable and | ||
38 | * obtained from device tree. The pre-scaler of 32 is used. | ||
39 | */ | ||
40 | |||
41 | /* | ||
42 | * Timer Register Offset Definitions of Timer 1, Increment base address by 4 | ||
43 | * and use same offsets for Timer 2 | ||
44 | */ | ||
45 | #define TTC_CLK_CNTRL_OFFSET 0x00 /* Clock Control Reg, RW */ | ||
46 | #define TTC_CNT_CNTRL_OFFSET 0x0C /* Counter Control Reg, RW */ | ||
47 | #define TTC_COUNT_VAL_OFFSET 0x18 /* Counter Value Reg, RO */ | ||
48 | #define TTC_INTR_VAL_OFFSET 0x24 /* Interval Count Reg, RW */ | ||
49 | #define TTC_ISR_OFFSET 0x54 /* Interrupt Status Reg, RO */ | ||
50 | #define TTC_IER_OFFSET 0x60 /* Interrupt Enable Reg, RW */ | ||
51 | |||
52 | #define TTC_CNT_CNTRL_DISABLE_MASK 0x1 | ||
53 | |||
54 | /* | ||
55 | * Setup the timers to use pre-scaling, using a fixed value for now that will | ||
56 | * work across most input frequency, but it may need to be more dynamic | ||
57 | */ | ||
58 | #define PRESCALE_EXPONENT 11 /* 2 ^ PRESCALE_EXPONENT = PRESCALE */ | ||
59 | #define PRESCALE 2048 /* The exponent must match this */ | ||
60 | #define CLK_CNTRL_PRESCALE ((PRESCALE_EXPONENT - 1) << 1) | ||
61 | #define CLK_CNTRL_PRESCALE_EN 1 | ||
62 | #define CNT_CNTRL_RESET (1 << 4) | ||
63 | |||
64 | /** | ||
65 | * struct ttc_timer - This definition defines local timer structure | ||
66 | * | ||
67 | * @base_addr: Base address of timer | ||
68 | * @clk: Associated clock source | ||
69 | * @clk_rate_change_nb Notifier block for clock rate changes | ||
70 | */ | ||
71 | struct ttc_timer { | ||
72 | void __iomem *base_addr; | ||
73 | struct clk *clk; | ||
74 | struct notifier_block clk_rate_change_nb; | ||
75 | }; | ||
76 | |||
77 | #define to_ttc_timer(x) \ | ||
78 | container_of(x, struct ttc_timer, clk_rate_change_nb) | ||
79 | |||
80 | struct ttc_timer_clocksource { | ||
81 | struct ttc_timer ttc; | ||
82 | struct clocksource cs; | ||
83 | }; | ||
84 | |||
85 | #define to_ttc_timer_clksrc(x) \ | ||
86 | container_of(x, struct ttc_timer_clocksource, cs) | ||
87 | |||
88 | struct ttc_timer_clockevent { | ||
89 | struct ttc_timer ttc; | ||
90 | struct clock_event_device ce; | ||
91 | }; | ||
92 | |||
93 | #define to_ttc_timer_clkevent(x) \ | ||
94 | container_of(x, struct ttc_timer_clockevent, ce) | ||
95 | |||
96 | /** | ||
97 | * ttc_set_interval - Set the timer interval value | ||
98 | * | ||
99 | * @timer: Pointer to the timer instance | ||
100 | * @cycles: Timer interval ticks | ||
101 | **/ | ||
102 | static void ttc_set_interval(struct ttc_timer *timer, | ||
103 | unsigned long cycles) | ||
104 | { | ||
105 | u32 ctrl_reg; | ||
106 | |||
107 | /* Disable the counter, set the counter value and re-enable counter */ | ||
108 | ctrl_reg = __raw_readl(timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
109 | ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; | ||
110 | __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
111 | |||
112 | __raw_writel(cycles, timer->base_addr + TTC_INTR_VAL_OFFSET); | ||
113 | |||
114 | /* | ||
115 | * Reset the counter (0x10) so that it starts from 0, one-shot | ||
116 | * mode makes this needed for timing to be right. | ||
117 | */ | ||
118 | ctrl_reg |= CNT_CNTRL_RESET; | ||
119 | ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; | ||
120 | __raw_writel(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * ttc_clock_event_interrupt - Clock event timer interrupt handler | ||
125 | * | ||
126 | * @irq: IRQ number of the Timer | ||
127 | * @dev_id: void pointer to the ttc_timer instance | ||
128 | * | ||
129 | * returns: Always IRQ_HANDLED - success | ||
130 | **/ | ||
131 | static irqreturn_t ttc_clock_event_interrupt(int irq, void *dev_id) | ||
132 | { | ||
133 | struct ttc_timer_clockevent *ttce = dev_id; | ||
134 | struct ttc_timer *timer = &ttce->ttc; | ||
135 | |||
136 | /* Acknowledge the interrupt and call event handler */ | ||
137 | __raw_readl(timer->base_addr + TTC_ISR_OFFSET); | ||
138 | |||
139 | ttce->ce.event_handler(&ttce->ce); | ||
140 | |||
141 | return IRQ_HANDLED; | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * __ttc_clocksource_read - Reads the timer counter register | ||
146 | * | ||
147 | * returns: Current timer counter register value | ||
148 | **/ | ||
149 | static cycle_t __ttc_clocksource_read(struct clocksource *cs) | ||
150 | { | ||
151 | struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc; | ||
152 | |||
153 | return (cycle_t)__raw_readl(timer->base_addr + | ||
154 | TTC_COUNT_VAL_OFFSET); | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * ttc_set_next_event - Sets the time interval for next event | ||
159 | * | ||
160 | * @cycles: Timer interval ticks | ||
161 | * @evt: Address of clock event instance | ||
162 | * | ||
163 | * returns: Always 0 - success | ||
164 | **/ | ||
165 | static int ttc_set_next_event(unsigned long cycles, | ||
166 | struct clock_event_device *evt) | ||
167 | { | ||
168 | struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); | ||
169 | struct ttc_timer *timer = &ttce->ttc; | ||
170 | |||
171 | ttc_set_interval(timer, cycles); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * ttc_set_mode - Sets the mode of timer | ||
177 | * | ||
178 | * @mode: Mode to be set | ||
179 | * @evt: Address of clock event instance | ||
180 | **/ | ||
181 | static void ttc_set_mode(enum clock_event_mode mode, | ||
182 | struct clock_event_device *evt) | ||
183 | { | ||
184 | struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); | ||
185 | struct ttc_timer *timer = &ttce->ttc; | ||
186 | u32 ctrl_reg; | ||
187 | |||
188 | switch (mode) { | ||
189 | case CLOCK_EVT_MODE_PERIODIC: | ||
190 | ttc_set_interval(timer, | ||
191 | DIV_ROUND_CLOSEST(clk_get_rate(ttce->ttc.clk), | ||
192 | PRESCALE * HZ)); | ||
193 | break; | ||
194 | case CLOCK_EVT_MODE_ONESHOT: | ||
195 | case CLOCK_EVT_MODE_UNUSED: | ||
196 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
197 | ctrl_reg = __raw_readl(timer->base_addr + | ||
198 | TTC_CNT_CNTRL_OFFSET); | ||
199 | ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; | ||
200 | __raw_writel(ctrl_reg, | ||
201 | timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
202 | break; | ||
203 | case CLOCK_EVT_MODE_RESUME: | ||
204 | ctrl_reg = __raw_readl(timer->base_addr + | ||
205 | TTC_CNT_CNTRL_OFFSET); | ||
206 | ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; | ||
207 | __raw_writel(ctrl_reg, | ||
208 | timer->base_addr + TTC_CNT_CNTRL_OFFSET); | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, | ||
214 | unsigned long event, void *data) | ||
215 | { | ||
216 | struct clk_notifier_data *ndata = data; | ||
217 | struct ttc_timer *ttc = to_ttc_timer(nb); | ||
218 | struct ttc_timer_clocksource *ttccs = container_of(ttc, | ||
219 | struct ttc_timer_clocksource, ttc); | ||
220 | |||
221 | switch (event) { | ||
222 | case POST_RATE_CHANGE: | ||
223 | /* | ||
224 | * Do whatever is necessary to maintain a proper time base | ||
225 | * | ||
226 | * I cannot find a way to adjust the currently used clocksource | ||
227 | * to the new frequency. __clocksource_updatefreq_hz() sounds | ||
228 | * good, but does not work. Not sure what's that missing. | ||
229 | * | ||
230 | * This approach works, but triggers two clocksource switches. | ||
231 | * The first after unregister to clocksource jiffies. And | ||
232 | * another one after the register to the newly registered timer. | ||
233 | * | ||
234 | * Alternatively we could 'waste' another HW timer to ping pong | ||
235 | * between clock sources. That would also use one register and | ||
236 | * one unregister call, but only trigger one clocksource switch | ||
237 | * for the cost of another HW timer used by the OS. | ||
238 | */ | ||
239 | clocksource_unregister(&ttccs->cs); | ||
240 | clocksource_register_hz(&ttccs->cs, | ||
241 | ndata->new_rate / PRESCALE); | ||
242 | /* fall through */ | ||
243 | case PRE_RATE_CHANGE: | ||
244 | case ABORT_RATE_CHANGE: | ||
245 | default: | ||
246 | return NOTIFY_DONE; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static void __init ttc_setup_clocksource(struct clk *clk, void __iomem *base) | ||
251 | { | ||
252 | struct ttc_timer_clocksource *ttccs; | ||
253 | int err; | ||
254 | |||
255 | ttccs = kzalloc(sizeof(*ttccs), GFP_KERNEL); | ||
256 | if (WARN_ON(!ttccs)) | ||
257 | return; | ||
258 | |||
259 | ttccs->ttc.clk = clk; | ||
260 | |||
261 | err = clk_prepare_enable(ttccs->ttc.clk); | ||
262 | if (WARN_ON(err)) { | ||
263 | kfree(ttccs); | ||
264 | return; | ||
265 | } | ||
266 | |||
267 | ttccs->ttc.clk_rate_change_nb.notifier_call = | ||
268 | ttc_rate_change_clocksource_cb; | ||
269 | ttccs->ttc.clk_rate_change_nb.next = NULL; | ||
270 | if (clk_notifier_register(ttccs->ttc.clk, | ||
271 | &ttccs->ttc.clk_rate_change_nb)) | ||
272 | pr_warn("Unable to register clock notifier.\n"); | ||
273 | |||
274 | ttccs->ttc.base_addr = base; | ||
275 | ttccs->cs.name = "ttc_clocksource"; | ||
276 | ttccs->cs.rating = 200; | ||
277 | ttccs->cs.read = __ttc_clocksource_read; | ||
278 | ttccs->cs.mask = CLOCKSOURCE_MASK(16); | ||
279 | ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
280 | |||
281 | /* | ||
282 | * Setup the clock source counter to be an incrementing counter | ||
283 | * with no interrupt and it rolls over at 0xFFFF. Pre-scale | ||
284 | * it by 32 also. Let it start running now. | ||
285 | */ | ||
286 | __raw_writel(0x0, ttccs->ttc.base_addr + TTC_IER_OFFSET); | ||
287 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
288 | ttccs->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); | ||
289 | __raw_writel(CNT_CNTRL_RESET, | ||
290 | ttccs->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); | ||
291 | |||
292 | err = clocksource_register_hz(&ttccs->cs, | ||
293 | clk_get_rate(ttccs->ttc.clk) / PRESCALE); | ||
294 | if (WARN_ON(err)) { | ||
295 | kfree(ttccs); | ||
296 | return; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static int ttc_rate_change_clockevent_cb(struct notifier_block *nb, | ||
301 | unsigned long event, void *data) | ||
302 | { | ||
303 | struct clk_notifier_data *ndata = data; | ||
304 | struct ttc_timer *ttc = to_ttc_timer(nb); | ||
305 | struct ttc_timer_clockevent *ttcce = container_of(ttc, | ||
306 | struct ttc_timer_clockevent, ttc); | ||
307 | |||
308 | switch (event) { | ||
309 | case POST_RATE_CHANGE: | ||
310 | { | ||
311 | unsigned long flags; | ||
312 | |||
313 | /* | ||
314 | * clockevents_update_freq should be called with IRQ disabled on | ||
315 | * the CPU the timer provides events for. The timer we use is | ||
316 | * common to both CPUs, not sure if we need to run on both | ||
317 | * cores. | ||
318 | */ | ||
319 | local_irq_save(flags); | ||
320 | clockevents_update_freq(&ttcce->ce, | ||
321 | ndata->new_rate / PRESCALE); | ||
322 | local_irq_restore(flags); | ||
323 | |||
324 | /* fall through */ | ||
325 | } | ||
326 | case PRE_RATE_CHANGE: | ||
327 | case ABORT_RATE_CHANGE: | ||
328 | default: | ||
329 | return NOTIFY_DONE; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | static void __init ttc_setup_clockevent(struct clk *clk, | ||
334 | void __iomem *base, u32 irq) | ||
335 | { | ||
336 | struct ttc_timer_clockevent *ttcce; | ||
337 | int err; | ||
338 | |||
339 | ttcce = kzalloc(sizeof(*ttcce), GFP_KERNEL); | ||
340 | if (WARN_ON(!ttcce)) | ||
341 | return; | ||
342 | |||
343 | ttcce->ttc.clk = clk; | ||
344 | |||
345 | err = clk_prepare_enable(ttcce->ttc.clk); | ||
346 | if (WARN_ON(err)) { | ||
347 | kfree(ttcce); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | ttcce->ttc.clk_rate_change_nb.notifier_call = | ||
352 | ttc_rate_change_clockevent_cb; | ||
353 | ttcce->ttc.clk_rate_change_nb.next = NULL; | ||
354 | if (clk_notifier_register(ttcce->ttc.clk, | ||
355 | &ttcce->ttc.clk_rate_change_nb)) | ||
356 | pr_warn("Unable to register clock notifier.\n"); | ||
357 | |||
358 | ttcce->ttc.base_addr = base; | ||
359 | ttcce->ce.name = "ttc_clockevent"; | ||
360 | ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
361 | ttcce->ce.set_next_event = ttc_set_next_event; | ||
362 | ttcce->ce.set_mode = ttc_set_mode; | ||
363 | ttcce->ce.rating = 200; | ||
364 | ttcce->ce.irq = irq; | ||
365 | ttcce->ce.cpumask = cpu_possible_mask; | ||
366 | |||
367 | /* | ||
368 | * Setup the clock event timer to be an interval timer which | ||
369 | * is prescaled by 32 using the interval interrupt. Leave it | ||
370 | * disabled for now. | ||
371 | */ | ||
372 | __raw_writel(0x23, ttcce->ttc.base_addr + TTC_CNT_CNTRL_OFFSET); | ||
373 | __raw_writel(CLK_CNTRL_PRESCALE | CLK_CNTRL_PRESCALE_EN, | ||
374 | ttcce->ttc.base_addr + TTC_CLK_CNTRL_OFFSET); | ||
375 | __raw_writel(0x1, ttcce->ttc.base_addr + TTC_IER_OFFSET); | ||
376 | |||
377 | err = request_irq(irq, ttc_clock_event_interrupt, | ||
378 | IRQF_DISABLED | IRQF_TIMER, | ||
379 | ttcce->ce.name, ttcce); | ||
380 | if (WARN_ON(err)) { | ||
381 | kfree(ttcce); | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | clockevents_config_and_register(&ttcce->ce, | ||
386 | clk_get_rate(ttcce->ttc.clk) / PRESCALE, 1, 0xfffe); | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * ttc_timer_init - Initialize the timer | ||
391 | * | ||
392 | * Initializes the timer hardware and register the clock source and clock event | ||
393 | * timers with Linux kernal timer framework | ||
394 | */ | ||
395 | static void __init ttc_timer_init(struct device_node *timer) | ||
396 | { | ||
397 | unsigned int irq; | ||
398 | void __iomem *timer_baseaddr; | ||
399 | struct clk *clk; | ||
400 | static int initialized; | ||
401 | |||
402 | if (initialized) | ||
403 | return; | ||
404 | |||
405 | initialized = 1; | ||
406 | |||
407 | /* | ||
408 | * Get the 1st Triple Timer Counter (TTC) block from the device tree | ||
409 | * and use it. Note that the event timer uses the interrupt and it's the | ||
410 | * 2nd TTC hence the irq_of_parse_and_map(,1) | ||
411 | */ | ||
412 | timer_baseaddr = of_iomap(timer, 0); | ||
413 | if (!timer_baseaddr) { | ||
414 | pr_err("ERROR: invalid timer base address\n"); | ||
415 | BUG(); | ||
416 | } | ||
417 | |||
418 | irq = irq_of_parse_and_map(timer, 1); | ||
419 | if (irq <= 0) { | ||
420 | pr_err("ERROR: invalid interrupt number\n"); | ||
421 | BUG(); | ||
422 | } | ||
423 | |||
424 | clk = of_clk_get_by_name(timer, "cpu_1x"); | ||
425 | if (IS_ERR(clk)) { | ||
426 | pr_err("ERROR: timer input clock not found\n"); | ||
427 | BUG(); | ||
428 | } | ||
429 | |||
430 | ttc_setup_clocksource(clk, timer_baseaddr); | ||
431 | ttc_setup_clockevent(clk, timer_baseaddr + 4, irq); | ||
432 | |||
433 | pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq); | ||
434 | } | ||
435 | |||
436 | CLOCKSOURCE_OF_DECLARE(ttc, "cdns,ttc", ttc_timer_init); | ||
diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c index bdabdaa8d00f..37f5325bec95 100644 --- a/drivers/clocksource/clksrc-of.c +++ b/drivers/clocksource/clksrc-of.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/of.h> | 18 | #include <linux/of.h> |
19 | #include <linux/clocksource.h> | ||
19 | 20 | ||
20 | extern struct of_device_id __clksrc_of_table[]; | 21 | extern struct of_device_id __clksrc_of_table[]; |
21 | 22 | ||
@@ -26,10 +27,10 @@ void __init clocksource_of_init(void) | |||
26 | { | 27 | { |
27 | struct device_node *np; | 28 | struct device_node *np; |
28 | const struct of_device_id *match; | 29 | const struct of_device_id *match; |
29 | void (*init_func)(void); | 30 | clocksource_of_init_fn init_func; |
30 | 31 | ||
31 | for_each_matching_node_and_match(np, __clksrc_of_table, &match) { | 32 | for_each_matching_node_and_match(np, __clksrc_of_table, &match) { |
32 | init_func = match->data; | 33 | init_func = match->data; |
33 | init_func(); | 34 | init_func(np); |
34 | } | 35 | } |
35 | } | 36 | } |
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 0bde03feb095..2e4d8a666c36 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c | |||
@@ -154,29 +154,12 @@ static struct irqaction tegra_timer_irq = { | |||
154 | .dev_id = &tegra_clockevent, | 154 | .dev_id = &tegra_clockevent, |
155 | }; | 155 | }; |
156 | 156 | ||
157 | static const struct of_device_id timer_match[] __initconst = { | 157 | static void __init tegra20_init_timer(struct device_node *np) |
158 | { .compatible = "nvidia,tegra20-timer" }, | ||
159 | {} | ||
160 | }; | ||
161 | |||
162 | static const struct of_device_id rtc_match[] __initconst = { | ||
163 | { .compatible = "nvidia,tegra20-rtc" }, | ||
164 | {} | ||
165 | }; | ||
166 | |||
167 | static void __init tegra20_init_timer(void) | ||
168 | { | 158 | { |
169 | struct device_node *np; | ||
170 | struct clk *clk; | 159 | struct clk *clk; |
171 | unsigned long rate; | 160 | unsigned long rate; |
172 | int ret; | 161 | int ret; |
173 | 162 | ||
174 | np = of_find_matching_node(NULL, timer_match); | ||
175 | if (!np) { | ||
176 | pr_err("Failed to find timer DT node\n"); | ||
177 | BUG(); | ||
178 | } | ||
179 | |||
180 | timer_reg_base = of_iomap(np, 0); | 163 | timer_reg_base = of_iomap(np, 0); |
181 | if (!timer_reg_base) { | 164 | if (!timer_reg_base) { |
182 | pr_err("Can't map timer registers\n"); | 165 | pr_err("Can't map timer registers\n"); |
@@ -200,30 +183,6 @@ static void __init tegra20_init_timer(void) | |||
200 | 183 | ||
201 | of_node_put(np); | 184 | of_node_put(np); |
202 | 185 | ||
203 | np = of_find_matching_node(NULL, rtc_match); | ||
204 | if (!np) { | ||
205 | pr_err("Failed to find RTC DT node\n"); | ||
206 | BUG(); | ||
207 | } | ||
208 | |||
209 | rtc_base = of_iomap(np, 0); | ||
210 | if (!rtc_base) { | ||
211 | pr_err("Can't map RTC registers"); | ||
212 | BUG(); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * rtc registers are used by read_persistent_clock, keep the rtc clock | ||
217 | * enabled | ||
218 | */ | ||
219 | clk = clk_get_sys("rtc-tegra", NULL); | ||
220 | if (IS_ERR(clk)) | ||
221 | pr_warn("Unable to get rtc-tegra clock\n"); | ||
222 | else | ||
223 | clk_prepare_enable(clk); | ||
224 | |||
225 | of_node_put(np); | ||
226 | |||
227 | switch (rate) { | 186 | switch (rate) { |
228 | case 12000000: | 187 | case 12000000: |
229 | timer_writel(0x000b, TIMERUS_USEC_CFG); | 188 | timer_writel(0x000b, TIMERUS_USEC_CFG); |
@@ -259,12 +218,34 @@ static void __init tegra20_init_timer(void) | |||
259 | tegra_clockevent.irq = tegra_timer_irq.irq; | 218 | tegra_clockevent.irq = tegra_timer_irq.irq; |
260 | clockevents_config_and_register(&tegra_clockevent, 1000000, | 219 | clockevents_config_and_register(&tegra_clockevent, 1000000, |
261 | 0x1, 0x1fffffff); | 220 | 0x1, 0x1fffffff); |
262 | #ifdef CONFIG_HAVE_ARM_TWD | 221 | } |
263 | twd_local_timer_of_register(); | 222 | CLOCKSOURCE_OF_DECLARE(tegra20_timer, "nvidia,tegra20-timer", tegra20_init_timer); |
264 | #endif | 223 | |
224 | static void __init tegra20_init_rtc(struct device_node *np) | ||
225 | { | ||
226 | struct clk *clk; | ||
227 | |||
228 | rtc_base = of_iomap(np, 0); | ||
229 | if (!rtc_base) { | ||
230 | pr_err("Can't map RTC registers"); | ||
231 | BUG(); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * rtc registers are used by read_persistent_clock, keep the rtc clock | ||
236 | * enabled | ||
237 | */ | ||
238 | clk = clk_get_sys("rtc-tegra", NULL); | ||
239 | if (IS_ERR(clk)) | ||
240 | pr_warn("Unable to get rtc-tegra clock\n"); | ||
241 | else | ||
242 | clk_prepare_enable(clk); | ||
243 | |||
244 | of_node_put(np); | ||
245 | |||
265 | register_persistent_clock(NULL, tegra_read_persistent_clock); | 246 | register_persistent_clock(NULL, tegra_read_persistent_clock); |
266 | } | 247 | } |
267 | CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); | 248 | CLOCKSOURCE_OF_DECLARE(tegra20_rtc, "nvidia,tegra20-rtc", tegra20_init_rtc); |
268 | 249 | ||
269 | #ifdef CONFIG_PM | 250 | #ifdef CONFIG_PM |
270 | static u32 usec_config; | 251 | static u32 usec_config; |
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 8efc86b5b5dd..64f553f04fa4 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c | |||
@@ -129,22 +129,10 @@ static struct irqaction irq = { | |||
129 | .dev_id = &clockevent, | 129 | .dev_id = &clockevent, |
130 | }; | 130 | }; |
131 | 131 | ||
132 | static struct of_device_id vt8500_timer_ids[] = { | 132 | static void __init vt8500_timer_init(struct device_node *np) |
133 | { .compatible = "via,vt8500-timer" }, | ||
134 | { } | ||
135 | }; | ||
136 | |||
137 | static void __init vt8500_timer_init(void) | ||
138 | { | 133 | { |
139 | struct device_node *np; | ||
140 | int timer_irq; | 134 | int timer_irq; |
141 | 135 | ||
142 | np = of_find_matching_node(NULL, vt8500_timer_ids); | ||
143 | if (!np) { | ||
144 | pr_err("%s: Timer description missing from Device Tree\n", | ||
145 | __func__); | ||
146 | return; | ||
147 | } | ||
148 | regbase = of_iomap(np, 0); | 136 | regbase = of_iomap(np, 0); |
149 | if (!regbase) { | 137 | if (!regbase) { |
150 | pr_err("%s: Missing iobase description in Device Tree\n", | 138 | pr_err("%s: Missing iobase description in Device Tree\n", |
@@ -177,4 +165,4 @@ static void __init vt8500_timer_init(void) | |||
177 | 4, 0xf0000000); | 165 | 4, 0xf0000000); |
178 | } | 166 | } |
179 | 167 | ||
180 | CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init) | 168 | CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init); |
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index 27cfda427dd9..192d6d1771ee 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h | |||
@@ -332,15 +332,23 @@ extern int clocksource_mmio_init(void __iomem *, const char *, | |||
332 | 332 | ||
333 | extern int clocksource_i8253_init(void); | 333 | extern int clocksource_i8253_init(void); |
334 | 334 | ||
335 | struct device_node; | ||
336 | typedef void(*clocksource_of_init_fn)(struct device_node *); | ||
335 | #ifdef CONFIG_CLKSRC_OF | 337 | #ifdef CONFIG_CLKSRC_OF |
336 | extern void clocksource_of_init(void); | 338 | extern void clocksource_of_init(void); |
337 | 339 | ||
338 | #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ | 340 | #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ |
339 | static const struct of_device_id __clksrc_of_table_##name \ | 341 | static const struct of_device_id __clksrc_of_table_##name \ |
340 | __used __section(__clksrc_of_table) \ | 342 | __used __section(__clksrc_of_table) \ |
341 | = { .compatible = compat, .data = fn }; | 343 | = { .compatible = compat, \ |
344 | .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn } | ||
342 | #else | 345 | #else |
343 | #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) | 346 | static inline void clocksource_of_init(void) {} |
347 | #define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ | ||
348 | static const struct of_device_id __clksrc_of_table_##name \ | ||
349 | __attribute__((unused)) \ | ||
350 | = { .compatible = compat, \ | ||
351 | .data = (fn == (clocksource_of_init_fn)NULL) ? fn : fn } | ||
344 | #endif | 352 | #endif |
345 | 353 | ||
346 | #endif /* _LINUX_CLOCKSOURCE_H */ | 354 | #endif /* _LINUX_CLOCKSOURCE_H */ |