aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-at91rm9200/time.c
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2006-06-20 14:48:18 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-06-20 14:48:18 -0400
commit695a9d236a6fd5a60557a02eff612880c37fe731 (patch)
tree0ca809031f5f7139568914fe73ab5e244532aaf8 /arch/arm/mach-at91rm9200/time.c
parentc322e24b40b83bbdfa7c269bc0105e76a39e627f (diff)
parent55c20c0af7fe7d5d09af4addfafcfe3bdc500f5d (diff)
Merge AT91 branch
Diffstat (limited to 'arch/arm/mach-at91rm9200/time.c')
-rw-r--r--arch/arm/mach-at91rm9200/time.c57
1 files changed, 36 insertions, 21 deletions
diff --git a/arch/arm/mach-at91rm9200/time.c b/arch/arm/mach-at91rm9200/time.c
index 7ffcf443b99f..fc2d7d5e4637 100644
--- a/arch/arm/mach-at91rm9200/time.c
+++ b/arch/arm/mach-at91rm9200/time.c
@@ -31,6 +31,8 @@
31#include <asm/irq.h> 31#include <asm/irq.h>
32#include <asm/mach/time.h> 32#include <asm/mach/time.h>
33 33
34static unsigned long last_crtr;
35
34/* 36/*
35 * The ST_CRTR is updated asynchronously to the master clock. It is therefore 37 * The ST_CRTR is updated asynchronously to the master clock. It is therefore
36 * necessary to read it twice (with the same value) to ensure accuracy. 38 * necessary to read it twice (with the same value) to ensure accuracy.
@@ -56,7 +58,7 @@ static unsigned long at91rm9200_gettimeoffset(void)
56{ 58{
57 unsigned long elapsed; 59 unsigned long elapsed;
58 60
59 elapsed = (read_CRTR() - at91_sys_read(AT91_ST_RTAR)) & AT91_ST_ALMV; 61 elapsed = (read_CRTR() - last_crtr) & AT91_ST_ALMV;
60 62
61 return (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH; 63 return (unsigned long)(elapsed * (tick_nsec / 1000)) / LATCH;
62} 64}
@@ -66,15 +68,12 @@ static unsigned long at91rm9200_gettimeoffset(void)
66 */ 68 */
67static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 69static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
68{ 70{
69 unsigned long rtar;
70
71 if (at91_sys_read(AT91_ST_SR) & AT91_ST_PITS) { /* This is a shared interrupt */ 71 if (at91_sys_read(AT91_ST_SR) & AT91_ST_PITS) { /* This is a shared interrupt */
72 write_seqlock(&xtime_lock); 72 write_seqlock(&xtime_lock);
73 73
74 while (((read_CRTR() - at91_sys_read(AT91_ST_RTAR)) & AT91_ST_ALMV) >= LATCH) { 74 while (((read_CRTR() - last_crtr) & AT91_ST_ALMV) >= LATCH) {
75 timer_tick(regs); 75 timer_tick(regs);
76 rtar = (at91_sys_read(AT91_ST_RTAR) + LATCH) & AT91_ST_ALMV; 76 last_crtr = (last_crtr + LATCH) & AT91_ST_ALMV;
77 at91_sys_write(AT91_ST_RTAR, rtar);
78 } 77 }
79 78
80 write_sequnlock(&xtime_lock); 79 write_sequnlock(&xtime_lock);
@@ -87,10 +86,24 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id, struct pt_r
87 86
88static struct irqaction at91rm9200_timer_irq = { 87static struct irqaction at91rm9200_timer_irq = {
89 .name = "at91_tick", 88 .name = "at91_tick",
90 .flags = SA_SHIRQ | SA_INTERRUPT, 89 .flags = SA_SHIRQ | SA_INTERRUPT | SA_TIMER,
91 .handler = at91rm9200_timer_interrupt 90 .handler = at91rm9200_timer_interrupt
92}; 91};
93 92
93void at91rm9200_timer_reset(void)
94{
95 last_crtr = 0;
96
97 /* Real time counter incremented every 30.51758 microseconds */
98 at91_sys_write(AT91_ST_RTMR, 1);
99
100 /* Set Period Interval timer */
101 at91_sys_write(AT91_ST_PIMR, LATCH);
102
103 /* Enable Period Interval Timer interrupt */
104 at91_sys_write(AT91_ST_IER, AT91_ST_PITS);
105}
106
94/* 107/*
95 * Set up timer interrupt. 108 * Set up timer interrupt.
96 */ 109 */
@@ -100,28 +113,30 @@ void __init at91rm9200_timer_init(void)
100 at91_sys_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS); 113 at91_sys_write(AT91_ST_IDR, AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
101 (void) at91_sys_read(AT91_ST_SR); /* Clear any pending interrupts */ 114 (void) at91_sys_read(AT91_ST_SR); /* Clear any pending interrupts */
102 115
103 /* 116 /* Make IRQs happen for the system timer */
104 * Make IRQs happen for the system timer.
105 */
106 setup_irq(AT91_ID_SYS, &at91rm9200_timer_irq); 117 setup_irq(AT91_ID_SYS, &at91rm9200_timer_irq);
107 118
108 /* Set initial alarm to 0 */
109 at91_sys_write(AT91_ST_RTAR, 0);
110
111 /* Real time counter incremented every 30.51758 microseconds */
112 at91_sys_write(AT91_ST_RTMR, 1);
113
114 /* Set Period Interval timer */
115 at91_sys_write(AT91_ST_PIMR, LATCH);
116
117 /* Change the kernel's 'tick' value to 10009 usec. (the default is 10000) */ 119 /* Change the kernel's 'tick' value to 10009 usec. (the default is 10000) */
118 tick_usec = (LATCH * 1000000) / CLOCK_TICK_RATE; 120 tick_usec = (LATCH * 1000000) / CLOCK_TICK_RATE;
119 121
120 /* Enable Period Interval Timer interrupt */ 122 /* Initialize and enable the timer interrupt */
121 at91_sys_write(AT91_ST_IER, AT91_ST_PITS); 123 at91rm9200_timer_reset();
124}
125
126#ifdef CONFIG_PM
127static void at91rm9200_timer_suspend(void)
128{
129 /* disable Period Interval Timer interrupt */
130 at91_sys_write(AT91_ST_IDR, AT91_ST_PITS);
122} 131}
132#else
133#define at91rm9200_timer_suspend NULL
134#endif
123 135
124struct sys_timer at91rm9200_timer = { 136struct sys_timer at91rm9200_timer = {
125 .init = at91rm9200_timer_init, 137 .init = at91rm9200_timer_init,
126 .offset = at91rm9200_gettimeoffset, 138 .offset = at91rm9200_gettimeoffset,
139 .suspend = at91rm9200_timer_suspend,
140 .resume = at91rm9200_timer_reset,
127}; 141};
142