aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-imx/time.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 18:40:39 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 18:40:39 -0500
commitea14fad0d416354a4e9bb1a04f32acba706f9548 (patch)
tree2c8acc5331f189aef1d40ddce3f40d6be9314e77 /arch/arm/mach-imx/time.c
parent6ee7e78e7c78d871409ad4df30551c9355be7d0e (diff)
parent6705cda24fad1cb0ac82ac4f312df8ec735b39b0 (diff)
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (76 commits) [ARM] 4002/1: S3C24XX: leave parent IRQs unmasked [ARM] 4001/1: S3C24XX: shorten reboot time [ARM] 3983/2: remove unused argument to __bug() [ARM] 4000/1: Osiris: add third serial port in [ARM] 3999/1: RX3715: suspend to RAM support [ARM] 3998/1: VR1000: LED platform devices [ARM] 3995/1: iop13xx: add iop13xx support [ARM] 3968/1: iop13xx: add iop13xx_defconfig [ARM] Update mach-types [ARM] Allow gcc to optimise arm_add_memory a little more [ARM] 3991/1: i.MX/MX1 high resolution time source [ARM] 3990/1: i.MX/MX1 more precise PLL decode [ARM] 3986/1: H1940: suspend to RAM support [ARM] 3985/1: ixp4xx clocksource cleanup [ARM] 3984/1: ixp4xx/nslu2: Fix disk LED numbering (take 2) [ARM] 3994/1: ixp23xx: fix handling of pci master aborts [ARM] 3981/1: sched_clock for PXA2xx [ARM] 3980/1: extend the ARM Versatile sched_clock implementation from 32 to 63 bit [ARM] 3979/1: extend the SA11x0 sched_clock implementation from 32 to 63 bit period [ARM] 3978/1: macro to provide a 63-bit value from a 32-bit hardware counter ...
Diffstat (limited to 'arch/arm/mach-imx/time.c')
-rw-r--r--arch/arm/mach-imx/time.c86
1 files changed, 50 insertions, 36 deletions
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 8ae4a2c5066f..40039b2a90b3 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -14,6 +14,7 @@
14#include <linux/interrupt.h> 14#include <linux/interrupt.h>
15#include <linux/irq.h> 15#include <linux/irq.h>
16#include <linux/time.h> 16#include <linux/time.h>
17#include <linux/clocksource.h>
17 18
18#include <asm/hardware.h> 19#include <asm/hardware.h>
19#include <asm/io.h> 20#include <asm/io.h>
@@ -24,33 +25,7 @@
24/* Use timer 1 as system timer */ 25/* Use timer 1 as system timer */
25#define TIMER_BASE IMX_TIM1_BASE 26#define TIMER_BASE IMX_TIM1_BASE
26 27
27/* 28static unsigned long evt_diff;
28 * Returns number of us since last clock interrupt. Note that interrupts
29 * will have been disabled by do_gettimeoffset()
30 */
31static unsigned long imx_gettimeoffset(void)
32{
33 unsigned long ticks;
34
35 /*
36 * Get the current number of ticks. Note that there is a race
37 * condition between us reading the timer and checking for
38 * an interrupt. We get around this by ensuring that the
39 * counter has not reloaded between our two reads.
40 */
41 ticks = IMX_TCN(TIMER_BASE);
42
43 /*
44 * Interrupt pending? If so, we've reloaded once already.
45 */
46 if (IMX_TSTAT(TIMER_BASE) & TSTAT_COMP)
47 ticks += LATCH;
48
49 /*
50 * Convert the ticks to usecs
51 */
52 return (1000000 / CLK32) * ticks;
53}
54 29
55/* 30/*
56 * IRQ handler for the timer 31 * IRQ handler for the timer
@@ -58,14 +33,23 @@ static unsigned long imx_gettimeoffset(void)
58static irqreturn_t 33static irqreturn_t
59imx_timer_interrupt(int irq, void *dev_id) 34imx_timer_interrupt(int irq, void *dev_id)
60{ 35{
61 write_seqlock(&xtime_lock); 36 uint32_t tstat;
62 37
63 /* clear the interrupt */ 38 /* clear the interrupt */
64 if (IMX_TSTAT(TIMER_BASE)) 39 tstat = IMX_TSTAT(TIMER_BASE);
65 IMX_TSTAT(TIMER_BASE) = 0; 40 IMX_TSTAT(TIMER_BASE) = 0;
41
42 if (tstat & TSTAT_COMP) {
43 do {
44
45 write_seqlock(&xtime_lock);
46 timer_tick();
47 write_sequnlock(&xtime_lock);
48 IMX_TCMP(TIMER_BASE) += evt_diff;
66 49
67 timer_tick(); 50 } while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE)
68 write_sequnlock(&xtime_lock); 51 - IMX_TCN(TIMER_BASE)) < 0));
52 }
69 53
70 return IRQ_HANDLED; 54 return IRQ_HANDLED;
71} 55}
@@ -77,9 +61,9 @@ static struct irqaction imx_timer_irq = {
77}; 61};
78 62
79/* 63/*
80 * Set up timer interrupt, and return the current time in seconds. 64 * Set up timer hardware into expected mode and state.
81 */ 65 */
82static void __init imx_timer_init(void) 66static void __init imx_timer_hardware_init(void)
83{ 67{
84 /* 68 /*
85 * Initialise to a known state (all timers off, and timing reset) 69 * Initialise to a known state (all timers off, and timing reset)
@@ -87,7 +71,38 @@ static void __init imx_timer_init(void)
87 IMX_TCTL(TIMER_BASE) = 0; 71 IMX_TCTL(TIMER_BASE) = 0;
88 IMX_TPRER(TIMER_BASE) = 0; 72 IMX_TPRER(TIMER_BASE) = 0;
89 IMX_TCMP(TIMER_BASE) = LATCH - 1; 73 IMX_TCMP(TIMER_BASE) = LATCH - 1;
90 IMX_TCTL(TIMER_BASE) = TCTL_CLK_32 | TCTL_IRQEN | TCTL_TEN; 74
75 IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_IRQEN | TCTL_TEN;
76 evt_diff = LATCH;
77}
78
79cycle_t imx_get_cycles(void)
80{
81 return IMX_TCN(TIMER_BASE);
82}
83
84static struct clocksource clocksource_imx = {
85 .name = "imx_timer1",
86 .rating = 200,
87 .read = imx_get_cycles,
88 .mask = 0xFFFFFFFF,
89 .shift = 20,
90 .is_continuous = 1,
91};
92
93static int __init imx_clocksource_init(void)
94{
95 clocksource_imx.mult =
96 clocksource_hz2mult(imx_get_perclk1(), clocksource_imx.shift);
97 clocksource_register(&clocksource_imx);
98
99 return 0;
100}
101
102static void __init imx_timer_init(void)
103{
104 imx_timer_hardware_init();
105 imx_clocksource_init();
91 106
92 /* 107 /*
93 * Make irqs happen for the system timer 108 * Make irqs happen for the system timer
@@ -97,5 +112,4 @@ static void __init imx_timer_init(void)
97 112
98struct sys_timer imx_timer = { 113struct sys_timer imx_timer = {
99 .init = imx_timer_init, 114 .init = imx_timer_init,
100 .offset = imx_gettimeoffset,
101}; 115};