upgrade wireless-tools and iproute2
[openwrt.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