import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / drivers / pcmcia / au1000_db1x00.c
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
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
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 
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
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 
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 };