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
db1x00_pcmcia_init(struct pcmcia_init * init)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
db1x00_pcmcia_shutdown(void)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
db1x00_pcmcia_socket_state(unsigned sock,struct pcmcia_state * state)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
db1x00_pcmcia_get_irq_info(struct pcmcia_irq_info * info)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
db1x00_pcmcia_configure_socket(const struct pcmcia_configure * configure)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 };
275