v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / arch / arm / mach-sa1100 / neponset.c
1 /*
2  * linux/arch/arm/mach-sa1100/neponset.c
3  *
4  */
5
6 #include <linux/init.h>
7 #include <linux/sched.h>
8 #include <linux/interrupt.h>
9 #include <linux/ptrace.h>
10
11 #include <asm/hardware.h>
12 #include <asm/irq.h>
13 #include <asm/mach/map.h>
14 #include <asm/mach/irq.h>
15 #include <asm/arch/irq.h>
16 #include <asm/mach/serial_sa1100.h>
17 #include <linux/serial_core.h>
18
19 #include "sa1111.h"
20
21
22 /*
23  * Install handler for Neponset IRQ.  Yes, yes... we are way down the IRQ
24  * cascade which is not good for IRQ latency, but the hardware has been
25  * designed that way...
26  */
27
28 static void neponset_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
29 {
30         int irr;
31
32         for(;;){
33                 irr = IRR & (IRR_ETHERNET | IRR_USAR | IRR_SA1111);
34                 /* Let's have all active IRQ bits high.
35                  * Note: there is a typo in the Neponset user's guide
36                  * for the SA1111 IRR level.
37                  */
38                 irr ^= (IRR_ETHERNET | IRR_USAR);
39                 if (!irr) break;
40
41                 if( irr & IRR_ETHERNET )
42                         do_IRQ(NEPONSET_ETHERNET_IRQ, regs);
43
44                 if( irr & IRR_USAR )
45                         do_IRQ(NEPONSET_USAR_IRQ, regs);
46
47                 if( irr & IRR_SA1111 )
48                         sa1111_IRQ_demux(irq, dev_id, regs);
49         }
50 }
51
52 static struct irqaction neponset_irq = {
53         name:           "Neponset",
54         handler:        neponset_IRQ_demux,
55         flags:          SA_INTERRUPT
56 };
57
58 static void __init neponset_init_irq(void)
59 {
60         int irq;
61
62         sa1111_init_irq(-1);    /* SA1111 IRQ not routed to a GPIO */
63
64         /* setup extra Neponset IRQs */
65         irq = NEPONSET_ETHERNET_IRQ;
66         irq_desc[irq].valid     = 1;
67         irq_desc[irq].probe_ok  = 1;
68         irq = NEPONSET_USAR_IRQ;
69         irq_desc[irq].valid     = 1;
70         irq_desc[irq].probe_ok  = 1;
71         set_GPIO_IRQ_edge( GPIO_NEP_IRQ, GPIO_RISING_EDGE );
72         setup_arm_irq( IRQ_GPIO_NEP_IRQ, &neponset_irq );
73 }
74
75 static int __init neponset_init(void)
76 {
77         if (machine_has_neponset()) {
78                 LEDS = WHOAMI;
79
80                 if (sa1111_init() < 0)
81                         return -EINVAL;
82                 /*
83                  * Assabet is populated by default with two Samsung
84                  * KM416S8030T-G8
85                  * 128Mb SDRAMs, which are organized as 12-bit (row addr) x
86                  * 9-bit
87                  * (column addr), according to the data sheet. Apparently, the
88                  * bank selects factor into the row address, as Angel sets up
89                  * the
90                  * SA-1110 to use 14x9 addresses. The SDRAM datasheet specifies
91                  * that when running at 100-125MHz, the CAS latency for -8
92                  * parts
93                  * is 3 cycles, which is consistent with Angel.
94                  */
95                 SMCR = (SMCR_DTIM | SMCR_MBGE |
96                         FInsrt(FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), SMCR_DRAC) |
97                         ((FExtr(MDCNFG, MDCNFG_SA1110_TDL0)==3) ? SMCR_CLAT : 0));
98                 SKPCR |= SKPCR_DCLKEN;
99
100                 neponset_init_irq();
101         } else
102                 printk("Neponset expansion board not present\n");
103
104         return 0;
105 }
106
107 __initcall(neponset_init);
108
109 static struct map_desc neponset_io_desc[] __initdata = {
110  /* virtual     physical    length      domain     r  w  c  b */
111   { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
112   { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
113   LAST_DESC
114 };
115
116 static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
117 {
118         u_int mdm_ctl0 = MDM_CTL_0;
119
120         if (port->mapbase == _Ser1UTCR0) {
121                 if (mctrl & TIOCM_RTS)
122                         mdm_ctl0 &= ~MDM_CTL0_RTS2;
123                 else
124                         mdm_ctl0 |= MDM_CTL0_RTS2;
125
126                 if (mctrl & TIOCM_DTR)
127                         mdm_ctl0 &= ~MDM_CTL0_DTR2;
128                 else
129                         mdm_ctl0 |= MDM_CTL0_DTR2;
130         } else if (port->mapbase == _Ser3UTCR0) {
131                 if (mctrl & TIOCM_RTS)
132                         mdm_ctl0 &= ~MDM_CTL0_RTS1;
133                 else
134                         mdm_ctl0 |= MDM_CTL0_RTS1;
135
136                 if (mctrl & TIOCM_DTR)
137                         mdm_ctl0 &= ~MDM_CTL0_DTR1;
138                 else
139                         mdm_ctl0 |= MDM_CTL0_DTR1;
140         }
141
142         MDM_CTL_0 = mdm_ctl0;
143 }
144
145 static int neponset_get_mctrl(struct uart_port *port)
146 {
147         u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
148         u_int mdm_ctl1 = MDM_CTL_1;
149
150         if (port->mapbase == _Ser1UTCR0) {
151                 if (mdm_ctl1 & MDM_CTL1_DCD2)
152                         ret &= ~TIOCM_CD;
153                 if (mdm_ctl1 & MDM_CTL1_CTS2)
154                         ret &= ~TIOCM_CTS;
155                 if (mdm_ctl1 & MDM_CTL1_DSR2)
156                         ret &= ~TIOCM_DSR;
157         } else if (port->mapbase == _Ser3UTCR0) {
158                 if (mdm_ctl1 & MDM_CTL1_DCD1)
159                         ret &= ~TIOCM_CD;
160                 if (mdm_ctl1 & MDM_CTL1_CTS1)
161                         ret &= ~TIOCM_CTS;
162                 if (mdm_ctl1 & MDM_CTL1_DSR1)
163                         ret &= ~TIOCM_DSR;
164         }
165
166         return ret;
167 }
168
169 static struct sa1100_port_fns neponset_port_fns __initdata = {
170         set_mctrl:      neponset_set_mctrl,
171         get_mctrl:      neponset_get_mctrl,
172 };
173
174 void __init neponset_map_io(void)
175 {
176         iotable_init(neponset_io_desc);
177         if (machine_has_neponset())
178                 sa1100_register_uart_fns(&neponset_port_fns);
179 }