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