2 * BCM4710 specific pcmcia routines.
4 * Copyright 2004, Broadcom Corporation
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.
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>
23 #include <linux/proc_fs.h>
24 #include <linux/version.h>
25 #include <linux/types.h>
26 #include <linux/pci.h>
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"
39 #include <asm/system.h>
48 #include "bcm4710pcmcia.h"
50 /* Use a static var for irq dev_id */
51 static int bcm47xx_pcmcia_dev_id
;
53 /* Do we think we have a card or not? */
54 static int bcm47xx_pcmcia_present
= 0;
57 static void bcm4710_pcmcia_reset(void)
61 uint32 out0
, out1
, outen
;
64 eir
= (extifregs_t
*) ioremap_nocache(BCM4710_REG_EXTIF
, sizeof(extifregs_t
));
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
;
75 writel(out0
, &eir
->gpio
[0].out
);
76 writel(outen
, &eir
->gpio
[0].outen
);
78 writel(out1
, &eir
->gpio
[0].out
);
80 writel(out0
, &eir
->gpio
[0].out
);
86 static int bcm4710_pcmcia_init(struct pcmcia_init
*init
)
90 uint32 outen
, intp
, intm
, tmp
;
93 extern unsigned long bcm4710_cpu_cycle
;
96 if (!(pdev
= pci_find_device(VENDOR_BROADCOM
, SB_EXTIF
, NULL
))) {
97 printk(KERN_ERR
"bcm4710_pcmcia: extif not found\n");
100 eir
= (extifregs_t
*) ioremap_nocache(pci_resource_start(pdev
, 0), pci_resource_len(pdev
, 0));
102 /* Initialize the pcmcia i/f: 16bit no swap */
103 writel(CF_EM_PCMCIA
| CF_DS
| CF_EN
, &eir
->pcmcia_config
);
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 */
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 */
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 */
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
);
134 /* Issue a reset to the pcmcia socket */
135 bcm4710_pcmcia_reset();
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 */
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
));
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
);
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;
169 bcm47xx_pcmcia_present
= 1;
172 /* There's only one socket */
176 static int bcm4710_pcmcia_shutdown(void)
181 eir
= (extifregs_t
*) ioremap_nocache(BCM4710_REG_EXTIF
, sizeof(extifregs_t
));
183 /* Disable the pcmcia i/f */
184 writel(0, &eir
->pcmcia_config
);
187 intm
= readl(&eir
->gpiointmask
);
188 writel(intm
& ~BCM47XX_PCMCIA_STSCHG
, &eir
->gpiointmask
); /* Disable it */
190 free_irq(BCM47XX_PCMCIA_IRQ
, &bcm47xx_pcmcia_dev_id
);
196 bcm4710_pcmcia_socket_state(unsigned sock
, struct pcmcia_state
*state
)
200 eir
= (extifregs_t
*) ioremap_nocache(BCM4710_REG_EXTIF
, sizeof(extifregs_t
));
204 printk(KERN_ERR
"bcm4710 socket_state bad sock %d\n", sock
);
208 if (bcm47xx_pcmcia_present
) {
213 state
->wrprot
= (readl(&eir
->gpioin
) & BCM47XX_PCMCIA_WP
) == BCM47XX_PCMCIA_WP
;
225 static int bcm4710_pcmcia_get_irq_info(struct pcmcia_irq_info
*info
)
227 if (info
->sock
>= BCM47XX_PCMCIA_MAX_SOCK
) return -1;
229 info
->irq
= BCM47XX_PCMCIA_IRQ
;
236 bcm4710_pcmcia_configure_socket(const struct pcmcia_configure
*configure
)
238 if (configure
->sock
>= BCM47XX_PCMCIA_MAX_SOCK
) return -1;
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
);
244 if ((configure
->vcc
!= 50) || (configure
->vpp
!= 50)) {
245 printk("%s: bad Vcc/Vpp (%d:%d)\n", __FUNCTION__
, configure
->vcc
,
249 if (configure
->reset
) {
250 /* Issue a reset to the pcmcia socket */
251 DEBUG(1, "%s: Reseting socket\n", __FUNCTION__
);
252 bcm4710_pcmcia_reset();
259 struct pcmcia_low_level bcm4710_pcmcia_ops
= {
261 bcm4710_pcmcia_shutdown
,
262 bcm4710_pcmcia_socket_state
,
263 bcm4710_pcmcia_get_irq_info
,
264 bcm4710_pcmcia_configure_socket