Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / arch / arm / mach-picoxcell / time.c
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
15 #include <asm/mach/time.h>
16 #include <asm/sched_clock.h>
17
18 #include "common.h"
19
20 static void timer_get_base_and_rate(struct device_node *np,
21                                     void __iomem **base, u32 *rate)
22 {
23         *base = of_iomap(np, 0);
24
25         if (!*base)
26                 panic("Unable to map regs for %s", np->name);
27
28         if (of_property_read_u32(np, "clock-freq", rate))
29                 panic("No clock-freq property for %s", np->name);
30 }
31
32 static void picoxcell_add_clockevent(struct device_node *event_timer)
33 {
34         void __iomem *iobase;
35         struct dw_apb_clock_event_device *ced;
36         u32 irq, rate;
37
38         irq = irq_of_parse_and_map(event_timer, 0);
39         if (irq == NO_IRQ)
40                 panic("No IRQ for clock event timer");
41
42         timer_get_base_and_rate(event_timer, &iobase, &rate);
43
44         ced = dw_apb_clockevent_init(0, event_timer->name, 300, iobase, irq,
45                                      rate);
46         if (!ced)
47                 panic("Unable to initialise clockevent device");
48
49         dw_apb_clockevent_register(ced);
50 }
51
52 static void picoxcell_add_clocksource(struct device_node *source_timer)
53 {
54         void __iomem *iobase;
55         struct dw_apb_clocksource *cs;
56         u32 rate;
57
58         timer_get_base_and_rate(source_timer, &iobase, &rate);
59
60         cs = dw_apb_clocksource_init(300, source_timer->name, iobase, rate);
61         if (!cs)
62                 panic("Unable to initialise clocksource device");
63
64         dw_apb_clocksource_start(cs);
65         dw_apb_clocksource_register(cs);
66 }
67
68 static void __iomem *sched_io_base;
69
70 unsigned u32 notrace picoxcell_read_sched_clock(void)
71 {
72         return __raw_readl(sched_io_base);
73 }
74
75 static const struct of_device_id picoxcell_rtc_ids[] __initconst = {
76         { .compatible = "picochip,pc3x2-rtc" },
77         { /* Sentinel */ },
78 };
79
80 static void picoxcell_init_sched_clock(void)
81 {
82         struct device_node *sched_timer;
83         u32 rate;
84
85         sched_timer = of_find_matching_node(NULL, picoxcell_rtc_ids);
86         if (!sched_timer)
87                 panic("No RTC for sched clock to use");
88
89         timer_get_base_and_rate(sched_timer, &sched_io_base, &rate);
90         of_node_put(sched_timer);
91
92         setup_sched_clock(picoxcell_read_sched_clock, 32, rate);
93 }
94
95 static const struct of_device_id picoxcell_timer_ids[] __initconst = {
96         { .compatible = "picochip,pc3x2-timer" },
97         {},
98 };
99
100 static void __init picoxcell_timer_init(void)
101 {
102         struct device_node *event_timer, *source_timer;
103
104         event_timer = of_find_matching_node(NULL, picoxcell_timer_ids);
105         if (!event_timer)
106                 panic("No timer for clockevent");
107         picoxcell_add_clockevent(event_timer);
108
109         source_timer = of_find_matching_node(event_timer, picoxcell_timer_ids);
110         if (!source_timer)
111                 panic("No timer for clocksource");
112         picoxcell_add_clocksource(source_timer);
113
114         of_node_put(source_timer);
115
116         picoxcell_init_sched_clock();
117 }
118
119 struct sys_timer picoxcell_timer = {
120         .init = picoxcell_timer_init,
121 };