summary refs log tree commit diff
path: root/arch/arm/mach-sa1100/time.c
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2005-09-01 12:48:48 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-09-01 12:48:48 +0100
commit569d2c34dcf259b07977835492aa8813d1168230 (patch)
treeaa16ba481ff295b1cf7d0bafa503078bc54249a2 /arch/arm/mach-sa1100/time.c
parent20e912680842504ab4633deaa644c2b855ad3d44 (diff)
downloadlinux-569d2c34dcf259b07977835492aa8813d1168230.tar.gz
[ARM] 2864/1: VST aka CONFIG_NO_IDLE_HZ support for SA11x0
Patch from Nicolas Pitre

Signed-off-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mach-sa1100/time.c')
-rw-r--r--arch/arm/mach-sa1100/time.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index a084b38698cf..47e0420623fc 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -70,6 +70,11 @@ static unsigned long sa1100_gettimeoffset (void)
 	return usec;
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+static unsigned long initial_match;
+static int match_posponed;
+#endif
+
 static irqreturn_t
 sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
@@ -77,6 +82,13 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 	write_seqlock(&xtime_lock);
 
+#ifdef CONFIG_NO_IDLE_HZ
+	if (match_posponed) {
+		match_posponed = 0;
+		OSMR0 = initial_match;
+	}
+#endif
+
 	/*
 	 * Loop until we get ahead of the free running timer.
 	 * This ensures an exact clock tick count and time accuracy.
@@ -119,6 +131,42 @@ static void __init sa1100_timer_init(void)
 	OSCR = 0;		/* initialize free-running timer, force first match */
 }
 
+#ifdef CONFIG_NO_IDLE_HZ
+static int sa1100_dyn_tick_enable_disable(void)
+{
+	/* nothing to do */
+	return 0;
+}
+
+static void sa1100_dyn_tick_reprogram(unsigned long ticks)
+{
+	if (ticks > 1) {
+		initial_match = OSMR0;
+		OSMR0 = initial_match + ticks * LATCH;
+		match_posponed = 1;
+	}
+}
+
+static irqreturn_t
+sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (match_posponed) {
+		match_posponed = 0;
+		OSMR0 = initial_match;
+		if ((signed long)(initial_match - OSCR) <= 0)
+			return sa1100_timer_interrupt(irq, dev_id, regs);
+	}
+	return IRQ_NONE;
+}
+
+static struct dyn_tick_timer sa1100_dyn_tick = {
+	.enable		= sa1100_dyn_tick_enable_disable,
+	.disable	= sa1100_dyn_tick_enable_disable,
+	.reprogram	= sa1100_dyn_tick_reprogram,
+	.handler	= sa1100_dyn_tick_handler,
+};
+#endif
+
 #ifdef CONFIG_PM
 unsigned long osmr[4], oier;
 
@@ -155,4 +203,7 @@ struct sys_timer sa1100_timer = {
 	.suspend	= sa1100_timer_suspend,
 	.resume		= sa1100_timer_resume,
 	.offset		= sa1100_gettimeoffset,
+#ifdef CONFIG_NO_IDLE_HZ
+	.dyn_tick	= &sa1100_dyn_tick,
+#endif
 };