aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/timer-gp.c
diff options
context:
space:
mode:
authorKevin Hilman <khilman@mvista.com>2007-11-13 02:24:02 -0500
committerTony Lindgren <tony@atomide.com>2008-04-14 12:57:12 -0400
commit5a3a388fbefac3705dfcde16c93fc81e6fd9378f (patch)
treecb32a3a40650dfa2ae72b0aefffef30b3d566ec0 /arch/arm/mach-omap2/timer-gp.c
parent225dfda1d676b70acf1e696ace68c23297926ce0 (diff)
ARM: OMAP: Timer32K: Re-organize duplicated 32k-timer code
On OMAP2/3, the gp-timer code can be used for a 32kHz timer simply by setting the source to be the 32k clock instead of sys_clk. This patch uses the mach-omap2/timer-gp.c code for 32kHz timer on OMAP2, moving the logic into mach-omap2/timer-gp.c, and not using plat-omap/timer32k.c which, for OMAP2, is redundant with the timer-gp code. Also, if CONFIG_OMAP_32K_TIMER is enabled, the gptimer-based clocksource is not used. Instead the default 32k sync counter is used as the clocksource (see the clocksource in plat-omap/common.c.) This is important for sleep/suspend so there is a valid counter during sleep. Note that the suspend/sleep code needs fixing to check for overflows of this counter. In addition, the OMAP2/3 details are removed from timer32k.c leaving that with only OMAP1 specifics. A follow-up patch will move it from plat-omap common code to mach-omap1. Signed-off-by: Kevin Hilman <khilman@mvista.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/timer-gp.c')
-rw-r--r--arch/arm/mach-omap2/timer-gp.c152
1 files changed, 137 insertions, 15 deletions
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 3234deedb94..78d05f203ff 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -3,6 +3,11 @@
3 * 3 *
4 * OMAP2 GP timer support. 4 * OMAP2 GP timer support.
5 * 5 *
6 * Update to use new clocksource/clockevent layers
7 * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
8 * Copyright (C) 2007 MontaVista Software, Inc.
9 *
10 * Original driver:
6 * Copyright (C) 2005 Nokia Corporation 11 * Copyright (C) 2005 Nokia Corporation
7 * Author: Paul Mundt <paul.mundt@nokia.com> 12 * Author: Paul Mundt <paul.mundt@nokia.com>
8 * Juha Yrjölä <juha.yrjola@nokia.com> 13 * Juha Yrjölä <juha.yrjola@nokia.com>
@@ -25,24 +30,23 @@
25#include <linux/clk.h> 30#include <linux/clk.h>
26#include <linux/delay.h> 31#include <linux/delay.h>
27#include <linux/irq.h> 32#include <linux/irq.h>
33#include <linux/clocksource.h>
34#include <linux/clockchips.h>
28 35
29#include <asm/mach/time.h> 36#include <asm/mach/time.h>
30#include <asm/arch/dmtimer.h> 37#include <asm/arch/dmtimer.h>
31 38
32static struct omap_dm_timer *gptimer; 39static struct omap_dm_timer *gptimer;
33 40static struct clock_event_device clockevent_gpt;
34static inline void omap2_gp_timer_start(unsigned long load_val)
35{
36 omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val);
37 omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
38 omap_dm_timer_start(gptimer);
39}
40 41
41static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) 42static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
42{ 43{
43 omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW); 44 struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id;
44 timer_tick(); 45 struct clock_event_device *evt = &clockevent_gpt;
46
47 omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW);
45 48
49 evt->event_handler(evt);
46 return IRQ_HANDLED; 50 return IRQ_HANDLED;
47} 51}
48 52
@@ -52,20 +56,138 @@ static struct irqaction omap2_gp_timer_irq = {
52 .handler = omap2_gp_timer_interrupt, 56 .handler = omap2_gp_timer_interrupt,
53}; 57};
54 58
55static void __init omap2_gp_timer_init(void) 59static int omap2_gp_timer_set_next_event(unsigned long cycles,
60 struct clock_event_device *evt)
56{ 61{
57 u32 tick_period; 62 omap_dm_timer_set_load(gptimer, 0, 0xffffffff - cycles);
63 omap_dm_timer_start(gptimer);
64
65 return 0;
66}
67
68static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
69 struct clock_event_device *evt)
70{
71 u32 period;
72
73 omap_dm_timer_stop(gptimer);
74
75 switch (mode) {
76 case CLOCK_EVT_MODE_PERIODIC:
77 period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
78 period -= 1;
79
80 omap_dm_timer_set_load(gptimer, 1, 0xffffffff - period);
81 omap_dm_timer_start(gptimer);
82 break;
83 case CLOCK_EVT_MODE_ONESHOT:
84 break;
85 case CLOCK_EVT_MODE_UNUSED:
86 case CLOCK_EVT_MODE_SHUTDOWN:
87 case CLOCK_EVT_MODE_RESUME:
88 break;
89 }
90}
91
92static struct clock_event_device clockevent_gpt = {
93 .name = "gp timer",
94 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
95 .shift = 32,
96 .set_next_event = omap2_gp_timer_set_next_event,
97 .set_mode = omap2_gp_timer_set_mode,
98};
99
100static void __init omap2_gp_clockevent_init(void)
101{
102 u32 tick_rate;
58 103
59 omap_dm_timer_init();
60 gptimer = omap_dm_timer_request_specific(1); 104 gptimer = omap_dm_timer_request_specific(1);
61 BUG_ON(gptimer == NULL); 105 BUG_ON(gptimer == NULL);
62 106
107#if defined(CONFIG_OMAP_32K_TIMER)
108 omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ);
109#else
63 omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK); 110 omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK);
64 tick_period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ; 111#endif
65 tick_period -= 1; 112 tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
66 113
114 omap2_gp_timer_irq.dev_id = (void *)gptimer;
67 setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq); 115 setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
68 omap2_gp_timer_start(tick_period); 116 omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
117
118 clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC,
119 clockevent_gpt.shift);
120 clockevent_gpt.max_delta_ns =
121 clockevent_delta2ns(0xffffffff, &clockevent_gpt);
122 clockevent_gpt.min_delta_ns =
123 clockevent_delta2ns(1, &clockevent_gpt);
124
125 clockevent_gpt.cpumask = cpumask_of_cpu(0);
126 clockevents_register_device(&clockevent_gpt);
127}
128
129#ifdef CONFIG_OMAP_32K_TIMER
130/*
131 * When 32k-timer is enabled, don't use GPTimer for clocksource
132 * instead, just leave default clocksource which uses the 32k
133 * sync counter. See clocksource setup in see plat-omap/common.c.
134 */
135
136static inline void __init omap2_gp_clocksource_init(void) {}
137#else
138/*
139 * clocksource
140 */
141static struct omap_dm_timer *gpt_clocksource;
142static cycle_t clocksource_read_cycles(void)
143{
144 return (cycle_t)omap_dm_timer_read_counter(gpt_clocksource);
145}
146
147static struct clocksource clocksource_gpt = {
148 .name = "gp timer",
149 .rating = 300,
150 .read = clocksource_read_cycles,
151 .mask = CLOCKSOURCE_MASK(32),
152 .shift = 24,
153 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
154};
155
156/* Setup free-running counter for clocksource */
157static void __init omap2_gp_clocksource_init(void)
158{
159 static struct omap_dm_timer *gpt;
160 u32 tick_rate, tick_period;
161 static char err1[] __initdata = KERN_ERR
162 "%s: failed to request dm-timer\n";
163 static char err2[] __initdata = KERN_ERR
164 "%s: can't register clocksource!\n";
165
166 gpt = omap_dm_timer_request();
167 if (!gpt)
168 printk(err1, clocksource_gpt.name);
169 gpt_clocksource = gpt;
170
171 omap_dm_timer_set_source(gpt, OMAP_TIMER_SRC_SYS_CLK);
172 tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gpt));
173 tick_period = (tick_rate / HZ) - 1;
174
175 omap_dm_timer_set_load(gpt, 1, 0);
176 omap_dm_timer_start(gpt);
177
178 clocksource_gpt.mult =
179 clocksource_khz2mult(tick_rate/1000, clocksource_gpt.shift);
180 if (clocksource_register(&clocksource_gpt))
181 printk(err2, clocksource_gpt.name);
182}
183#endif
184
185static void __init omap2_gp_timer_init(void)
186{
187 omap_dm_timer_init();
188
189 omap2_gp_clockevent_init();
190 omap2_gp_clocksource_init();
69} 191}
70 192
71struct sys_timer omap_timer = { 193struct sys_timer omap_timer = {