Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
[pandora-kernel.git] / arch / arm / mach-omap2 / timer-gp.c
1 /*
2  * linux/arch/arm/mach-omap2/timer-gp.c
3  *
4  * OMAP2 GP timer support.
5  *
6  * Copyright (C) 2009 Nokia Corporation
7  *
8  * Update to use new clocksource/clockevent layers
9  * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
10  * Copyright (C) 2007 MontaVista Software, Inc.
11  *
12  * Original driver:
13  * Copyright (C) 2005 Nokia Corporation
14  * Author: Paul Mundt <paul.mundt@nokia.com>
15  *         Juha Yrjölä <juha.yrjola@nokia.com>
16  * OMAP Dual-mode timer framework support by Timo Teras
17  *
18  * Some parts based off of TI's 24xx code:
19  *
20  *   Copyright (C) 2004 Texas Instruments, Inc.
21  *
22  * Roughly modelled after the OMAP1 MPU timer code.
23  *
24  * This file is subject to the terms and conditions of the GNU General Public
25  * License. See the file "COPYING" in the main directory of this archive
26  * for more details.
27  */
28 #include <linux/init.h>
29 #include <linux/time.h>
30 #include <linux/interrupt.h>
31 #include <linux/err.h>
32 #include <linux/clk.h>
33 #include <linux/delay.h>
34 #include <linux/irq.h>
35 #include <linux/clocksource.h>
36 #include <linux/clockchips.h>
37
38 #include <asm/mach/time.h>
39 #include <mach/dmtimer.h>
40
41 /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */
42 #define MAX_GPTIMER_ID          12
43
44 static struct omap_dm_timer *gptimer;
45 static struct clock_event_device clockevent_gpt;
46 static u8 __initdata gptimer_id = 1;
47 static u8 __initdata inited;
48
49 static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
50 {
51         struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id;
52         struct clock_event_device *evt = &clockevent_gpt;
53
54         omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW);
55
56         evt->event_handler(evt);
57         return IRQ_HANDLED;
58 }
59
60 static struct irqaction omap2_gp_timer_irq = {
61         .name           = "gp timer",
62         .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
63         .handler        = omap2_gp_timer_interrupt,
64 };
65
66 static int omap2_gp_timer_set_next_event(unsigned long cycles,
67                                          struct clock_event_device *evt)
68 {
69         omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles);
70
71         return 0;
72 }
73
74 static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
75                                     struct clock_event_device *evt)
76 {
77         u32 period;
78
79         omap_dm_timer_stop(gptimer);
80
81         switch (mode) {
82         case CLOCK_EVT_MODE_PERIODIC:
83                 period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
84                 period -= 1;
85
86                 omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period);
87                 break;
88         case CLOCK_EVT_MODE_ONESHOT:
89                 break;
90         case CLOCK_EVT_MODE_UNUSED:
91         case CLOCK_EVT_MODE_SHUTDOWN:
92         case CLOCK_EVT_MODE_RESUME:
93                 break;
94         }
95 }
96
97 static struct clock_event_device clockevent_gpt = {
98         .name           = "gp timer",
99         .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
100         .shift          = 32,
101         .set_next_event = omap2_gp_timer_set_next_event,
102         .set_mode       = omap2_gp_timer_set_mode,
103 };
104
105 /**
106  * omap2_gp_clockevent_set_gptimer - set which GPTIMER is used for clockevents
107  * @id: GPTIMER to use (1..MAX_GPTIMER_ID)
108  *
109  * Define the GPTIMER that the system should use for the tick timer.
110  * Meant to be called from board-*.c files in the event that GPTIMER1, the
111  * default, is unsuitable.  Returns -EINVAL on error or 0 on success.
112  */
113 int __init omap2_gp_clockevent_set_gptimer(u8 id)
114 {
115         if (id < 1 || id > MAX_GPTIMER_ID)
116                 return -EINVAL;
117
118         BUG_ON(inited);
119
120         gptimer_id = id;
121
122         return 0;
123 }
124
125 static void __init omap2_gp_clockevent_init(void)
126 {
127         u32 tick_rate;
128         int src;
129
130         inited = 1;
131
132         gptimer = omap_dm_timer_request_specific(gptimer_id);
133         BUG_ON(gptimer == NULL);
134
135 #if defined(CONFIG_OMAP_32K_TIMER)
136         src = OMAP_TIMER_SRC_32_KHZ;
137 #else
138         src = OMAP_TIMER_SRC_SYS_CLK;
139         WARN(gptimer_id == 12, "WARNING: GPTIMER12 can only use the "
140              "secure 32KiHz clock source\n");
141 #endif
142
143         if (gptimer_id != 12)
144                 WARN(IS_ERR_VALUE(omap_dm_timer_set_source(gptimer, src)),
145                      "timer-gp: omap_dm_timer_set_source() failed\n");
146
147         tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
148
149         pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n",
150                 gptimer_id, tick_rate);
151
152         omap2_gp_timer_irq.dev_id = (void *)gptimer;
153         setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
154         omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
155
156         clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC,
157                                      clockevent_gpt.shift);
158         clockevent_gpt.max_delta_ns =
159                 clockevent_delta2ns(0xffffffff, &clockevent_gpt);
160         clockevent_gpt.min_delta_ns =
161                 clockevent_delta2ns(3, &clockevent_gpt);
162                 /* Timer internal resynch latency. */
163
164         clockevent_gpt.cpumask = cpumask_of(0);
165         clockevents_register_device(&clockevent_gpt);
166 }
167
168 /* Clocksource code */
169
170 #ifdef CONFIG_OMAP_32K_TIMER
171 /* 
172  * When 32k-timer is enabled, don't use GPTimer for clocksource
173  * instead, just leave default clocksource which uses the 32k
174  * sync counter.  See clocksource setup in see plat-omap/common.c. 
175  */
176
177 static inline void __init omap2_gp_clocksource_init(void) {}
178 #else
179 /*
180  * clocksource
181  */
182 static struct omap_dm_timer *gpt_clocksource;
183 static cycle_t clocksource_read_cycles(struct clocksource *cs)
184 {
185         return (cycle_t)omap_dm_timer_read_counter(gpt_clocksource);
186 }
187
188 static struct clocksource clocksource_gpt = {
189         .name           = "gp timer",
190         .rating         = 300,
191         .read           = clocksource_read_cycles,
192         .mask           = CLOCKSOURCE_MASK(32),
193         .shift          = 24,
194         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
195 };
196
197 /* Setup free-running counter for clocksource */
198 static void __init omap2_gp_clocksource_init(void)
199 {
200         static struct omap_dm_timer *gpt;
201         u32 tick_rate, tick_period;
202         static char err1[] __initdata = KERN_ERR
203                 "%s: failed to request dm-timer\n";
204         static char err2[] __initdata = KERN_ERR
205                 "%s: can't register clocksource!\n";
206
207         gpt = omap_dm_timer_request();
208         if (!gpt)
209                 printk(err1, clocksource_gpt.name);
210         gpt_clocksource = gpt;
211
212         omap_dm_timer_set_source(gpt, OMAP_TIMER_SRC_SYS_CLK);
213         tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gpt));
214         tick_period = (tick_rate / HZ) - 1;
215
216         omap_dm_timer_set_load_start(gpt, 1, 0);
217
218         clocksource_gpt.mult =
219                 clocksource_khz2mult(tick_rate/1000, clocksource_gpt.shift);
220         if (clocksource_register(&clocksource_gpt))
221                 printk(err2, clocksource_gpt.name);
222 }
223 #endif
224
225 static void __init omap2_gp_timer_init(void)
226 {
227         omap_dm_timer_init();
228
229         omap2_gp_clockevent_init();
230         omap2_gp_clocksource_init();
231 }
232
233 struct sys_timer omap_timer = {
234         .init   = omap2_gp_timer_init,
235 };