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