summaryrefslogtreecommitdiff
path: root/arch/m68knommu/platform/coldfire/pit.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68knommu/platform/coldfire/pit.c')
-rw-r--r--arch/m68knommu/platform/coldfire/pit.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/arch/m68knommu/platform/coldfire/pit.c b/arch/m68knommu/platform/coldfire/pit.c
new file mode 100644
index 000000000000..173b754d1cda
--- /dev/null
+++ b/arch/m68knommu/platform/coldfire/pit.c
@@ -0,0 +1,97 @@
+/***************************************************************************/
+
+/*
+ * pit.c -- Freescale ColdFire PIT timer. Currently this type of
+ * hardware timer only exists in the Freescale ColdFire
+ * 5270/5271, 5282 and other CPUs.
+ *
+ * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
+ */
+
+/***************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/param.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/coldfire.h>
+#include <asm/mcfpit.h>
+#include <asm/mcfsim.h>
+
+/***************************************************************************/
+
+/*
+ * By default use timer1 as the system clock timer.
+ */
+#define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a))
+
+/***************************************************************************/
+
+static irqreturn_t hw_tick(int irq, void *dummy)
+{
+ unsigned short pcsr;
+
+ /* Reset the ColdFire timer */
+ pcsr = __raw_readw(TA(MCFPIT_PCSR));
+ __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
+
+ return arch_timer_interrupt(irq, dummy);
+}
+
+/***************************************************************************/
+
+static struct irqaction coldfire_pit_irq = {
+ .name = "timer",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = hw_tick,
+};
+
+void hw_timer_init(void)
+{
+ volatile unsigned char *icrp;
+ volatile unsigned long *imrp;
+
+ setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq);
+
+ icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
+ MCFINTC_ICR0 + MCFINT_PIT1);
+ *icrp = ICR_INTRCONF;
+
+ imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
+ *imrp &= ~MCFPIT_IMR_IBIT;
+
+ /* Set up PIT timer 1 as poll clock */
+ __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
+ __raw_writew(((MCF_CLK / 2) / 64) / HZ, TA(MCFPIT_PMR));
+ __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
+ MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
+}
+
+/***************************************************************************/
+
+unsigned long hw_timer_offset(void)
+{
+ volatile unsigned long *ipr;
+ unsigned long pmr, pcntr, offset;
+
+ ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
+
+ pmr = __raw_readw(TA(MCFPIT_PMR));
+ pcntr = __raw_readw(TA(MCFPIT_PCNTR));
+
+ /*
+ * If we are still in the first half of the upcount and a
+ * timer interrupt is pending, then add on a ticks worth of time.
+ */
+ offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr;
+ if ((offset < (1000000 / HZ / 2)) && (*ipr & MCFPIT_IMR_IBIT))
+ offset += 1000000 / HZ;
+ return offset;
+}
+
+/***************************************************************************/