1 /*
2  *
3  * Alchemy Semi Db1x00 boards specific pcmcia routines.
4  *
5  * Copyright 2002 MontaVista Software Inc.
6  * Author: MontaVista Software, Inc.
7  *         	ppopov@mvista.com or source@mvista.com
8  *
9  * ########################################################################
10  *
11  *  This program is free software; you can distribute it and/or modify it
12  *  under the terms of the GNU General Public License (Version 2) as
13  *  published by the Free Software Foundation.
14  *
15  *  This program is distributed in the hope it will be useful, but WITHOUT
16  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18  *  for more details.
19  *
20  *  You should have received a copy of the GNU General Public License along
21  *  with this program; if not, write to the Free Software Foundation, Inc.,
22  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
23  *
24  * ########################################################################
25  *
26  *
27  */
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/config.h>
31 #include <linux/delay.h>
32 #include <linux/ioport.h>
33 #include <linux/kernel.h>
34 #include <linux/tqueue.h>
35 #include <linux/timer.h>
36 #include <linux/mm.h>
37 #include <linux/proc_fs.h>
38 #include <linux/version.h>
39 #include <linux/types.h>
40 
41 #include <pcmcia/version.h>
42 #include <pcmcia/cs_types.h>
43 #include <pcmcia/cs.h>
44 #include <pcmcia/ss.h>
45 #include <pcmcia/bulkmem.h>
46 #include <pcmcia/cistpl.h>
47 #include <pcmcia/bus_ops.h>
48 #include "cs_internal.h"
49 
50 #include <asm/io.h>
51 #include <asm/irq.h>
52 #include <asm/system.h>
53 
54 #include <asm/au1000.h>
55 #include <asm/au1000_pcmcia.h>
56 
57 #include <asm/db1x00.h>
58 
59 static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
60 
db1x00_pcmcia_init(struct pcmcia_init * init)61 static int db1x00_pcmcia_init(struct pcmcia_init *init)
62 {
63 	bcsr->pcmcia = 0; /* turn off power */
64 	au_sync_delay(2);
65 	return PCMCIA_NUM_SOCKS;
66 }
67 
db1x00_pcmcia_shutdown(void)68 static int db1x00_pcmcia_shutdown(void)
69 {
70 	bcsr->pcmcia = 0; /* turn off power */
71 	au_sync_delay(2);
72 	return 0;
73 }
74 
75 static int
db1x00_pcmcia_socket_state(unsigned sock,struct pcmcia_state * state)76 db1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
77 {
78 	u32 inserted;
79 	unsigned char vs;
80 
81 	if(sock > PCMCIA_MAX_SOCK) return -1;
82 
83 	state->ready = 0;
84 	state->vs_Xv = 0;
85 	state->vs_3v = 0;
86 	state->detect = 0;
87 
88 	if (sock == 0) {
89 		vs = bcsr->status & 0x3;
90 		inserted = !(bcsr->status & (1<<4));
91 	}
92 	else {
93 		vs = (bcsr->status & 0xC)>>2;
94 		inserted = !(bcsr->status & (1<<5));
95 	}
96 
97 	DEBUG(KERN_DEBUG "db1x00 socket %d: inserted %d, vs %d\n",
98 			sock, inserted, vs);
99 
100 	if (inserted) {
101 		switch (vs) {
102 			case 0:
103 			case 2:
104 				state->vs_3v=1;
105 				break;
106 			case 3: /* 5V */
107 				break;
108 			default:
109 				/* return without setting 'detect' */
110 				printk(KERN_ERR "db1x00 bad VS (%d)\n",
111 						vs);
112 				return -1;
113 		}
114 		state->detect = 1;
115 		state->ready = 1;
116 	}
117 	else {
118 		/* if the card was previously inserted and then ejected,
119 		 * we should turn off power to it
120 		 */
121 		if ((sock == 0) && (bcsr->pcmcia & BCSR_PCMCIA_PC0RST)) {
122 			bcsr->pcmcia &= ~(BCSR_PCMCIA_PC0RST |
123 					BCSR_PCMCIA_PC0DRVEN |
124 					BCSR_PCMCIA_PC0VPP |
125 					BCSR_PCMCIA_PC0VCC);
126 		}
127 		else if ((sock == 1) && (bcsr->pcmcia & BCSR_PCMCIA_PC1RST)) {
128 			bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST |
129 					BCSR_PCMCIA_PC1DRVEN |
130 					BCSR_PCMCIA_PC1VPP |
131 					BCSR_PCMCIA_PC1VCC);
132 		}
133 	}
134 
135 	state->bvd1=1;
136 	state->bvd2=1;
137 	state->wrprot=0;
138 	return 1;
139 }
140 
141 
db1x00_pcmcia_get_irq_info(struct pcmcia_irq_info * info)142 static int db1x00_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
143 {
144 	if(info->sock > PCMCIA_MAX_SOCK) return -1;
145 
146 	if(info->sock == 0)
147 #ifdef CONFIG_MIPS_DB1550
148 		info->irq = AU1000_GPIO_3;
149 	else
150 		info->irq = AU1000_GPIO_5;
151 #else
152 		info->irq = AU1000_GPIO_2;
153 	else
154 		info->irq = AU1000_GPIO_5;
155 #endif
156 
157 	return 0;
158 }
159 
160 
161 static int
db1x00_pcmcia_configure_socket(const struct pcmcia_configure * configure)162 db1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
163 {
164 	u16 pwr;
165 	int sock = configure->sock;
166 
167 	if(sock > PCMCIA_MAX_SOCK) return -1;
168 
169 	DEBUG(KERN_DEBUG "socket %d Vcc %dV Vpp %dV, reset %d\n",
170 			sock, configure->vcc, configure->vpp, configure->reset);
171 
172 	/* pcmcia reg was set to zero at init time. Be careful when
173 	 * initializing a socket not to wipe out the settings of the
174 	 * other socket.
175 	 */
176 	pwr = bcsr->pcmcia;
177 	pwr &= ~(0xf << sock*8); /* clear voltage settings */
178 
179 	switch(configure->vcc){
180 		case 0:  /* Vcc 0 */
181 			pwr |= SET_VCC_VPP(0,0,sock);
182 			break;
183 		case 50: /* Vcc 5V */
184 			switch(configure->vpp) {
185 				case 0:
186 					pwr |= SET_VCC_VPP(2,0,sock);
187 					break;
188 				case 50:
189 					pwr |= SET_VCC_VPP(2,1,sock);
190 					break;
191 				case 12:
192 					pwr |= SET_VCC_VPP(2,2,sock);
193 					break;
194 				case 33:
195 				default:
196 					pwr |= SET_VCC_VPP(0,0,sock);
197 					printk("%s: bad Vcc/Vpp (%d:%d)\n",
198 							__FUNCTION__,
199 							configure->vcc,
200 							configure->vpp);
201 					break;
202 			}
203 			break;
204 		case 33: /* Vcc 3.3V */
205 			switch(configure->vpp) {
206 				case 0:
207 					pwr |= SET_VCC_VPP(1,0,sock);
208 					break;
209 				case 12:
210 					pwr |= SET_VCC_VPP(1,2,sock);
211 					break;
212 				case 33:
213 					pwr |= SET_VCC_VPP(1,1,sock);
214 					break;
215 				case 50:
216 				default:
217 					pwr |= SET_VCC_VPP(0,0,sock);
218 					printk("%s: bad Vcc/Vpp (%d:%d)\n",
219 							__FUNCTION__,
220 							configure->vcc,
221 							configure->vpp);
222 					break;
223 			}
224 			break;
225 		default: /* what's this ? */
226 			pwr |= SET_VCC_VPP(0,0,sock);
227 			printk(KERN_ERR "%s: bad Vcc %d\n",
228 					__FUNCTION__, configure->vcc);
229 			break;
230 	}
231 
232 	bcsr->pcmcia = pwr;
233 	au_sync_delay(300);
234 
235 	if (sock == 0) {
236 		if (!configure->reset) {
237 			pwr |= BCSR_PCMCIA_PC0DRVEN;
238 			bcsr->pcmcia = pwr;
239 			au_sync_delay(300);
240 			pwr |= BCSR_PCMCIA_PC0RST;
241 			bcsr->pcmcia = pwr;
242 			au_sync_delay(100);
243 		}
244 		else {
245 			pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
246 			bcsr->pcmcia = pwr;
247 			au_sync_delay(100);
248 		}
249 	}
250 	else {
251 		if (!configure->reset) {
252 			pwr |= BCSR_PCMCIA_PC1DRVEN;
253 			bcsr->pcmcia = pwr;
254 			au_sync_delay(300);
255 			pwr |= BCSR_PCMCIA_PC1RST;
256 			bcsr->pcmcia = pwr;
257 			au_sync_delay(100);
258 		}
259 		else {
260 			pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
261 			bcsr->pcmcia = pwr;
262 			au_sync_delay(100);
263 		}
264 	}
265 	return 0;
266 }
267 
268 struct pcmcia_low_level au1x00_pcmcia_ops = {
269 	db1x00_pcmcia_init,
270 	db1x00_pcmcia_shutdown,
271 	db1x00_pcmcia_socket_state,
272 	db1x00_pcmcia_get_irq_info,
273 	db1x00_pcmcia_configure_socket
274 };
275