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 #include <linux/tty.h>
11 #include <linux/ioport.h>
12 #include <linux/serial_core.h>
13 #include <linux/list.h>
14 #include <linux/timer.h>
15
16 #include <asm/hardware.h>
17 #include <asm/irq.h>
18 #include <asm/mach/map.h>
19 #include <asm/mach/irq.h>
20 #include <asm/arch/irq.h>
21 #include <asm/mach/serial_sa1100.h>
22 #include <asm/arch/assabet.h>
23 #include <asm/hardware/sa1111.h>
24
25 #include "sa1111.h"
26
27
28 /*
29 * Install handler for Neponset IRQ. Yes, yes... we are way down the IRQ
30 * cascade which is not good for IRQ latency, but the hardware has been
31 * designed that way...
32 */
33
neponset_IRQ_demux(int irq,void * dev_id,struct pt_regs * regs)34 static void neponset_IRQ_demux( int irq, void *dev_id, struct pt_regs *regs )
35 {
36 int irr;
37
38 for(;;){
39 irr = IRR & (IRR_ETHERNET | IRR_USAR | IRR_SA1111);
40 /* Let's have all active IRQ bits high.
41 * Note: there is a typo in the Neponset user's guide
42 * for the SA1111 IRR level.
43 */
44 irr ^= (IRR_ETHERNET | IRR_USAR);
45 if (!irr) break;
46
47 if( irr & IRR_ETHERNET )
48 do_IRQ(IRQ_NEPONSET_SMC9196, regs);
49
50 if( irr & IRR_USAR )
51 do_IRQ(IRQ_NEPONSET_USAR, regs);
52
53 if( irr & IRR_SA1111 )
54 sa1111_IRQ_demux(irq, dev_id, regs);
55 }
56 }
57
58 static struct irqaction neponset_irq = {
59 .name = "Neponset",
60 .handler = neponset_IRQ_demux,
61 .flags = SA_INTERRUPT
62 };
63
neponset_init_irq(void)64 static void __init neponset_init_irq(void)
65 {
66 sa1111_init_irq(-1); /* SA1111 IRQ not routed to a GPIO */
67
68 /* setup extra Neponset IRQs */
69 irq_desc[IRQ_NEPONSET_SMC9196].valid = 1;
70 irq_desc[IRQ_NEPONSET_SMC9196].probe_ok = 1;
71 irq_desc[IRQ_NEPONSET_USAR].valid = 1;
72 irq_desc[IRQ_NEPONSET_USAR].probe_ok = 1;
73
74 set_GPIO_IRQ_edge(GPIO_GPIO25, GPIO_RISING_EDGE);
75 setup_arm_irq(IRQ_GPIO25, &neponset_irq);
76 }
77
neponset_init(void)78 static int __init neponset_init(void)
79 {
80 int ret;
81
82 /*
83 * The Neponset is only present on the Assabet machine type.
84 */
85 if (!machine_is_assabet())
86 return -ENODEV;
87
88 /*
89 * Ensure that the memory bus request/grant signals are setup,
90 * and the grant is held in its inactive state, whether or not
91 * we actually have a Neponset attached.
92 */
93 sa1110_mb_disable();
94
95 if (!machine_has_neponset()) {
96 printk(KERN_DEBUG "Neponset expansion board not present\n");
97 return -ENODEV;
98 }
99
100 if (WHOAMI != 0x11) {
101 printk(KERN_WARNING "Neponset board detected, but "
102 "wrong ID: %02x\n", WHOAMI);
103 return -ENODEV;
104 }
105
106 /*
107 * Disable GPIO 0/1 drivers so the buttons work on the module.
108 */
109 NCR_0 |= NCR_GP01_OFF;
110
111 /*
112 * Neponset has SA1111 connected to CS4. We know that after
113 * reset the chip will be configured for variable latency IO.
114 */
115 /* FIXME: setup MSC2 */
116
117 /*
118 * Probe for a SA1111.
119 */
120 ret = sa1111_probe(NEPONSET_SA1111_BASE);
121 if (ret < 0)
122 return ret;
123
124 /*
125 * We found it. Wake the chip up.
126 */
127 sa1111_wake();
128
129 /*
130 * The SDRAM configuration of the SA1110 and the SA1111 must
131 * match. This is very important to ensure that SA1111 accesses
132 * don't corrupt the SDRAM. Note that this ungates the SA1111's
133 * MBGNT signal, so we must have called sa1110_mb_disable()
134 * beforehand.
135 */
136 sa1111_configure_smc(1,
137 FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
138 FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
139
140 /*
141 * We only need to turn on DCLK whenever we want to use the
142 * DMA. It can otherwise be held firmly in the off position.
143 */
144 SKPCR |= SKPCR_DCLKEN;
145
146 /*
147 * Enable the SA1110 memory bus request and grant signals.
148 */
149 sa1110_mb_enable();
150
151 neponset_init_irq();
152
153 return 0;
154 }
155
156 __initcall(neponset_init);
157
158 static struct map_desc neponset_io_desc[] __initdata = {
159 /* virtual physical length domain r w c b */
160 { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
161 { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
162 LAST_DESC
163 };
164
neponset_set_mctrl(struct uart_port * port,u_int mctrl)165 static void neponset_set_mctrl(struct uart_port *port, u_int mctrl)
166 {
167 u_int mdm_ctl0 = MDM_CTL_0;
168
169 if (port->mapbase == _Ser1UTCR0) {
170 if (mctrl & TIOCM_RTS)
171 mdm_ctl0 &= ~MDM_CTL0_RTS2;
172 else
173 mdm_ctl0 |= MDM_CTL0_RTS2;
174
175 if (mctrl & TIOCM_DTR)
176 mdm_ctl0 &= ~MDM_CTL0_DTR2;
177 else
178 mdm_ctl0 |= MDM_CTL0_DTR2;
179 } else if (port->mapbase == _Ser3UTCR0) {
180 if (mctrl & TIOCM_RTS)
181 mdm_ctl0 &= ~MDM_CTL0_RTS1;
182 else
183 mdm_ctl0 |= MDM_CTL0_RTS1;
184
185 if (mctrl & TIOCM_DTR)
186 mdm_ctl0 &= ~MDM_CTL0_DTR1;
187 else
188 mdm_ctl0 |= MDM_CTL0_DTR1;
189 }
190
191 MDM_CTL_0 = mdm_ctl0;
192 }
193
neponset_get_mctrl(struct uart_port * port)194 static u_int neponset_get_mctrl(struct uart_port *port)
195 {
196 u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
197 u_int mdm_ctl1 = MDM_CTL_1;
198
199 if (port->mapbase == _Ser1UTCR0) {
200 if (mdm_ctl1 & MDM_CTL1_DCD2)
201 ret &= ~TIOCM_CD;
202 if (mdm_ctl1 & MDM_CTL1_CTS2)
203 ret &= ~TIOCM_CTS;
204 if (mdm_ctl1 & MDM_CTL1_DSR2)
205 ret &= ~TIOCM_DSR;
206 } else if (port->mapbase == _Ser3UTCR0) {
207 if (mdm_ctl1 & MDM_CTL1_DCD1)
208 ret &= ~TIOCM_CD;
209 if (mdm_ctl1 & MDM_CTL1_CTS1)
210 ret &= ~TIOCM_CTS;
211 if (mdm_ctl1 & MDM_CTL1_DSR1)
212 ret &= ~TIOCM_DSR;
213 }
214
215 return ret;
216 }
217
218 static struct sa1100_port_fns neponset_port_fns __initdata = {
219 .set_mctrl = neponset_set_mctrl,
220 .get_mctrl = neponset_get_mctrl,
221 };
222
neponset_map_io(void)223 void __init neponset_map_io(void)
224 {
225 iotable_init(neponset_io_desc);
226 if (machine_has_neponset())
227 sa1100_register_uart_fns(&neponset_port_fns);
228 }
229