Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /***************************************************************************/ |
| 2 | |
| 3 | /* |
Greg Ungerer | b671b65 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 4 | * pit.c -- Freescale ColdFire PIT timer. Currently this type of |
| 5 | * hardware timer only exists in the Freescale ColdFire |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 6 | * 5270/5271, 5282 and 5208 CPUs. No doubt newer ColdFire |
| 7 | * family members will probably use it too. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 8 | * |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 9 | * Copyright (C) 1999-2008, Greg Ungerer (gerg@snapgear.com) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | * Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 11 | */ |
| 12 | |
| 13 | /***************************************************************************/ |
| 14 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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> |
Greg Ungerer | 5c4525d | 2007-07-27 01:09:00 +1000 | [diff] [blame] | 20 | #include <linux/irq.h> |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 21 | #include <linux/clocksource.h> |
Greg Ungerer | 2f2c267 | 2007-10-23 14:37:54 +1000 | [diff] [blame] | 22 | #include <asm/machdep.h> |
Greg Ungerer | b671b65 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 23 | #include <asm/io.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | #include <asm/coldfire.h> |
| 25 | #include <asm/mcfpit.h> |
| 26 | #include <asm/mcfsim.h> |
| 27 | |
| 28 | /***************************************************************************/ |
| 29 | |
Greg Ungerer | b671b65 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 30 | /* |
| 31 | * By default use timer1 as the system clock timer. |
| 32 | */ |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 33 | #define FREQ ((MCF_CLK / 2) / 64) |
Greg Ungerer | b671b65 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 34 | #define TA(a) (MCF_IPSBAR + MCFPIT_BASE1 + (a)) |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 35 | #define INTC0 (MCF_IPSBAR + MCFICM_INTC0) |
| 36 | |
| 37 | static u32 pit_cycles_per_jiffy; |
| 38 | static u32 pit_cnt; |
Greg Ungerer | b671b65 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 39 | |
| 40 | /***************************************************************************/ |
| 41 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 42 | static irqreturn_t pit_tick(int irq, void *dummy) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | { |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 44 | u16 pcsr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | |
| 46 | /* Reset the ColdFire timer */ |
Greg Ungerer | b671b65 | 2006-06-26 10:33:10 +1000 | [diff] [blame] | 47 | pcsr = __raw_readw(TA(MCFPIT_PCSR)); |
| 48 | __raw_writew(pcsr | MCFPIT_PCSR_PIF, TA(MCFPIT_PCSR)); |
Greg Ungerer | 2f2c267 | 2007-10-23 14:37:54 +1000 | [diff] [blame] | 49 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 50 | pit_cnt += pit_cycles_per_jiffy; |
Greg Ungerer | 2f2c267 | 2007-10-23 14:37:54 +1000 | [diff] [blame] | 51 | return arch_timer_interrupt(irq, dummy); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | /***************************************************************************/ |
| 55 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 56 | static struct irqaction pit_irq = { |
Greg Ungerer | 2f2c267 | 2007-10-23 14:37:54 +1000 | [diff] [blame] | 57 | .name = "timer", |
| 58 | .flags = IRQF_DISABLED | IRQF_TIMER, |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 59 | .handler = pit_tick, |
Greg Ungerer | 5c4525d | 2007-07-27 01:09:00 +1000 | [diff] [blame] | 60 | }; |
| 61 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 62 | /***************************************************************************/ |
| 63 | |
| 64 | static cycle_t pit_read_clk(void) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | { |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 66 | unsigned long flags; |
| 67 | u32 cycles; |
| 68 | u16 pcntr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 70 | local_irq_save(flags); |
| 71 | pcntr = __raw_readw(TA(MCFPIT_PCNTR)); |
| 72 | cycles = pit_cnt; |
| 73 | local_irq_restore(flags); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 75 | return cycles + pit_cycles_per_jiffy - pcntr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | /***************************************************************************/ |
| 79 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 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) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 | { |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 93 | u32 imr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 94 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 95 | setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &pit_irq); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 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); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 101 | |
Greg Ungerer | 8d80c5e | 2008-02-01 17:40:21 +1000 | [diff] [blame^] | 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); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | } |
| 112 | |
| 113 | /***************************************************************************/ |