2 * linux/arch/arm/mach-iop3xx/time-iq80310.c
4 * Timer functions for IQ80310 onboard timer
6 * Author: Nicolas Pitre
7 * Copyright: (C) 2001 MontaVista Software Inc.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
14 #include <linux/kernel.h>
15 #include <linux/interrupt.h>
16 #include <linux/time.h>
17 #include <linux/init.h>
18 #include <linux/timex.h>
20 #include <asm/hardware.h>
23 #include <asm/uaccess.h>
24 #include <asm/mach-types.h>
25 #include <asm/mach/irq.h>
27 static void iq80310_write_timer (u_long val)
29 volatile u_char *la0 = (volatile u_char *)IQ80310_TIMER_LA0;
30 volatile u_char *la1 = (volatile u_char *)IQ80310_TIMER_LA1;
31 volatile u_char *la2 = (volatile u_char *)IQ80310_TIMER_LA2;
35 *la2 = (val >> 16) & 0x3f;
38 static u_long iq80310_read_timer (void)
40 volatile u_char *la0 = (volatile u_char *)IQ80310_TIMER_LA0;
41 volatile u_char *la1 = (volatile u_char *)IQ80310_TIMER_LA1;
42 volatile u_char *la2 = (volatile u_char *)IQ80310_TIMER_LA2;
43 volatile u_char *la3 = (volatile u_char *)IQ80310_TIMER_LA3;
44 u_long b0, b1, b2, b3, val;
46 b0 = *la0; b1 = *la1; b2 = *la2; b3 = *la3;
47 b0 = (((b0 & 0x40) >> 1) | (b0 & 0x1f));
48 b1 = (((b1 & 0x40) >> 1) | (b1 & 0x1f));
49 b2 = (((b2 & 0x40) >> 1) | (b2 & 0x1f));
51 val = ((b0 << 0) | (b1 << 6) | (b2 << 12) | (b3 << 18));
56 * IRQs are disabled before entering here from do_gettimeofday().
57 * Note that the counter may wrap. When it does, 'elapsed' will
58 * be small, but we will have a pending interrupt.
60 static unsigned long iq80310_gettimeoffset (void)
62 unsigned long elapsed, usec;
63 unsigned int stat1, stat2;
65 stat1 = *(volatile u8 *)IQ80310_INT_STAT;
66 elapsed = iq80310_read_timer();
67 stat2 = *(volatile u8 *)IQ80310_INT_STAT;
70 * If an interrupt was pending before we read the timer,
71 * we've already wrapped. Factor this into the time.
72 * If an interrupt was pending after we read the timer,
73 * it may have wrapped between checking the interrupt
74 * status and reading the timer. Re-read the timer to
75 * be sure its value is after the wrap.
80 elapsed = LATCH + iq80310_read_timer();
83 * Now convert them to usec.
85 usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
92 iq80310_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
94 volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN;
96 /* clear timer interrupt */
105 extern unsigned long (*gettimeoffset)(void);
107 static struct irqaction timer_irq = {
109 .handler = iq80310_timer_interrupt,
113 void __init time_init(void)
115 volatile u_char *timer_en = (volatile u_char *)IQ80310_TIMER_EN;
117 gettimeoffset = iq80310_gettimeoffset;
119 setup_irq(IRQ_IQ80310_TIMER, &timer_irq);
122 iq80310_write_timer(LATCH);