aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-sa1100/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-sa1100/time.c')
-rw-r--r--arch/arm/mach-sa1100/time.c68
1 files changed, 59 insertions, 9 deletions
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 0eeb3616ffea..47e0420623fc 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -70,15 +70,11 @@ static unsigned long sa1100_gettimeoffset (void)
70 return usec; 70 return usec;
71} 71}
72 72
73/* 73#ifdef CONFIG_NO_IDLE_HZ
74 * We will be entered with IRQs enabled. 74static unsigned long initial_match;
75 * 75static int match_posponed;
76 * Loop until we get ahead of the free running timer. 76#endif
77 * This ensures an exact clock tick count and time accuracy. 77
78 * IRQs are disabled inside the loop to ensure coherence between
79 * lost_ticks (updated in do_timer()) and the match reg value, so we
80 * can use do_gettimeofday() from interrupt handlers.
81 */
82static irqreturn_t 78static irqreturn_t
83sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 79sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
84{ 80{
@@ -86,6 +82,21 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
86 82
87 write_seqlock(&xtime_lock); 83 write_seqlock(&xtime_lock);
88 84
85#ifdef CONFIG_NO_IDLE_HZ
86 if (match_posponed) {
87 match_posponed = 0;
88 OSMR0 = initial_match;
89 }
90#endif
91
92 /*
93 * Loop until we get ahead of the free running timer.
94 * This ensures an exact clock tick count and time accuracy.
95 * Since IRQs are disabled at this point, coherence between
96 * lost_ticks(updated in do_timer()) and the match reg value is
97 * ensured, hence we can use do_gettimeofday() from interrupt
98 * handlers.
99 */
89 do { 100 do {
90 timer_tick(regs); 101 timer_tick(regs);
91 OSSR = OSSR_M0; /* Clear match on timer 0 */ 102 OSSR = OSSR_M0; /* Clear match on timer 0 */
@@ -120,6 +131,42 @@ static void __init sa1100_timer_init(void)
120 OSCR = 0; /* initialize free-running timer, force first match */ 131 OSCR = 0; /* initialize free-running timer, force first match */
121} 132}
122 133
134#ifdef CONFIG_NO_IDLE_HZ
135static int sa1100_dyn_tick_enable_disable(void)
136{
137 /* nothing to do */
138 return 0;
139}
140
141static void sa1100_dyn_tick_reprogram(unsigned long ticks)
142{
143 if (ticks > 1) {
144 initial_match = OSMR0;
145 OSMR0 = initial_match + ticks * LATCH;
146 match_posponed = 1;
147 }
148}
149
150static irqreturn_t
151sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
152{
153 if (match_posponed) {
154 match_posponed = 0;
155 OSMR0 = initial_match;
156 if ((signed long)(initial_match - OSCR) <= 0)
157 return sa1100_timer_interrupt(irq, dev_id, regs);
158 }
159 return IRQ_NONE;
160}
161
162static struct dyn_tick_timer sa1100_dyn_tick = {
163 .enable = sa1100_dyn_tick_enable_disable,
164 .disable = sa1100_dyn_tick_enable_disable,
165 .reprogram = sa1100_dyn_tick_reprogram,
166 .handler = sa1100_dyn_tick_handler,
167};
168#endif
169
123#ifdef CONFIG_PM 170#ifdef CONFIG_PM
124unsigned long osmr[4], oier; 171unsigned long osmr[4], oier;
125 172
@@ -156,4 +203,7 @@ struct sys_timer sa1100_timer = {
156 .suspend = sa1100_timer_suspend, 203 .suspend = sa1100_timer_suspend,
157 .resume = sa1100_timer_resume, 204 .resume = sa1100_timer_resume,
158 .offset = sa1100_gettimeoffset, 205 .offset = sa1100_gettimeoffset,
206#ifdef CONFIG_NO_IDLE_HZ
207 .dyn_tick = &sa1100_dyn_tick,
208#endif
159}; 209};