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