diff options
Diffstat (limited to 'arch/arm/plat-omap/timer32k.c')
-rw-r--r-- | arch/arm/plat-omap/timer32k.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c index 281ecc7fcdfc..cf6df3378d37 100644 --- a/arch/arm/plat-omap/timer32k.c +++ b/arch/arm/plat-omap/timer32k.c | |||
@@ -105,6 +105,8 @@ static inline unsigned long omap_32k_timer_read(int reg) | |||
105 | 105 | ||
106 | static inline void omap_32k_timer_start(unsigned long load_val) | 106 | static inline void omap_32k_timer_start(unsigned long load_val) |
107 | { | 107 | { |
108 | if (!load_val) | ||
109 | load_val = 1; | ||
108 | omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); | 110 | omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR); |
109 | omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); | 111 | omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR); |
110 | } | 112 | } |
@@ -192,14 +194,11 @@ unsigned long long sched_clock(void) | |||
192 | * issues with dynamic tick. In the dynamic tick case, we need to lock | 194 | * issues with dynamic tick. In the dynamic tick case, we need to lock |
193 | * with irqsave. | 195 | * with irqsave. |
194 | */ | 196 | */ |
195 | static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, | 197 | static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id, |
196 | struct pt_regs *regs) | 198 | struct pt_regs *regs) |
197 | { | 199 | { |
198 | unsigned long flags; | ||
199 | unsigned long now; | 200 | unsigned long now; |
200 | 201 | ||
201 | write_seqlock_irqsave(&xtime_lock, flags); | ||
202 | |||
203 | omap_32k_timer_ack_irq(); | 202 | omap_32k_timer_ack_irq(); |
204 | now = omap_32k_sync_timer_read(); | 203 | now = omap_32k_sync_timer_read(); |
205 | 204 | ||
@@ -215,6 +214,23 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, | |||
215 | * continuous timer can be overridden from pm_idle to be longer. | 214 | * continuous timer can be overridden from pm_idle to be longer. |
216 | */ | 215 | */ |
217 | omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); | 216 | omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now); |
217 | |||
218 | return IRQ_HANDLED; | ||
219 | } | ||
220 | |||
221 | static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id, | ||
222 | struct pt_regs *regs) | ||
223 | { | ||
224 | return _omap_32k_timer_interrupt(irq, dev_id, regs); | ||
225 | } | ||
226 | |||
227 | static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, | ||
228 | struct pt_regs *regs) | ||
229 | { | ||
230 | unsigned long flags; | ||
231 | |||
232 | write_seqlock_irqsave(&xtime_lock, flags); | ||
233 | _omap_32k_timer_interrupt(irq, dev_id, regs); | ||
218 | write_sequnlock_irqrestore(&xtime_lock, flags); | 234 | write_sequnlock_irqrestore(&xtime_lock, flags); |
219 | 235 | ||
220 | return IRQ_HANDLED; | 236 | return IRQ_HANDLED; |
@@ -230,7 +246,15 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id, | |||
230 | */ | 246 | */ |
231 | void omap_32k_timer_reprogram(unsigned long next_tick) | 247 | void omap_32k_timer_reprogram(unsigned long next_tick) |
232 | { | 248 | { |
233 | omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1); | 249 | unsigned long ticks = JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1; |
250 | unsigned long now = omap_32k_sync_timer_read(); | ||
251 | unsigned long idled = now - omap_32k_last_tick; | ||
252 | |||
253 | if (idled + 1 < ticks) | ||
254 | ticks -= idled; | ||
255 | else | ||
256 | ticks = 1; | ||
257 | omap_32k_timer_start(ticks); | ||
234 | } | 258 | } |
235 | 259 | ||
236 | static struct irqaction omap_32k_timer_irq; | 260 | static struct irqaction omap_32k_timer_irq; |
@@ -252,7 +276,7 @@ static struct dyn_tick_timer omap_dyn_tick_timer = { | |||
252 | .enable = omap_32k_timer_enable_dyn_tick, | 276 | .enable = omap_32k_timer_enable_dyn_tick, |
253 | .disable = omap_32k_timer_disable_dyn_tick, | 277 | .disable = omap_32k_timer_disable_dyn_tick, |
254 | .reprogram = omap_32k_timer_reprogram, | 278 | .reprogram = omap_32k_timer_reprogram, |
255 | .handler = omap_32k_timer_interrupt, | 279 | .handler = omap_32k_timer_handler, |
256 | }; | 280 | }; |
257 | #endif /* CONFIG_NO_IDLE_HZ */ | 281 | #endif /* CONFIG_NO_IDLE_HZ */ |
258 | 282 | ||