[PATCH] pcmcia: reduce ds.c stack footprint
[linux-2.6] / 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  * Copyright 2004 Pete Popov, updated the driver to 2.6.
10  * Followed the sa11xx API and largely copied many of the hardware
11  * independent functions.
12  *
13  * ########################################################################
14  *
15  *  This program is free software; you can distribute it and/or modify it
16  *  under the terms of the GNU General Public License (Version 2) as
17  *  published by the Free Software Foundation.
18  *
19  *  This program is distributed in the hope it will be useful, but WITHOUT
20  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22  *  for more details.
23  *
24  *  You should have received a copy of the GNU General Public License along
25  *  with this program; if not, write to the Free Software Foundation, Inc.,
26  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
27  *
28  * ########################################################################
29  *
30  *
31  */
32
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/errno.h>
36 #include <linux/interrupt.h>
37 #include <linux/device.h>
38 #include <linux/init.h>
39
40 #include <asm/irq.h>
41 #include <asm/signal.h>
42 #include <asm/mach-au1x00/au1000.h>
43 #include <asm/mach-db1x00/db1x00.h>
44
45 #include "au1000_generic.h"
46
47 #if 0
48 #define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
49 #else
50 #define debug(x,args...)
51 #endif
52
53 static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
54
55 struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS];
56 extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int);
57
58 static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt)
59 {
60 #ifdef CONFIG_MIPS_DB1550
61         skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3;
62 #else
63         skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2;
64 #endif
65         return 0;
66 }
67
68 static void db1x00_pcmcia_shutdown(struct au1000_pcmcia_socket *skt)
69 {
70         bcsr->pcmcia = 0; /* turn off power */
71         au_sync_delay(2);
72 }
73
74 static void
75 db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state *state)
76 {
77         u32 inserted;
78         unsigned char vs;
79
80         state->ready = 0;
81         state->vs_Xv = 0;
82         state->vs_3v = 0;
83         state->detect = 0;
84
85         switch (skt->nr) {
86         case 0:
87                 vs = bcsr->status & 0x3;
88                 inserted = !(bcsr->status & (1<<4));
89                 break;
90         case 1:
91                 vs = (bcsr->status & 0xC)>>2;
92                 inserted = !(bcsr->status & (1<<5));
93                 break;
94         default:/* should never happen */
95                 return;
96         }
97
98         if (inserted)
99                 debug("db1x00 socket %d: inserted %d, vs %d pcmcia %x\n",
100                                 skt->nr, inserted, vs, bcsr->pcmcia);
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 "db1x00 bad VS (%d)\n",
113                                                 vs);
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 ((skt->nr == 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                         au_sync_delay(10);
128                 }
129                 else if ((skt->nr == 1) && bcsr->pcmcia & BCSR_PCMCIA_PC1RST) {
130                         bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST |
131                                         BCSR_PCMCIA_PC1DRVEN |
132                                         BCSR_PCMCIA_PC1VPP |
133                                         BCSR_PCMCIA_PC1VCC);
134                         au_sync_delay(10);
135                 }
136         }
137
138         state->bvd1=1;
139         state->bvd2=1;
140         state->wrprot=0;
141 }
142
143 static int
144 db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_state_t *state)
145 {
146         u16 pwr;
147         int sock = skt->nr;
148
149         debug("config_skt %d Vcc %dV Vpp %dV, reset %d\n",
150                         sock, state->Vcc, state->Vpp,
151                         state->flags & SS_RESET);
152
153         /* pcmcia reg was set to zero at init time. Be careful when
154          * initializing a socket not to wipe out the settings of the
155          * other socket.
156          */
157         pwr = bcsr->pcmcia;
158         pwr &= ~(0xf << sock*8); /* clear voltage settings */
159
160         state->Vpp = 0;
161         switch(state->Vcc){
162                 case 0:  /* Vcc 0 */
163                         pwr |= SET_VCC_VPP(0,0,sock);
164                         break;
165                 case 50: /* Vcc 5V */
166                         switch(state->Vpp) {
167                                 case 0:
168                                         pwr |= SET_VCC_VPP(2,0,sock);
169                                         break;
170                                 case 50:
171                                         pwr |= SET_VCC_VPP(2,1,sock);
172                                         break;
173                                 case 12:
174                                         pwr |= SET_VCC_VPP(2,2,sock);
175                                         break;
176                                 case 33:
177                                 default:
178                                         pwr |= SET_VCC_VPP(0,0,sock);
179                                         printk("%s: bad Vcc/Vpp (%d:%d)\n",
180                                                         __FUNCTION__,
181                                                         state->Vcc,
182                                                         state->Vpp);
183                                         break;
184                         }
185                         break;
186                 case 33: /* Vcc 3.3V */
187                         switch(state->Vpp) {
188                                 case 0:
189                                         pwr |= SET_VCC_VPP(1,0,sock);
190                                         break;
191                                 case 12:
192                                         pwr |= SET_VCC_VPP(1,2,sock);
193                                         break;
194                                 case 33:
195                                         pwr |= SET_VCC_VPP(1,1,sock);
196                                         break;
197                                 case 50:
198                                 default:
199                                         pwr |= SET_VCC_VPP(0,0,sock);
200                                         printk("%s: bad Vcc/Vpp (%d:%d)\n",
201                                                         __FUNCTION__,
202                                                         state->Vcc,
203                                                         state->Vpp);
204                                         break;
205                         }
206                         break;
207                 default: /* what's this ? */
208                         pwr |= SET_VCC_VPP(0,0,sock);
209                         printk(KERN_ERR "%s: bad Vcc %d\n",
210                                         __FUNCTION__, state->Vcc);
211                         break;
212         }
213
214         bcsr->pcmcia = pwr;
215         au_sync_delay(300);
216
217         if (sock == 0) {
218                 if (!(state->flags & SS_RESET)) {
219                         pwr |= BCSR_PCMCIA_PC0DRVEN;
220                         bcsr->pcmcia = pwr;
221                         au_sync_delay(300);
222                         pwr |= BCSR_PCMCIA_PC0RST;
223                         bcsr->pcmcia = pwr;
224                         au_sync_delay(100);
225                 }
226                 else {
227                         pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
228                         bcsr->pcmcia = pwr;
229                         au_sync_delay(100);
230                 }
231         }
232         else {
233                 if (!(state->flags & SS_RESET)) {
234                         pwr |= BCSR_PCMCIA_PC1DRVEN;
235                         bcsr->pcmcia = pwr;
236                         au_sync_delay(300);
237                         pwr |= BCSR_PCMCIA_PC1RST;
238                         bcsr->pcmcia = pwr;
239                         au_sync_delay(100);
240                 }
241                 else {
242                         pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
243                         bcsr->pcmcia = pwr;
244                         au_sync_delay(100);
245                 }
246         }
247         return 0;
248 }
249
250 /*
251  * Enable card status IRQs on (re-)initialisation.  This can
252  * be called at initialisation, power management event, or
253  * pcmcia event.
254  */
255 void db1x00_socket_init(struct au1000_pcmcia_socket *skt)
256 {
257         /* nothing to do for now */
258 }
259
260 /*
261  * Disable card status IRQs and PCMCIA bus on suspend.
262  */
263 void db1x00_socket_suspend(struct au1000_pcmcia_socket *skt)
264 {
265         /* nothing to do for now */
266 }
267
268 struct pcmcia_low_level db1x00_pcmcia_ops = {
269         .owner                  = THIS_MODULE,
270
271         .hw_init                = db1x00_pcmcia_hw_init,
272         .hw_shutdown            = db1x00_pcmcia_shutdown,
273
274         .socket_state           = db1x00_pcmcia_socket_state,
275         .configure_socket       = db1x00_pcmcia_configure_socket,
276
277         .socket_init            = db1x00_socket_init,
278         .socket_suspend         = db1x00_socket_suspend
279 };
280
281 int __init au1x_board_init(struct device *dev)
282 {
283         int ret = -ENODEV;
284         bcsr->pcmcia = 0; /* turn off power, if it's not already off */
285         au_sync_delay(2);
286         ret = au1x00_pcmcia_socket_probe(dev, &db1x00_pcmcia_ops, 0, 2);
287         return ret;
288 }