e53c446d10e4d9cd2343293b82f0017756a23f58
[linux-2.6.git] / arch / m68knommu / platform / 5307 / pit.c
1 /***************************************************************************/
2
3 /*
4  *      pit.c -- Freescale ColdFire PIT timer. Currently this type of
5  *               hardware timer only exists in the Freescale ColdFire
6  *               5270/5271, 5282 and other CPUs.
7  *
8  *      Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
9  *      Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
10  */
11
12 /***************************************************************************/
13
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/param.h>
17 #include <linux/init.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <asm/io.h>
21 #include <asm/coldfire.h>
22 #include <asm/mcfpit.h>
23 #include <asm/mcfsim.h>
24
25 /***************************************************************************/
26
27 /*
28  *      By default use timer1 as the system clock timer.
29  */
30 #define TA(a)   (MCF_IPSBAR + MCFPIT_BASE1 + (a))
31
32 /***************************************************************************/
33
34 void coldfire_pit_tick(void)
35 {
36         unsigned short pcsr;
37
38         /* Reset the ColdFire timer */
39         pcsr = __raw_readw(TA(MCFPIT_PCSR));
40         __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
41 }
42
43 /***************************************************************************/
44
45 static struct irqaction coldfire_pit_irq = {
46         .name    = "timer",
47         .flags   = IRQF_DISABLED | IRQF_TIMER,
48 };
49
50 void coldfire_pit_init(irq_handler_t handler)
51 {
52         volatile unsigned char *icrp;
53         volatile unsigned long *imrp;
54
55         coldfire_pit_irq.handler = handler;
56         setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq);
57
58         icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
59                 MCFINTC_ICR0 + MCFINT_PIT1);
60         *icrp = ICR_INTRCONF;
61
62         imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
63         *imrp &= ~MCFPIT_IMR_IBIT;
64
65         /* Set up PIT timer 1 as poll clock */
66         __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
67         __raw_writew(((MCF_CLK / 2) / 64) / HZ, TA(MCFPIT_PMR));
68         __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
69                 MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
70 }
71
72 /***************************************************************************/
73
74 unsigned long coldfire_pit_offset(void)
75 {
76         volatile unsigned long *ipr;
77         unsigned long pmr, pcntr, offset;
78
79         ipr = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFPIT_IMR);
80
81         pmr = __raw_readw(TA(MCFPIT_PMR));
82         pcntr = __raw_readw(TA(MCFPIT_PCNTR));
83
84         /*
85          * If we are still in the first half of the upcount and a
86          * timer interupt is pending, then add on a ticks worth of time.
87          */
88         offset = ((pmr - pcntr) * (1000000 / HZ)) / pmr;
89         if ((offset < (1000000 / HZ / 2)) && (*ipr & MCFPIT_IMR_IBIT))
90                 offset += 1000000 / HZ;
91         return offset;  
92 }
93
94 /***************************************************************************/