original comment: +Wilson03172004,marked due to this pci host does not support MWI
[linux-2.4.git] / drivers / pcmcia / au1000_pb1550.c
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
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
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 
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
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 
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 };