Root/
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-2009 Texas Instruments, Inc. |
21 | * |
22 | * Roughly modelled after the OMAP1 MPU timer code. |
23 | * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> |
24 | * |
25 | * This file is subject to the terms and conditions of the GNU General Public |
26 | * License. See the file "COPYING" in the main directory of this archive |
27 | * for more details. |
28 | */ |
29 | #include <linux/init.h> |
30 | #include <linux/time.h> |
31 | #include <linux/interrupt.h> |
32 | #include <linux/err.h> |
33 | #include <linux/clk.h> |
34 | #include <linux/delay.h> |
35 | #include <linux/irq.h> |
36 | #include <linux/clocksource.h> |
37 | #include <linux/clockchips.h> |
38 | |
39 | #include <asm/mach/time.h> |
40 | #include <plat/dmtimer.h> |
41 | #include <asm/localtimer.h> |
42 | |
43 | #include "timer-gp.h" |
44 | |
45 | /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ |
46 | #define MAX_GPTIMER_ID 12 |
47 | |
48 | static struct omap_dm_timer *gptimer; |
49 | static struct clock_event_device clockevent_gpt; |
50 | static u8 __initdata gptimer_id = 1; |
51 | static u8 __initdata inited; |
52 | struct omap_dm_timer *gptimer_wakeup; |
53 | |
54 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) |
55 | { |
56 | struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id; |
57 | struct clock_event_device *evt = &clockevent_gpt; |
58 | |
59 | omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW); |
60 | |
61 | evt->event_handler(evt); |
62 | return IRQ_HANDLED; |
63 | } |
64 | |
65 | static struct irqaction omap2_gp_timer_irq = { |
66 | .name = "gp timer", |
67 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, |
68 | .handler = omap2_gp_timer_interrupt, |
69 | }; |
70 | |
71 | static int omap2_gp_timer_set_next_event(unsigned long cycles, |
72 | struct clock_event_device *evt) |
73 | { |
74 | omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles); |
75 | |
76 | return 0; |
77 | } |
78 | |
79 | static void omap2_gp_timer_set_mode(enum clock_event_mode mode, |
80 | struct clock_event_device *evt) |
81 | { |
82 | u32 period; |
83 | |
84 | omap_dm_timer_stop(gptimer); |
85 | |
86 | switch (mode) { |
87 | case CLOCK_EVT_MODE_PERIODIC: |
88 | period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ; |
89 | period -= 1; |
90 | omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period); |
91 | break; |
92 | case CLOCK_EVT_MODE_ONESHOT: |
93 | break; |
94 | case CLOCK_EVT_MODE_UNUSED: |
95 | case CLOCK_EVT_MODE_SHUTDOWN: |
96 | case CLOCK_EVT_MODE_RESUME: |
97 | break; |
98 | } |
99 | } |
100 | |
101 | static struct clock_event_device clockevent_gpt = { |
102 | .name = "gp timer", |
103 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
104 | .shift = 32, |
105 | .set_next_event = omap2_gp_timer_set_next_event, |
106 | .set_mode = omap2_gp_timer_set_mode, |
107 | }; |
108 | |
109 | /** |
110 | * omap2_gp_clockevent_set_gptimer - set which GPTIMER is used for clockevents |
111 | * @id: GPTIMER to use (1..MAX_GPTIMER_ID) |
112 | * |
113 | * Define the GPTIMER that the system should use for the tick timer. |
114 | * Meant to be called from board-*.c files in the event that GPTIMER1, the |
115 | * default, is unsuitable. Returns -EINVAL on error or 0 on success. |
116 | */ |
117 | int __init omap2_gp_clockevent_set_gptimer(u8 id) |
118 | { |
119 | if (id < 1 || id > MAX_GPTIMER_ID) |
120 | return -EINVAL; |
121 | |
122 | BUG_ON(inited); |
123 | |
124 | gptimer_id = id; |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | static void __init omap2_gp_clockevent_init(void) |
130 | { |
131 | u32 tick_rate; |
132 | int src; |
133 | |
134 | inited = 1; |
135 | |
136 | gptimer = omap_dm_timer_request_specific(gptimer_id); |
137 | BUG_ON(gptimer == NULL); |
138 | gptimer_wakeup = gptimer; |
139 | |
140 | #if defined(CONFIG_OMAP_32K_TIMER) |
141 | src = OMAP_TIMER_SRC_32_KHZ; |
142 | #else |
143 | src = OMAP_TIMER_SRC_SYS_CLK; |
144 | WARN(gptimer_id == 12, "WARNING: GPTIMER12 can only use the " |
145 | "secure 32KiHz clock source\n"); |
146 | #endif |
147 | |
148 | if (gptimer_id != 12) |
149 | WARN(IS_ERR_VALUE(omap_dm_timer_set_source(gptimer, src)), |
150 | "timer-gp: omap_dm_timer_set_source() failed\n"); |
151 | |
152 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer)); |
153 | |
154 | pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n", |
155 | gptimer_id, tick_rate); |
156 | |
157 | omap2_gp_timer_irq.dev_id = (void *)gptimer; |
158 | setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq); |
159 | omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); |
160 | |
161 | clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC, |
162 | clockevent_gpt.shift); |
163 | clockevent_gpt.max_delta_ns = |
164 | clockevent_delta2ns(0xffffffff, &clockevent_gpt); |
165 | clockevent_gpt.min_delta_ns = |
166 | clockevent_delta2ns(3, &clockevent_gpt); |
167 | /* Timer internal resynch latency. */ |
168 | |
169 | clockevent_gpt.cpumask = cpumask_of(0); |
170 | clockevents_register_device(&clockevent_gpt); |
171 | } |
172 | |
173 | /* Clocksource code */ |
174 | |
175 | #ifdef CONFIG_OMAP_32K_TIMER |
176 | /* |
177 | * When 32k-timer is enabled, don't use GPTimer for clocksource |
178 | * instead, just leave default clocksource which uses the 32k |
179 | * sync counter. See clocksource setup in see plat-omap/common.c. |
180 | */ |
181 | |
182 | static inline void __init omap2_gp_clocksource_init(void) {} |
183 | #else |
184 | /* |
185 | * clocksource |
186 | */ |
187 | static struct omap_dm_timer *gpt_clocksource; |
188 | static cycle_t clocksource_read_cycles(struct clocksource *cs) |
189 | { |
190 | return (cycle_t)omap_dm_timer_read_counter(gpt_clocksource); |
191 | } |
192 | |
193 | static struct clocksource clocksource_gpt = { |
194 | .name = "gp timer", |
195 | .rating = 300, |
196 | .read = clocksource_read_cycles, |
197 | .mask = CLOCKSOURCE_MASK(32), |
198 | .shift = 24, |
199 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
200 | }; |
201 | |
202 | /* Setup free-running counter for clocksource */ |
203 | static void __init omap2_gp_clocksource_init(void) |
204 | { |
205 | static struct omap_dm_timer *gpt; |
206 | u32 tick_rate, tick_period; |
207 | static char err1[] __initdata = KERN_ERR |
208 | "%s: failed to request dm-timer\n"; |
209 | static char err2[] __initdata = KERN_ERR |
210 | "%s: can't register clocksource!\n"; |
211 | |
212 | gpt = omap_dm_timer_request(); |
213 | if (!gpt) |
214 | printk(err1, clocksource_gpt.name); |
215 | gpt_clocksource = gpt; |
216 | |
217 | omap_dm_timer_set_source(gpt, OMAP_TIMER_SRC_SYS_CLK); |
218 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gpt)); |
219 | tick_period = (tick_rate / HZ) - 1; |
220 | |
221 | omap_dm_timer_set_load_start(gpt, 1, 0); |
222 | |
223 | clocksource_gpt.mult = |
224 | clocksource_khz2mult(tick_rate/1000, clocksource_gpt.shift); |
225 | if (clocksource_register(&clocksource_gpt)) |
226 | printk(err2, clocksource_gpt.name); |
227 | } |
228 | #endif |
229 | |
230 | static void __init omap2_gp_timer_init(void) |
231 | { |
232 | #ifdef CONFIG_LOCAL_TIMERS |
233 | if (cpu_is_omap44xx()) { |
234 | twd_base = ioremap(OMAP44XX_LOCAL_TWD_BASE, SZ_256); |
235 | BUG_ON(!twd_base); |
236 | } |
237 | #endif |
238 | omap_dm_timer_init(); |
239 | |
240 | omap2_gp_clockevent_init(); |
241 | omap2_gp_clocksource_init(); |
242 | } |
243 | |
244 | struct sys_timer omap_timer = { |
245 | .init = omap2_gp_timer_init, |
246 | }; |
247 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9