/home/lenb/src/to-akpm branch 'acpi-2.6.12'
[sfrench/cifs-2.6.git] / arch / arm / mach-aaec2000 / core.c
1 /*
2  *  linux/arch/arm/mach-aaec2000/core.c
3  *
4  *  Code common to all AAEC-2000 machines
5  *
6  *  Copyright (c) 2005 Nicolas Bellido Y Ortega
7  *
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.
11  */
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>
21
22 #include <asm/hardware.h>
23 #include <asm/irq.h>
24
25 #include <asm/mach/irq.h>
26 #include <asm/mach/time.h>
27 #include <asm/mach/map.h>
28
29 /*
30  * Common I/O mapping:
31  *
32  * Static virtual address mappings are as follow:
33  *
34  * 0xf8000000-0xf8001ffff: Devices connected to APB bus
35  * 0xf8002000-0xf8003ffff: Devices connected to AHB bus
36  *
37  * Below 0xe8000000 is reserved for vm allocation.
38  *
39  * The machine specific code must provide the extra mapping beside the
40  * default mapping provided here.
41  */
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 }
46 };
47
48 void __init aaec2000_map_io(void)
49 {
50         iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
51 }
52
53 /*
54  * Interrupt handling routines
55  */
56 static void aaec2000_int_ack(unsigned int irq)
57 {
58         IRQ_INTSR = 1 << irq;
59 }
60
61 static void aaec2000_int_mask(unsigned int irq)
62 {
63         IRQ_INTENC |= (1 << irq);
64 }
65
66 static void aaec2000_int_unmask(unsigned int irq)
67 {
68         IRQ_INTENS |= (1 << irq);
69 }
70
71 static struct irqchip aaec2000_irq_chip = {
72         .ack    = aaec2000_int_ack,
73         .mask   = aaec2000_int_mask,
74         .unmask = aaec2000_int_unmask,
75 };
76
77 void __init aaec2000_init_irq(void)
78 {
79         unsigned int i;
80
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);
85         }
86
87         /* Disable all interrupts */
88         IRQ_INTENC = 0xffffffff;
89
90         /* Clear any pending interrupts */
91         IRQ_INTSR = IRQ_INTSR;
92 }
93
94 /*
95  * Time keeping
96  */
97 /* IRQs are disabled before entering here from do_gettimeofday() */
98 static unsigned long aaec2000_gettimeoffset(void)
99 {
100         unsigned long ticks_to_match, elapsed, usec;
101
102         /* Get ticks before next timer match */
103         ticks_to_match = TIMER1_LOAD - TIMER1_VAL;
104
105         /* We need elapsed ticks since last match */
106         elapsed = LATCH - ticks_to_match;
107
108         /* Now, convert them to usec */
109         usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
110
111         return usec;
112 }
113
114 /* We enter here with IRQs enabled */
115 static irqreturn_t
116 aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
117 {
118         /* TODO: Check timer accuracy */
119         write_seqlock(&xtime_lock);
120
121         timer_tick(regs);
122         TIMER1_CLEAR = 1;
123
124         write_sequnlock(&xtime_lock);
125
126         return IRQ_HANDLED;
127 }
128
129 static struct irqaction aaec2000_timer_irq = {
130         .name           = "AAEC-2000 Timer Tick",
131         .flags          = SA_INTERRUPT | SA_TIMER,
132         .handler        = aaec2000_timer_interrupt,
133 };
134
135 static void __init aaec2000_timer_init(void)
136 {
137         /* Disable timer 1 */
138         TIMER1_CTRL = 0;
139
140         /* We have somehow to generate a 100Hz clock.
141          * We then use the 508KHz timer in periodic mode.
142          */
143         TIMER1_LOAD = LATCH;
144         TIMER1_CLEAR = 1; /* Clear interrupt */
145
146         setup_irq(INT_TMR1_OFL, &aaec2000_timer_irq);
147
148         TIMER1_CTRL = TIMER_CTRL_ENABLE |
149                         TIMER_CTRL_PERIODIC |
150                         TIMER_CTRL_CLKSEL_508K;
151 }
152
153 struct sys_timer aaec2000_timer = {
154         .init           = aaec2000_timer_init,
155         .offset         = aaec2000_gettimeoffset,
156 };
157