diff options
Diffstat (limited to 'arch/arm/mach-picoxcell/time.c')
-rw-r--r-- | arch/arm/mach-picoxcell/time.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/arch/arm/mach-picoxcell/time.c b/arch/arm/mach-picoxcell/time.c new file mode 100644 index 000000000000..90a554ff4499 --- /dev/null +++ b/arch/arm/mach-picoxcell/time.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011 Picochip Ltd., Jamie Iles | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * All enquiries to support@picochip.com | ||
9 | */ | ||
10 | #include <linux/dw_apb_timer.h> | ||
11 | #include <linux/of.h> | ||
12 | #include <linux/of_address.h> | ||
13 | #include <linux/of_irq.h> | ||
14 | #include <linux/sched.h> | ||
15 | |||
16 | #include <asm/mach/time.h> | ||
17 | #include <asm/sched_clock.h> | ||
18 | |||
19 | #include "common.h" | ||
20 | |||
21 | static void timer_get_base_and_rate(struct device_node *np, | ||
22 | void __iomem **base, u32 *rate) | ||
23 | { | ||
24 | *base = of_iomap(np, 0); | ||
25 | |||
26 | if (!*base) | ||
27 | panic("Unable to map regs for %s", np->name); | ||
28 | |||
29 | if (of_property_read_u32(np, "clock-freq", rate)) | ||
30 | panic("No clock-freq property for %s", np->name); | ||
31 | } | ||
32 | |||
33 | static void picoxcell_add_clockevent(struct device_node *event_timer) | ||
34 | { | ||
35 | void __iomem *iobase; | ||
36 | struct dw_apb_clock_event_device *ced; | ||
37 | u32 irq, rate; | ||
38 | |||
39 | irq = irq_of_parse_and_map(event_timer, 0); | ||
40 | if (irq == NO_IRQ) | ||
41 | panic("No IRQ for clock event timer"); | ||
42 | |||
43 | timer_get_base_and_rate(event_timer, &iobase, &rate); | ||
44 | |||
45 | ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq, | ||
46 | rate); | ||
47 | if (!ced) | ||
48 | panic("Unable to initialise clockevent device"); | ||
49 | |||
50 | dw_apb_clockevent_register(ced); | ||
51 | } | ||
52 | |||
53 | static void picoxcell_add_clocksource(struct device_node *source_timer) | ||
54 | { | ||
55 | void __iomem *iobase; | ||
56 | struct dw_apb_clocksource *cs; | ||
57 | u32 rate; | ||
58 | |||
59 | timer_get_base_and_rate(source_timer, &iobase, &rate); | ||
60 | |||
61 | cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate); | ||
62 | if (!cs) | ||
63 | panic("Unable to initialise clocksource device"); | ||
64 | |||
65 | dw_apb_clocksource_start(cs); | ||
66 | dw_apb_clocksource_register(cs); | ||
67 | } | ||
68 | |||
69 | static DEFINE_CLOCK_DATA(cd); | ||
70 | static void __iomem *sched_io_base; | ||
71 | |||
72 | unsigned long long notrace sched_clock(void) | ||
73 | { | ||
74 | cycle_t cyc = sched_io_base ? __raw_readl(sched_io_base) : 0; | ||
75 | |||
76 | return cyc_to_sched_clock(&cd, cyc, (u32)~0); | ||
77 | } | ||
78 | |||
79 | static void notrace picoxcell_update_sched_clock(void) | ||
80 | { | ||
81 | cycle_t cyc = sched_io_base ? __raw_readl(sched_io_base) : 0; | ||
82 | |||
83 | update_sched_clock(&cd, cyc, (u32)~0); | ||
84 | } | ||
85 | |||
86 | static const struct of_device_id picoxcell_rtc_ids[] __initconst = { | ||
87 | { .compatible = "picochip,pc3x2-rtc" }, | ||
88 | { /* Sentinel */ }, | ||
89 | }; | ||
90 | |||
91 | static void picoxcell_init_sched_clock(void) | ||
92 | { | ||
93 | struct device_node *sched_timer; | ||
94 | u32 rate; | ||
95 | |||
96 | sched_timer = of_find_matching_node(NULL, picoxcell_rtc_ids); | ||
97 | if (!sched_timer) | ||
98 | panic("No RTC for sched clock to use"); | ||
99 | |||
100 | timer_get_base_and_rate(sched_timer, &sched_io_base, &rate); | ||
101 | of_node_put(sched_timer); | ||
102 | |||
103 | init_sched_clock(&cd, picoxcell_update_sched_clock, 32, rate); | ||
104 | } | ||
105 | |||
106 | static const struct of_device_id picoxcell_timer_ids[] __initconst = { | ||
107 | { .compatible = "picochip,pc3x2-timer" }, | ||
108 | {}, | ||
109 | }; | ||
110 | |||
111 | static void __init picoxcell_timer_init(void) | ||
112 | { | ||
113 | struct device_node *event_timer, *source_timer; | ||
114 | |||
115 | event_timer = of_find_matching_node(NULL, picoxcell_timer_ids); | ||
116 | if (!event_timer) | ||
117 | panic("No timer for clockevent"); | ||
118 | picoxcell_add_clockevent(event_timer); | ||
119 | |||
120 | source_timer = of_find_matching_node(event_timer, picoxcell_timer_ids); | ||
121 | if (!source_timer) | ||
122 | panic("No timer for clocksource"); | ||
123 | picoxcell_add_clocksource(source_timer); | ||
124 | |||
125 | of_node_put(source_timer); | ||
126 | |||
127 | picoxcell_init_sched_clock(); | ||
128 | } | ||
129 | |||
130 | struct sys_timer picoxcell_timer = { | ||
131 | .init = picoxcell_timer_init, | ||
132 | }; | ||