[PATCH] ARM: Add SA_TIMER flag to timer interrupts
[linux-2.6/mini2440.git] / arch / arm / mach-aaec2000 / core.c
blobaece0cd4f0a3f324cb203476db3d0bc9921794a1
1 /*
2 * linux/arch/arm/mach-aaec2000/core.c
4 * Code common to all AAEC-2000 machines
6 * Copyright (c) 2005 Nicolas Bellido Y Ortega
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 #include <linux/config.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/list.h>
17 #include <linux/errno.h>
18 #include <linux/interrupt.h>
19 #include <linux/timex.h>
20 #include <linux/signal.h>
22 #include <asm/hardware.h>
23 #include <asm/irq.h>
25 #include <asm/mach/irq.h>
26 #include <asm/mach/time.h>
27 #include <asm/mach/map.h>
30 * Common I/O mapping:
32 * Static virtual address mappings are as follow:
34 * 0xf8000000-0xf8001ffff: Devices connected to APB bus
35 * 0xf8002000-0xf8003ffff: Devices connected to AHB bus
37 * Below 0xe8000000 is reserved for vm allocation.
39 * The machine specific code must provide the extra mapping beside the
40 * default mapping provided here.
42 static struct map_desc standard_io_desc[] __initdata = {
43 /* virtual physical length type */
44 { VIO_APB_BASE, PIO_APB_BASE, IO_APB_LENGTH, MT_DEVICE },
45 { VIO_AHB_BASE, PIO_AHB_BASE, IO_AHB_LENGTH, MT_DEVICE }
48 void __init aaec2000_map_io(void)
50 iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
54 * Interrupt handling routines
56 static void aaec2000_int_ack(unsigned int irq)
58 IRQ_INTSR = 1 << irq;
61 static void aaec2000_int_mask(unsigned int irq)
63 IRQ_INTENC |= (1 << irq);
66 static void aaec2000_int_unmask(unsigned int irq)
68 IRQ_INTENS |= (1 << irq);
71 static struct irqchip aaec2000_irq_chip = {
72 .ack = aaec2000_int_ack,
73 .mask = aaec2000_int_mask,
74 .unmask = aaec2000_int_unmask,
77 void __init aaec2000_init_irq(void)
79 unsigned int i;
81 for (i = 0; i < NR_IRQS; i++) {
82 set_irq_handler(i, do_level_IRQ);
83 set_irq_chip(i, &aaec2000_irq_chip);
84 set_irq_flags(i, IRQF_VALID);
87 /* Disable all interrupts */
88 IRQ_INTENC = 0xffffffff;
90 /* Clear any pending interrupts */
91 IRQ_INTSR = IRQ_INTSR;
95 * Time keeping
97 /* IRQs are disabled before entering here from do_gettimeofday() */
98 static unsigned long aaec2000_gettimeoffset(void)
100 unsigned long ticks_to_match, elapsed, usec;
102 /* Get ticks before next timer match */
103 ticks_to_match = TIMER1_LOAD - TIMER1_VAL;
105 /* We need elapsed ticks since last match */
106 elapsed = LATCH - ticks_to_match;
108 /* Now, convert them to usec */
109 usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
111 return usec;
114 /* We enter here with IRQs enabled */
115 static irqreturn_t
116 aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
118 /* TODO: Check timer accuracy */
119 write_seqlock(&xtime_lock);
121 timer_tick(regs);
122 TIMER1_CLEAR = 1;
124 write_sequnlock(&xtime_lock);
126 return IRQ_HANDLED;
129 static struct irqaction aaec2000_timer_irq = {
130 .name = "AAEC-2000 Timer Tick",
131 .flags = SA_INTERRUPT | SA_TIMER,
132 .handler = aaec2000_timer_interrupt,
135 static void __init aaec2000_timer_init(void)
137 /* Disable timer 1 */
138 TIMER1_CTRL = 0;
140 /* We have somehow to generate a 100Hz clock.
141 * We then use the 508KHz timer in periodic mode.
143 TIMER1_LOAD = LATCH;
144 TIMER1_CLEAR = 1; /* Clear interrupt */
146 setup_irq(INT_TMR1_OFL, &aaec2000_timer_irq);
148 TIMER1_CTRL = TIMER_CTRL_ENABLE |
149 TIMER_CTRL_PERIODIC |
150 TIMER_CTRL_CLKSEL_508K;
153 struct sys_timer aaec2000_timer = {
154 .init = aaec2000_timer_init,
155 .offset = aaec2000_gettimeoffset,