aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pxa/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-pxa/time.c')
-rw-r--r--arch/arm/mach-pxa/time.c58
1 files changed, 55 insertions, 3 deletions
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 6e5202154f91..7dad3f1465e0 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -70,6 +70,11 @@ static unsigned long pxa_gettimeoffset (void)
70 return usec; 70 return usec;
71} 71}
72 72
73#ifdef CONFIG_NO_IDLE_HZ
74static unsigned long initial_match;
75static int match_posponed;
76#endif
77
73static irqreturn_t 78static irqreturn_t
74pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 79pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
75{ 80{
@@ -77,11 +82,19 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
77 82
78 write_seqlock(&xtime_lock); 83 write_seqlock(&xtime_lock);
79 84
85#ifdef CONFIG_NO_IDLE_HZ
86 if (match_posponed) {
87 match_posponed = 0;
88 OSMR0 = initial_match;
89 }
90#endif
91
80 /* Loop until we get ahead of the free running timer. 92 /* Loop until we get ahead of the free running timer.
81 * This ensures an exact clock tick count and time accuracy. 93 * This ensures an exact clock tick count and time accuracy.
82 * IRQs are disabled inside the loop to ensure coherence between 94 * Since IRQs are disabled at this point, coherence between
83 * lost_ticks (updated in do_timer()) and the match reg value, so we 95 * lost_ticks(updated in do_timer()) and the match reg value is
84 * can use do_gettimeofday() from interrupt handlers. 96 * ensured, hence we can use do_gettimeofday() from interrupt
97 * handlers.
85 * 98 *
86 * HACK ALERT: it seems that the PXA timer regs aren't updated right 99 * HACK ALERT: it seems that the PXA timer regs aren't updated right
87 * away in all cases when a write occurs. We therefore compare with 100 * away in all cases when a write occurs. We therefore compare with
@@ -126,6 +139,42 @@ static void __init pxa_timer_init(void)
126 OSCR = 0; /* initialize free-running timer, force first match */ 139 OSCR = 0; /* initialize free-running timer, force first match */
127} 140}
128 141
142#ifdef CONFIG_NO_IDLE_HZ
143static int pxa_dyn_tick_enable_disable(void)
144{
145 /* nothing to do */
146 return 0;
147}
148
149static void pxa_dyn_tick_reprogram(unsigned long ticks)
150{
151 if (ticks > 1) {
152 initial_match = OSMR0;
153 OSMR0 = initial_match + ticks * LATCH;
154 match_posponed = 1;
155 }
156}
157
158static irqreturn_t
159pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
160{
161 if (match_posponed) {
162 match_posponed = 0;
163 OSMR0 = initial_match;
164 if ( (signed long)(initial_match - OSCR) <= 8 )
165 return pxa_timer_interrupt(irq, dev_id, regs);
166 }
167 return IRQ_NONE;
168}
169
170static struct dyn_tick_timer pxa_dyn_tick = {
171 .enable = pxa_dyn_tick_enable_disable,
172 .disable = pxa_dyn_tick_enable_disable,
173 .reprogram = pxa_dyn_tick_reprogram,
174 .handler = pxa_dyn_tick_handler,
175};
176#endif
177
129#ifdef CONFIG_PM 178#ifdef CONFIG_PM
130static unsigned long osmr[4], oier; 179static unsigned long osmr[4], oier;
131 180
@@ -161,4 +210,7 @@ struct sys_timer pxa_timer = {
161 .suspend = pxa_timer_suspend, 210 .suspend = pxa_timer_suspend,
162 .resume = pxa_timer_resume, 211 .resume = pxa_timer_resume,
163 .offset = pxa_gettimeoffset, 212 .offset = pxa_gettimeoffset,
213#ifdef CONFIG_NO_IDLE_HZ
214 .dyn_tick = &pxa_dyn_tick,
215#endif
164}; 216};