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
59static BCSR * const bcsr = (BCSR *)0xAE000000;
60
61static 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
68static int db1x00_pcmcia_shutdown(void)
69{
70	bcsr->pcmcia = 0; /* turn off power */
71	au_sync_delay(2);
72	return 0;
73}
74
75static int
76db1x00_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
142static 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		info->irq = AU1000_GPIO_2;
148	}
149	else
150		info->irq = AU1000_GPIO_5;
151
152	return 0;
153}
154
155
156static int
157db1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
158{
159	u16 pwr;
160	int sock = configure->sock;
161
162	if(sock > PCMCIA_MAX_SOCK) return -1;
163
164	DEBUG(KERN_DEBUG "socket %d Vcc %dV Vpp %dV, reset %d\n",
165			sock, configure->vcc, configure->vpp, configure->reset);
166
167	/* pcmcia reg was set to zero at init time. Be careful when
168	 * initializing a socket not to wipe out the settings of the
169	 * other socket.
170	 */
171	pwr = bcsr->pcmcia;
172	pwr &= ~(0xf << sock*8); /* clear voltage settings */
173
174	switch(configure->vcc){
175		case 0:  /* Vcc 0 */
176			pwr |= SET_VCC_VPP(0,0,sock);
177			break;
178		case 50: /* Vcc 5V */
179			switch(configure->vpp) {
180				case 0:
181					pwr |= SET_VCC_VPP(2,0,sock);
182					break;
183				case 50:
184					pwr |= SET_VCC_VPP(2,1,sock);
185					break;
186				case 12:
187					pwr |= SET_VCC_VPP(2,2,sock);
188					break;
189				case 33:
190				default:
191					pwr |= SET_VCC_VPP(0,0,sock);
192					printk("%s: bad Vcc/Vpp (%d:%d)\n",
193							__FUNCTION__,
194							configure->vcc,
195							configure->vpp);
196					break;
197			}
198			break;
199		case 33: /* Vcc 3.3V */
200			switch(configure->vpp) {
201				case 0:
202					pwr |= SET_VCC_VPP(1,0,sock);
203					break;
204				case 12:
205					pwr |= SET_VCC_VPP(1,2,sock);
206					break;
207				case 33:
208					pwr |= SET_VCC_VPP(1,1,sock);
209					break;
210				case 50:
211				default:
212					pwr |= SET_VCC_VPP(0,0,sock);
213					printk("%s: bad Vcc/Vpp (%d:%d)\n",
214							__FUNCTION__,
215							configure->vcc,
216							configure->vpp);
217					break;
218			}
219			break;
220		default: /* what's this ? */
221			pwr |= SET_VCC_VPP(0,0,sock);
222			printk(KERN_ERR "%s: bad Vcc %d\n",
223					__FUNCTION__, configure->vcc);
224			break;
225	}
226
227	bcsr->pcmcia = pwr;
228	au_sync_delay(300);
229
230	if (sock == 0) {
231		if (!configure->reset) {
232			pwr |= BCSR_PCMCIA_PC0DRVEN;
233			bcsr->pcmcia = pwr;
234			au_sync_delay(300);
235			pwr |= BCSR_PCMCIA_PC0RST;
236			bcsr->pcmcia = pwr;
237			au_sync_delay(100);
238		}
239		else {
240			pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
241			bcsr->pcmcia = pwr;
242			au_sync_delay(100);
243		}
244	}
245	else {
246		if (!configure->reset) {
247			pwr |= BCSR_PCMCIA_PC1DRVEN;
248			bcsr->pcmcia = pwr;
249			au_sync_delay(300);
250			pwr |= BCSR_PCMCIA_PC1RST;
251			bcsr->pcmcia = pwr;
252			au_sync_delay(100);
253		}
254		else {
255			pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
256			bcsr->pcmcia = pwr;
257			au_sync_delay(100);
258		}
259	}
260	return 0;
261}
262
263struct pcmcia_low_level db1x00_pcmcia_ops = {
264	db1x00_pcmcia_init,
265	db1x00_pcmcia_shutdown,
266	db1x00_pcmcia_socket_state,
267	db1x00_pcmcia_get_irq_info,
268	db1x00_pcmcia_configure_socket
269};
270