blob: 4290638012e0ee3dfee426848fb8624bb8cb77e5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/***************************************************************************/
2
3/*
Greg Ungererb671b652006-06-26 10:33:10 +10004 * pit.c -- Freescale ColdFire PIT timer. Currently this type of
5 * hardware timer only exists in the Freescale ColdFire
Greg Ungerer8d80c5e2008-02-01 17:40:21 +10006 * 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire
7 * family members will probably use it too.
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
Greg Ungerer8d80c5e2008-02-01 17:40:21 +10009 * Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12
13/***************************************************************************/
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/kernel.h>
16#include <linux/sched.h>
17#include <linux/param.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
Greg Ungerer5c4525d2007-07-27 01:09:00 +100020#include <linux/irq.h>
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100021#include <linux/clocksource.h>
Greg Ungerer2f2c2672007-10-23 14:37:54 +100022#include <asm/machdep.h>
Greg Ungererb671b652006-06-26 10:33:10 +100023#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/coldfire.h>
25#include <asm/mcfpit.h>
26#include <asm/mcfsim.h>
27
28/***************************************************************************/
29
Greg Ungererb671b652006-06-26 10:33:10 +100030/*
31 * By default use timer1 as the system clock timer.
32 */
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100033#define FREQ ((MCF_CLK / 2) / 64)
Greg Ungererb671b652006-06-26 10:33:10 +100034#define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a))
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100035#define INTC0 (MCF_IPSBAR + MCFICM_INTC0)
36
37static u32 pit_cycles_per_jiffy;
38static u32 pit_cnt;
Greg Ungererb671b652006-06-26 10:33:10 +100039
40/***************************************************************************/
41
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100042static irqreturn_t pit_tick(int irq, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043{
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100044 u16 pcsr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 /* Reset the ColdFire timer */
Greg Ungererb671b652006-06-26 10:33:10 +100047 pcsr = __raw_readw(TA(MCFPIT_PCSR));
48 __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR));
Greg Ungerer2f2c2672007-10-23 14:37:54 +100049
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100050 pit_cnt += pit_cycles_per_jiffy;
Greg Ungerer2f2c2672007-10-23 14:37:54 +100051 return arch_timer_interrupt(irq, dummy);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052}
53
54/***************************************************************************/
55
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100056static struct irqaction pit_irq = {
Greg Ungerer2f2c2672007-10-23 14:37:54 +100057 .name = "timer",
58 .flags = IRQF_DISABLED | IRQF_TIMER,
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100059 .handler = pit_tick,
Greg Ungerer5c4525d2007-07-27 01:09:00 +100060};
61
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100062/***************************************************************************/
63
64static cycle_t pit_read_clk(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100066 unsigned long flags;
67 u32 cycles;
68 u16 pcntr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100070 local_irq_save(flags);
71 pcntr = __raw_readw(TA(MCFPIT_PCNTR));
72 cycles = pit_cnt;
73 local_irq_restore(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100075 return cycles + pit_cycles_per_jiffy - pcntr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070076}
77
78/***************************************************************************/
79
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100080static 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
91void hw_timer_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070092{
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100093 u32 imr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100095 setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Greg Ungerer8d80c5e2008-02-01 17:40:21 +100097 __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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Greg Ungerer8d80c5e2008-02-01 17:40:21 +1000102 /* 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
113/***************************************************************************/