m68knommu: MCF5307 PIT GENERIC_CLOCKEVENTS support

The PIT code has been changed in order to suppport GENERIC_CLOCKEVENTS.
The priority of the PIT clocksource has been decreased in favor of the
DMA timer.

pit_cycles_per_jiffy become a constant (PIT_CYCLES_PER_JIFFY) because it
is known at compile time and does not change afterwards.

Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: Sebastian Siewior <bigeasy@linutronix.de>
Signed-off-by: Greg Ungerer <gerg@uclinux.org>
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index bfd3530..2e7515e 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -66,6 +66,10 @@
 	bool
 	default y
 
+config GENERIC_CLOCKEVENTS
+	bool
+	default n
+
 config NO_IOPORT
 	def_bool y
 
@@ -112,11 +116,13 @@
 
 config M520x
 	bool "MCF520x"
+	select GENERIC_CLOCKEVENTS
 	help
 	   Freescale Coldfire 5207/5208 processor support.
 
 config M523x
 	bool "MCF523x"
+	select GENERIC_CLOCKEVENTS
 	help
 	  Freescale Coldfire 5230/1/2/4/5 processor support
 
@@ -142,6 +148,7 @@
 
 config M528x
 	bool "MCF528x"
+	select GENERIC_CLOCKEVENTS
 	help
 	  Motorola ColdFire 5280/5282 processor support.
 
@@ -165,6 +172,7 @@
 config M527x
 	bool
 	depends on (M5271 || M5275)
+	select GENERIC_CLOCKEVENTS
 	default y
 
 config COLDFIRE
@@ -678,6 +686,9 @@
 if COLDFIRE
 source "kernel/Kconfig.preempt"
 endif
+
+source "kernel/time/Kconfig"
+
 source "mm/Kconfig"
 
 endmenu
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index 67944aa..d182b2f 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -33,6 +33,7 @@
 	return -1;
 }
 
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
@@ -54,6 +55,7 @@
 #endif
 	return(IRQ_HANDLED);
 }
+#endif
 
 static unsigned long read_rtc_mmss(void)
 {
diff --git a/arch/m68knommu/platform/coldfire/pit.c b/arch/m68knommu/platform/coldfire/pit.c
index 4290638..c5b9167 100644
--- a/arch/m68knommu/platform/coldfire/pit.c
+++ b/arch/m68knommu/platform/coldfire/pit.c
@@ -18,7 +18,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/clocksource.h>
+#include <linux/clockchips.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/coldfire.h>
@@ -33,22 +33,86 @@
 #define	FREQ	((MCF_CLK / 2) / 64)
 #define	TA(a)	(MCF_IPSBAR + MCFPIT_BASE1 + (a))
 #define	INTC0	(MCF_IPSBAR + MCFICM_INTC0)
+#define PIT_CYCLES_PER_JIFFY (FREQ / HZ)
 
-static u32 pit_cycles_per_jiffy;
 static u32 pit_cnt;
 
+/*
+ * Initialize the PIT timer.
+ *
+ * This is also called after resume to bring the PIT into operation again.
+ */
+
+static void init_cf_pit_timer(enum clock_event_mode mode,
+                             struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+
+		__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+		__raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR));
+		__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
+				MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \
+				MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
+		break;
+
+	case CLOCK_EVT_MODE_SHUTDOWN:
+	case CLOCK_EVT_MODE_UNUSED:
+
+		__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+
+		__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+		__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \
+				MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \
+				TA(MCFPIT_PCSR));
+		break;
+
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here */
+		break;
+	}
+}
+
+/*
+ * Program the next event in oneshot mode
+ *
+ * Delta is given in PIT ticks
+ */
+static int cf_pit_next_event(unsigned long delta,
+		struct clock_event_device *evt)
+{
+	__raw_writew(delta, TA(MCFPIT_PMR));
+	return 0;
+}
+
+struct clock_event_device cf_pit_clockevent = {
+	.name		= "pit",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode	= init_cf_pit_timer,
+	.set_next_event	= cf_pit_next_event,
+	.shift		= 32,
+	.irq		= MCFINT_VECBASE + MCFINT_PIT1,
+};
+
+
+
 /***************************************************************************/
 
 static irqreturn_t pit_tick(int irq, void *dummy)
 {
+	struct clock_event_device *evt = &cf_pit_clockevent;
 	u16 pcsr;
 
 	/* Reset the ColdFire timer */
 	pcsr = __raw_readw(TA(MCFPIT_PCSR));
 	__raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
 
-	pit_cnt += pit_cycles_per_jiffy;
-	return arch_timer_interrupt(irq, dummy);
+	pit_cnt += PIT_CYCLES_PER_JIFFY;
+	evt->event_handler(evt);
+	return IRQ_HANDLED;
 }
 
 /***************************************************************************/
@@ -72,14 +136,14 @@
 	cycles = pit_cnt;
 	local_irq_restore(flags);
 
-	return cycles + pit_cycles_per_jiffy - pcntr;
+	return cycles + PIT_CYCLES_PER_JIFFY - pcntr;
 }
 
 /***************************************************************************/
 
 static struct clocksource pit_clk = {
 	.name	= "pit",
-	.rating	= 250,
+	.rating	= 100,
 	.read	= pit_read_clk,
 	.shift	= 20,
 	.mask	= CLOCKSOURCE_MASK(32),
@@ -92,6 +156,14 @@
 {
 	u32 imr;
 
+	cf_pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+	cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32);
+	cf_pit_clockevent.max_delta_ns =
+		clockevent_delta2ns(0xFFFF, &cf_pit_clockevent);
+	cf_pit_clockevent.min_delta_ns =
+		clockevent_delta2ns(0x3f, &cf_pit_clockevent);
+	clockevents_register_device(&cf_pit_clockevent);
+
 	setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
 
 	__raw_writeb(ICR_INTRCONF, INTC0 + MCFINTC_ICR0 + MCFINT_PIT1);
@@ -99,13 +171,6 @@
 	imr &= ~MCFPIT_IMR_IBIT;
 	__raw_writel(imr, INTC0 + MCFPIT_IMR);
 
-	/* Set up PIT timer 1 as poll clock */
-	pit_cycles_per_jiffy = FREQ / HZ;
-	__raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
-	__raw_writew(pit_cycles_per_jiffy, TA(MCFPIT_PMR));
-	__raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
-		MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
-
 	pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
 	clocksource_register(&pit_clk);
 }