add all source code from linksys/broadcom which is free, to cvs for better maintainen...
[openwrt/svn-archive/archive.git] / openwrt / package / linux / kernel-source / drivers / pcmcia / bcm4710_pcmcia.c
1 /*
2 * BCM4710 specific pcmcia routines.
3 *
4 * Copyright 2004, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id$
13 */
14 #include <linux/module.h>
15 #include <linux/init.h>
16 #include <linux/config.h>
17 #include <linux/delay.h>
18 #include <linux/ioport.h>
19 #include <linux/kernel.h>
20 #include <linux/tqueue.h>
21 #include <linux/timer.h>
22 #include <linux/mm.h>
23 #include <linux/proc_fs.h>
24 #include <linux/version.h>
25 #include <linux/types.h>
26 #include <linux/pci.h>
27
28 #include <pcmcia/version.h>
29 #include <pcmcia/cs_types.h>
30 #include <pcmcia/cs.h>
31 #include <pcmcia/ss.h>
32 #include <pcmcia/bulkmem.h>
33 #include <pcmcia/cistpl.h>
34 #include <pcmcia/bus_ops.h>
35 #include "cs_internal.h"
36
37 #include <asm/io.h>
38 #include <asm/irq.h>
39 #include <asm/system.h>
40
41
42 #include <typedefs.h>
43 #include <bcmdevs.h>
44 #include <bcm4710.h>
45 #include <sbconfig.h>
46 #include <sbextif.h>
47
48 #include "bcm4710pcmcia.h"
49
50 /* Use a static var for irq dev_id */
51 static int bcm47xx_pcmcia_dev_id;
52
53 /* Do we think we have a card or not? */
54 static int bcm47xx_pcmcia_present = 0;
55
56
57 static void bcm4710_pcmcia_reset(void)
58 {
59 extifregs_t *eir;
60 unsigned long s;
61 uint32 out0, out1, outen;
62
63
64 eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t));
65
66 save_and_cli(s);
67
68 /* Use gpio7 to reset the pcmcia slot */
69 outen = readl(&eir->gpio[0].outen);
70 outen |= BCM47XX_PCMCIA_RESET;
71 out0 = readl(&eir->gpio[0].out);
72 out0 &= ~(BCM47XX_PCMCIA_RESET);
73 out1 = out0 | BCM47XX_PCMCIA_RESET;
74
75 writel(out0, &eir->gpio[0].out);
76 writel(outen, &eir->gpio[0].outen);
77 mdelay(1);
78 writel(out1, &eir->gpio[0].out);
79 mdelay(1);
80 writel(out0, &eir->gpio[0].out);
81
82 restore_flags(s);
83 }
84
85
86 static int bcm4710_pcmcia_init(struct pcmcia_init *init)
87 {
88 struct pci_dev *pdev;
89 extifregs_t *eir;
90 uint32 outen, intp, intm, tmp;
91 uint16 *attrsp;
92 int rc = 0, i;
93 extern unsigned long bcm4710_cpu_cycle;
94
95
96 if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_EXTIF, NULL))) {
97 printk(KERN_ERR "bcm4710_pcmcia: extif not found\n");
98 return -ENODEV;
99 }
100 eir = (extifregs_t *) ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
101
102 /* Initialize the pcmcia i/f: 16bit no swap */
103 writel(CF_EM_PCMCIA | CF_DS | CF_EN, &eir->pcmcia_config);
104
105 #ifdef notYet
106
107 /* Set the timing for memory accesses */
108 tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */
109 tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */
110 tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */
111 tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */
112 writel(tmp, &eir->pcmcia_memwait); /* 0x01020a0c for a 100Mhz clock */
113
114 /* Set the timing for I/O accesses */
115 tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */
116 tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */
117 tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */
118 tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */
119 writel(tmp, &eir->pcmcia_iowait); /* 0x01020a0c for a 100Mhz clock */
120
121 /* Set the timing for attribute accesses */
122 tmp = (19 / bcm4710_cpu_cycle) << 24; /* W3 = 10nS */
123 tmp = tmp | ((29 / bcm4710_cpu_cycle) << 16); /* W2 = 20nS */
124 tmp = tmp | ((109 / bcm4710_cpu_cycle) << 8); /* W1 = 100nS */
125 tmp = tmp | (129 / bcm4710_cpu_cycle); /* W0 = 120nS */
126 writel(tmp, &eir->pcmcia_attrwait); /* 0x01020a0c for a 100Mhz clock */
127
128 #endif
129 /* Make sure gpio0 and gpio5 are inputs */
130 outen = readl(&eir->gpio[0].outen);
131 outen &= ~(BCM47XX_PCMCIA_WP | BCM47XX_PCMCIA_STSCHG | BCM47XX_PCMCIA_RESET);
132 writel(outen, &eir->gpio[0].outen);
133
134 /* Issue a reset to the pcmcia socket */
135 bcm4710_pcmcia_reset();
136
137 #ifdef DO_BCM47XX_PCMCIA_INTERRUPTS
138 /* Setup gpio5 to be the STSCHG interrupt */
139 intp = readl(&eir->gpiointpolarity);
140 writel(intp | BCM47XX_PCMCIA_STSCHG, &eir->gpiointpolarity); /* Active low */
141 intm = readl(&eir->gpiointmask);
142 writel(intm | BCM47XX_PCMCIA_STSCHG, &eir->gpiointmask); /* Enable it */
143 #endif
144
145 DEBUG(2, "bcm4710_pcmcia after reset:\n");
146 DEBUG(2, "\textstatus\t= 0x%08x:\n", readl(&eir->extstatus));
147 DEBUG(2, "\tpcmcia_config\t= 0x%08x:\n", readl(&eir->pcmcia_config));
148 DEBUG(2, "\tpcmcia_memwait\t= 0x%08x:\n", readl(&eir->pcmcia_memwait));
149 DEBUG(2, "\tpcmcia_attrwait\t= 0x%08x:\n", readl(&eir->pcmcia_attrwait));
150 DEBUG(2, "\tpcmcia_iowait\t= 0x%08x:\n", readl(&eir->pcmcia_iowait));
151 DEBUG(2, "\tgpioin\t\t= 0x%08x:\n", readl(&eir->gpioin));
152 DEBUG(2, "\tgpio_outen0\t= 0x%08x:\n", readl(&eir->gpio[0].outen));
153 DEBUG(2, "\tgpio_out0\t= 0x%08x:\n", readl(&eir->gpio[0].out));
154 DEBUG(2, "\tgpiointpolarity\t= 0x%08x:\n", readl(&eir->gpiointpolarity));
155 DEBUG(2, "\tgpiointmask\t= 0x%08x:\n", readl(&eir->gpiointmask));
156
157 #ifdef DO_BCM47XX_PCMCIA_INTERRUPTS
158 /* Request pcmcia interrupt */
159 rc = request_irq(BCM47XX_PCMCIA_IRQ, init->handler, SA_INTERRUPT,
160 "PCMCIA Interrupt", &bcm47xx_pcmcia_dev_id);
161 #endif
162
163 attrsp = (uint16 *)ioremap_nocache(EXTIF_PCMCIA_CFGBASE(BCM4710_EXTIF), 0x1000);
164 tmp = readw(&attrsp[0]);
165 DEBUG(2, "\tattr[0] = 0x%04x\n", tmp);
166 if ((tmp == 0x7fff) || (tmp == 0x7f00)) {
167 bcm47xx_pcmcia_present = 0;
168 } else {
169 bcm47xx_pcmcia_present = 1;
170 }
171
172 /* There's only one socket */
173 return 1;
174 }
175
176 static int bcm4710_pcmcia_shutdown(void)
177 {
178 extifregs_t *eir;
179 uint32 intm;
180
181 eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t));
182
183 /* Disable the pcmcia i/f */
184 writel(0, &eir->pcmcia_config);
185
186 /* Reset gpio's */
187 intm = readl(&eir->gpiointmask);
188 writel(intm & ~BCM47XX_PCMCIA_STSCHG, &eir->gpiointmask); /* Disable it */
189
190 free_irq(BCM47XX_PCMCIA_IRQ, &bcm47xx_pcmcia_dev_id);
191
192 return 0;
193 }
194
195 static int
196 bcm4710_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
197 {
198 extifregs_t *eir;
199
200 eir = (extifregs_t *) ioremap_nocache(BCM4710_REG_EXTIF, sizeof(extifregs_t));
201
202
203 if (sock != 0) {
204 printk(KERN_ERR "bcm4710 socket_state bad sock %d\n", sock);
205 return -1;
206 }
207
208 if (bcm47xx_pcmcia_present) {
209 state->detect = 1;
210 state->ready = 1;
211 state->bvd1 = 1;
212 state->bvd2 = 1;
213 state->wrprot = (readl(&eir->gpioin) & BCM47XX_PCMCIA_WP) == BCM47XX_PCMCIA_WP;
214 state->vs_3v = 0;
215 state->vs_Xv = 0;
216 } else {
217 state->detect = 0;
218 state->ready = 0;
219 }
220
221 return 1;
222 }
223
224
225 static int bcm4710_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
226 {
227 if (info->sock >= BCM47XX_PCMCIA_MAX_SOCK) return -1;
228
229 info->irq = BCM47XX_PCMCIA_IRQ;
230
231 return 0;
232 }
233
234
235 static int
236 bcm4710_pcmcia_configure_socket(const struct pcmcia_configure *configure)
237 {
238 if (configure->sock >= BCM47XX_PCMCIA_MAX_SOCK) return -1;
239
240
241 DEBUG(2, "Vcc %dV Vpp %dV output %d speaker %d reset %d\n", configure->vcc,
242 configure->vpp, configure->output, configure->speaker, configure->reset);
243
244 if ((configure->vcc != 50) || (configure->vpp != 50)) {
245 printk("%s: bad Vcc/Vpp (%d:%d)\n", __FUNCTION__, configure->vcc,
246 configure->vpp);
247 }
248
249 if (configure->reset) {
250 /* Issue a reset to the pcmcia socket */
251 DEBUG(1, "%s: Reseting socket\n", __FUNCTION__);
252 bcm4710_pcmcia_reset();
253 }
254
255
256 return 0;
257 }
258
259 struct pcmcia_low_level bcm4710_pcmcia_ops = {
260 bcm4710_pcmcia_init,
261 bcm4710_pcmcia_shutdown,
262 bcm4710_pcmcia_socket_state,
263 bcm4710_pcmcia_get_irq_info,
264 bcm4710_pcmcia_configure_socket
265 };
266