Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/davej/cpufreq
[linux-2.6] / arch / m68knommu / platform / coldfire / 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 5208 CPUs. No doubt newer ColdFire
7  *               family members will probably use it too.
8  *
9  *      Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
10  *      Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
11  */
12
13 /***************************************************************************/
14
15 #include <linux/kernel.h>
16 #include <linux/sched.h>
17 #include <linux/param.h>
18 #include <linux/init.h>
19 #include <linux/interrupt.h>
20 #include <linux/irq.h>
21 #include <linux/clocksource.h>
22 #include <asm/machdep.h>
23 #include <asm/io.h>
24 #include <asm/coldfire.h>
25 #include <asm/mcfpit.h>
26 #include <asm/mcfsim.h>
27
28 /***************************************************************************/
29
30 /*
31  *      By default use timer1 as the system clock timer.
32  */
33 #define FREQ    ((MCF_CLK / 2) / 64)
34 #define TA(a)   (MCF_IPSBAR + MCFPIT_BASE1 + (a))
35 #define INTC0   (MCF_IPSBAR + MCFICM_INTC0)
36
37 static u32 pit_cycles_per_jiffy;
38 static u32 pit_cnt;
39
40 /***************************************************************************/
41
42 static irqreturn_t pit_tick(int irq, void *dummy)
43 {
44         u16 pcsr;
45
46         /* Reset the ColdFire timer */
47         pcsr = __raw_readw(TA(MCFPIT_PCSR));
48         __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
49
50         pit_cnt += pit_cycles_per_jiffy;
51         return arch_timer_interrupt(irq, dummy);
52 }
53
54 /***************************************************************************/
55
56 static struct irqaction pit_irq = {
57         .name    = "timer",
58         .flags   = IRQF_DISABLED | IRQF_TIMER,
59         .handler = pit_tick,
60 };
61
62 /***************************************************************************/
63
64 static cycle_t pit_read_clk(void)
65 {
66         unsigned long flags;
67         u32 cycles;
68         u16 pcntr;
69
70         local_irq_save(flags);
71         pcntr = __raw_readw(TA(MCFPIT_PCNTR));
72         cycles = pit_cnt;
73         local_irq_restore(flags);
74
75         return cycles + pit_cycles_per_jiffy - pcntr;
76 }
77
78 /***************************************************************************/
79
80 static struct clocksource pit_clk = {
81         .name   = "pit",
82         .rating = 250,
83         .read   = pit_read_clk,
84         .shift  = 20,
85         .mask   = CLOCKSOURCE_MASK(32),
86         .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
87 };
88
89 /***************************************************************************/
90
91 void hw_timer_init(void)
92 {
93         u32 imr;
94
95         setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
96
97         __raw_writeb(ICR_INTRCONF, INTC0 + MCFINTC_ICR0 + MCFINT_PIT1);
98         imr = __raw_readl(INTC0 + MCFPIT_IMR);
99         imr &= ~MCFPIT_IMR_IBIT;
100         __raw_writel(imr, INTC0 + MCFPIT_IMR);
101
102         /* Set up PIT timer 1 as poll clock */
103         pit_cycles_per_jiffy = FREQ / HZ;
104         __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR));
105         __raw_writew(pit_cycles_per_jiffy, TA(MCFPIT_PMR));
106         __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | MCFPIT_PCSR_OVW |
107                 MCFPIT_PCSR_RLD | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR));
108
109         pit_clk.mult = clocksource_hz2mult(FREQ, pit_clk.shift);
110         clocksource_register(&pit_clk);
111 }
112
113 /***************************************************************************/