1 /*
2 * SDIO access interface for drivers - linux specific (pci only)
3 *
4 * Copyright (C) 1999-2009, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdh_linux.c,v 1.42.10.10.2.8 2009/10/15 22:48:28 Exp $
25 */
26
27 /**
28 * @file bcmsdh_linux.c
29 */
30
31 #define __UNDEF_NO_VERSION__
32
33 #include <typedefs.h>
34 #include <linuxver.h>
35
36 #include <linux/pci.h>
37 #include <linux/completion.h>
38
39 #include <osl.h>
40 #include <pcicfg.h>
41 #include <bcmdefs.h>
42 #include <bcmdevs.h>
43
44 #if defined(OOB_INTR_ONLY)
45 #include <linux/irq.h>
46 extern void dhdsdio_isr(void * args);
47 #include <bcmutils.h>
48 #include <dngl_stats.h>
49 #include <dhd.h>
50 #endif /* defined(OOB_INTR_ONLY) */
51 #if defined(CONFIG_MACH_SANDGATE2G) || defined(CONFIG_MACH_LOGICPD_PXA270)
52 #if !defined(BCMPLATFORM_BUS)
53 #define BCMPLATFORM_BUS
54 #endif /* !defined(BCMPLATFORM_BUS) */
55
56 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
57 #include <linux/platform_device.h>
58 #endif /* KERNEL_VERSION(2, 6, 19) */
59 #endif /* CONFIG_MACH_SANDGATE2G || CONFIG_MACH_LOGICPD_PXA270 */
60
61 /**
62 * SDIO Host Controller info
63 */
64 typedef struct bcmsdh_hc bcmsdh_hc_t;
65
66 struct bcmsdh_hc {
67 bcmsdh_hc_t *next;
68 #ifdef BCMPLATFORM_BUS
69 struct device *dev; /* platform device handle */
70 #else
71 struct pci_dev *dev; /* pci device handle */
72 #endif /* BCMPLATFORM_BUS */
73 osl_t *osh;
74 void *regs; /* SDIO Host Controller address */
75 bcmsdh_info_t *sdh; /* SDIO Host Controller handle */
76 void *ch;
77 unsigned int oob_irq;
78 };
79 static bcmsdh_hc_t *sdhcinfo = NULL;
80
81 /* driver info, initialized when bcmsdh_register is called */
82 static bcmsdh_driver_t drvinfo = {NULL, NULL};
83
84 /* debugging macros */
85 #define SDLX_MSG(x)
86
87 /**
88 * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
89 */
90 bool
bcmsdh_chipmatch(uint16 vendor,uint16 device)91 bcmsdh_chipmatch(uint16 vendor, uint16 device)
92 {
93 /* Add other vendors and devices as required */
94
95 #ifdef BCMSDIOH_STD
96 /* Check for Arasan host controller */
97 if (vendor == VENDOR_SI_IMAGE) {
98 return (TRUE);
99 }
100 /* Check for BRCM 27XX Standard host controller */
101 if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
102 return (TRUE);
103 }
104 /* Check for BRCM Standard host controller */
105 if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
106 return (TRUE);
107 }
108 /* Check for TI PCIxx21 Standard host controller */
109 if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
110 return (TRUE);
111 }
112 if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
113 return (TRUE);
114 }
115 /* Ricoh R5C822 Standard SDIO Host */
116 if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
117 return (TRUE);
118 }
119 /* JMicron Standard SDIO Host */
120 if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
121 return (TRUE);
122 }
123
124 #endif /* BCMSDIOH_STD */
125 #ifdef BCMSDIOH_SPI
126 /* This is the PciSpiHost. */
127 if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
128 printf("Found PCI SPI Host Controller\n");
129 return (TRUE);
130 }
131
132 #endif /* BCMSDIOH_SPI */
133
134 return (FALSE);
135 }
136
137 #if defined(BCMPLATFORM_BUS)
138 #if defined(BCMLXSDMMC)
139 /* forward declarations */
140 int bcmsdh_probe(struct device *dev);
141 int bcmsdh_remove(struct device *dev);
142
143 EXPORT_SYMBOL(bcmsdh_probe);
144 EXPORT_SYMBOL(bcmsdh_remove);
145
146 #else
147 /* forward declarations */
148 static int __devinit bcmsdh_probe(struct device *dev);
149 static int __devexit bcmsdh_remove(struct device *dev);
150 #endif /* BCMLXSDMMC */
151
152 #ifndef BCMLXSDMMC
153 static struct device_driver bcmsdh_driver = {
154 .name = "pxa2xx-mci",
155 .bus = &platform_bus_type,
156 .probe = bcmsdh_probe,
157 .remove = bcmsdh_remove,
158 .suspend = NULL,
159 .resume = NULL,
160 };
161 #endif /* BCMLXSDMMC */
162
163 #ifndef BCMLXSDMMC
164 static
165 #endif /* BCMLXSDMMC */
bcmsdh_probe(struct device * dev)166 int bcmsdh_probe(struct device *dev)
167 {
168 osl_t *osh = NULL;
169 bcmsdh_hc_t *sdhc = NULL;
170 ulong regs = 0;
171 bcmsdh_info_t *sdh = NULL;
172 #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
173 struct platform_device *pdev;
174 struct resource *r;
175 #endif /* BCMLXSDMMC */
176 int irq = 0;
177 uint32 vendevid;
178
179 #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
180 pdev = to_platform_device(dev);
181 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
182 irq = platform_get_irq(pdev, 0);
183 if (!r || irq == NO_IRQ)
184 return -ENXIO;
185 #endif /* BCMLXSDMMC */
186
187 #if defined(OOB_INTR_ONLY)
188 irq = dhd_customer_oob_irq_map();
189 if (irq < 0) {
190 SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
191 return 1;
192 }
193 #endif /* defined(OOB_INTR_ONLY) */
194 /* allocate SDIO Host Controller state info */
195 if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
196 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
197 goto err;
198 }
199 if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
200 SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
201 __FUNCTION__,
202 MALLOCED(osh)));
203 goto err;
204 }
205 bzero(sdhc, sizeof(bcmsdh_hc_t));
206 sdhc->osh = osh;
207
208 sdhc->dev = (void *)dev;
209
210 #ifdef BCMLXSDMMC
211 if (!(sdh = bcmsdh_attach(osh, (void *)0,
212 (void **)®s, irq))) {
213 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
214 goto err;
215 }
216 #else
217 if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
218 (void **)®s, irq))) {
219 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
220 goto err;
221 }
222 #endif /* BCMLXSDMMC */
223 sdhc->sdh = sdh;
224 sdhc->oob_irq = irq;
225
226 /* chain SDIO Host Controller info together */
227 sdhc->next = sdhcinfo;
228 sdhcinfo = sdhc;
229 /* Read the vendor/device ID from the CIS */
230 vendevid = bcmsdh_query_device(sdh);
231
232 /* try to attach to the target device */
233 if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
234 (vendevid & 0xFFFF), 0, 0, 0, 0,
235 (void *)regs, NULL, sdh))) {
236 SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
237 goto err;
238 }
239
240 return 0;
241
242 /* error handling */
243 err:
244 if (sdhc) {
245 if (sdhc->sdh)
246 bcmsdh_detach(sdhc->osh, sdhc->sdh);
247 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
248 }
249 if (osh)
250 osl_detach(osh);
251 return -ENODEV;
252 }
253
254 #ifndef BCMLXSDMMC
255 static
256 #endif /* BCMLXSDMMC */
bcmsdh_remove(struct device * dev)257 int bcmsdh_remove(struct device *dev)
258 {
259 bcmsdh_hc_t *sdhc, *prev;
260 osl_t *osh;
261
262 sdhc = sdhcinfo;
263 drvinfo.detach(sdhc->ch);
264 bcmsdh_detach(sdhc->osh, sdhc->sdh);
265 /* find the SDIO Host Controller state for this pdev and take it out from the list */
266 for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
267 if (sdhc->dev == (void *)dev) {
268 if (prev)
269 prev->next = sdhc->next;
270 else
271 sdhcinfo = NULL;
272 break;
273 }
274 prev = sdhc;
275 }
276 if (!sdhc) {
277 SDLX_MSG(("%s: failed\n", __FUNCTION__));
278 return 0;
279 }
280
281
282 /* release SDIO Host Controller info */
283 osh = sdhc->osh;
284 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
285 osl_detach(osh);
286
287 #if !defined(BCMLXSDMMC)
288 dev_set_drvdata(dev, NULL);
289 #endif /* !defined(BCMLXSDMMC) */
290
291 return 0;
292 }
293
294 #else /* BCMPLATFORM_BUS */
295
296 #if !defined(BCMLXSDMMC)
297 /* forward declarations for PCI probe and remove functions. */
298 static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
299 static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
300
301 /**
302 * pci id table
303 */
304 static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
305 { vendor: PCI_ANY_ID,
306 device: PCI_ANY_ID,
307 subvendor: PCI_ANY_ID,
308 subdevice: PCI_ANY_ID,
309 class: 0,
310 class_mask: 0,
311 driver_data: 0,
312 },
313 { 0, }
314 };
315 MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
316
317 /**
318 * SDIO Host Controller pci driver info
319 */
320 static struct pci_driver bcmsdh_pci_driver = {
321 node: {},
322 name: "bcmsdh",
323 id_table: bcmsdh_pci_devid,
324 probe: bcmsdh_pci_probe,
325 remove: bcmsdh_pci_remove,
326 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
327 save_state: NULL,
328 #endif
329 suspend: NULL,
330 resume: NULL,
331 };
332
333
334 /**
335 * Detect supported SDIO Host Controller and attach if found.
336 *
337 * Determine if the device described by pdev is a supported SDIO Host
338 * Controller. If so, attach to it and attach to the target device.
339 */
340 static int __devinit
bcmsdh_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)341 bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
342 {
343 osl_t *osh = NULL;
344 bcmsdh_hc_t *sdhc = NULL;
345 ulong regs;
346 bcmsdh_info_t *sdh = NULL;
347 int rc;
348
349 if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
350 (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
351 uint32 config_reg;
352
353 SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
354 if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
355 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
356 goto err;
357 }
358
359 config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
360
361 /*
362 * Set MMC_SD_DIS bit in FlashMedia Controller.
363 * Disbling the SD/MMC Controller in the FlashMedia Controller
364 * allows the Standard SD Host Controller to take over control
365 * of the SD Slot.
366 */
367 config_reg |= 0x02;
368 OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
369 osl_detach(osh);
370 }
371 /* match this pci device with what we support */
372 /* we can't solely rely on this to believe it is our SDIO Host Controller! */
373 if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
374 return -ENODEV;
375 }
376
377 /* this is a pci device we might support */
378 SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
379 __FUNCTION__,
380 pdev->bus->number, PCI_SLOT(pdev->devfn),
381 PCI_FUNC(pdev->devfn), pdev->irq));
382
383 /* use bcmsdh_query_device() to get the vendor ID of the target device so
384 * it will eventually appear in the Broadcom string on the console
385 */
386
387 /* allocate SDIO Host Controller state info */
388 if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
389 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
390 goto err;
391 }
392 if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
393 SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
394 __FUNCTION__,
395 MALLOCED(osh)));
396 goto err;
397 }
398 bzero(sdhc, sizeof(bcmsdh_hc_t));
399 sdhc->osh = osh;
400
401 sdhc->dev = pdev;
402
403 /* map to address where host can access */
404 pci_set_master(pdev);
405 rc = pci_enable_device(pdev);
406 if (rc) {
407 SDLX_MSG(("%s: Cannot enble PCI device\n", __FUNCTION__));
408 goto err;
409 }
410 if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
411 (void **)®s, pdev->irq))) {
412 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
413 goto err;
414 }
415
416 sdhc->sdh = sdh;
417
418 /* try to attach to the target device */
419 if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
420 bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
421 (void *)regs, NULL, sdh))) {
422 SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
423 goto err;
424 }
425
426 /* chain SDIO Host Controller info together */
427 sdhc->next = sdhcinfo;
428 sdhcinfo = sdhc;
429
430 return 0;
431
432 /* error handling */
433 err:
434 if (sdhc->sdh)
435 bcmsdh_detach(sdhc->osh, sdhc->sdh);
436 if (sdhc)
437 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
438 if (osh)
439 osl_detach(osh);
440 return -ENODEV;
441 }
442
443
444 /**
445 * Detach from target devices and SDIO Host Controller
446 */
447 static void __devexit
bcmsdh_pci_remove(struct pci_dev * pdev)448 bcmsdh_pci_remove(struct pci_dev *pdev)
449 {
450 bcmsdh_hc_t *sdhc, *prev;
451 osl_t *osh;
452
453 /* find the SDIO Host Controller state for this pdev and take it out from the list */
454 for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
455 if (sdhc->dev == pdev) {
456 if (prev)
457 prev->next = sdhc->next;
458 else
459 sdhcinfo = NULL;
460 break;
461 }
462 prev = sdhc;
463 }
464 if (!sdhc)
465 return;
466
467 drvinfo.detach(sdhc->ch);
468
469 bcmsdh_detach(sdhc->osh, sdhc->sdh);
470
471 /* release SDIO Host Controller info */
472 osh = sdhc->osh;
473 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
474 osl_detach(osh);
475 }
476 #endif /* BCMLXSDMMC */
477 #endif /* BCMPLATFORM_BUS */
478
479 extern int sdio_function_init(void);
480
481 int
bcmsdh_register(bcmsdh_driver_t * driver)482 bcmsdh_register(bcmsdh_driver_t *driver)
483 {
484 int error = 0;
485
486 drvinfo = *driver;
487
488 #if defined(BCMPLATFORM_BUS)
489 #if defined(BCMLXSDMMC)
490 SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
491 error = sdio_function_init();
492 #else
493 SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
494 error = driver_register(&bcmsdh_driver);
495 #endif /* defined(BCMLXSDMMC) */
496 return error;
497 #endif /* defined(BCMPLATFORM_BUS) */
498
499 #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
500 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
501 if (!(error = pci_module_init(&bcmsdh_pci_driver)))
502 return 0;
503 #else
504 if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
505 return 0;
506 #endif
507
508 SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
509 #endif /* BCMPLATFORM_BUS */
510
511 return error;
512 }
513
514 extern void sdio_function_cleanup(void);
515
516 void
bcmsdh_unregister(void)517 bcmsdh_unregister(void)
518 {
519 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
520 if (bcmsdh_pci_driver.node.next)
521 #endif
522
523 #if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
524 driver_unregister(&bcmsdh_driver);
525 #endif
526 #if defined(BCMLXSDMMC)
527 sdio_function_cleanup();
528 #endif /* BCMLXSDMMC */
529 #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
530 pci_unregister_driver(&bcmsdh_pci_driver);
531 #endif /* BCMPLATFORM_BUS */
532 }
533
534 #if defined(OOB_INTR_ONLY)
wlan_oob_irq(int irq,void * dev_id)535 static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
536 {
537 dhd_pub_t *dhdp;
538
539 dhdp = (dhd_pub_t *)sdhcinfo->dev->driver_data;
540
541 if (dhdp == NULL) {
542 disable_irq(sdhcinfo->oob_irq);
543 SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
544 return IRQ_HANDLED;
545 }
546
547 dhdsdio_isr((void *)dhdp->bus);
548
549 return IRQ_HANDLED;
550 }
551
bcmsdh_register_oob_intr(void * dhdp)552 int bcmsdh_register_oob_intr(void * dhdp)
553 {
554 int error = 0;
555
556 SDLX_MSG(("%s Enter\n", __FUNCTION__));
557
558 sdhcinfo->dev->driver_data = dhdp;
559
560 set_irq_wake(sdhcinfo->oob_irq, 1);
561
562 /* Refer to customer Host IRQ docs about proper irqflags definition */
563 error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, IRQF_TRIGGER_FALLING,
564 "bcmsdh_sdmmc", NULL);
565
566 if (error)
567 return -ENODEV;
568
569 return 0;
570 }
571
bcmsdh_unregister_oob_intr(void)572 void bcmsdh_unregister_oob_intr(void)
573 {
574 SDLX_MSG(("%s: Enter\n", __FUNCTION__));
575
576 set_irq_wake(sdhcinfo->oob_irq, 0);
577 disable_irq(sdhcinfo->oob_irq); /* just in case.. */
578 free_irq(sdhcinfo->oob_irq, NULL);
579 }
580
bcmsdh_oob_intr_set(bool enable)581 void bcmsdh_oob_intr_set(bool enable)
582 {
583 if (enable)
584 enable_irq(sdhcinfo->oob_irq);
585 else
586 disable_irq(sdhcinfo->oob_irq);
587 }
588 #endif /* defined(OOB_INTR_ONLY) */
589 /* Module parameters specific to each host-controller driver */
590
591 extern uint sd_msglevel; /* Debug message level */
592 module_param(sd_msglevel, uint, 0);
593
594 extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */
595 module_param(sd_power, uint, 0);
596
597 extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
598 module_param(sd_clock, uint, 0);
599
600 extern uint sd_divisor; /* Divisor (-1 means external clock) */
601 module_param(sd_divisor, uint, 0);
602
603 extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
604 module_param(sd_sdmode, uint, 0);
605
606 extern uint sd_hiok; /* Ok to use hi-speed mode */
607 module_param(sd_hiok, uint, 0);
608
609 extern uint sd_f2_blocksize;
610 module_param(sd_f2_blocksize, int, 0);
611
612
613 #ifdef BCMSDH_MODULE
614 EXPORT_SYMBOL(bcmsdh_attach);
615 EXPORT_SYMBOL(bcmsdh_detach);
616 EXPORT_SYMBOL(bcmsdh_intr_query);
617 EXPORT_SYMBOL(bcmsdh_intr_enable);
618 EXPORT_SYMBOL(bcmsdh_intr_disable);
619 EXPORT_SYMBOL(bcmsdh_intr_reg);
620 EXPORT_SYMBOL(bcmsdh_intr_dereg);
621
622 #if defined(DHD_DEBUG)
623 EXPORT_SYMBOL(bcmsdh_intr_pending);
624 #endif
625
626 EXPORT_SYMBOL(bcmsdh_devremove_reg);
627 EXPORT_SYMBOL(bcmsdh_cfg_read);
628 EXPORT_SYMBOL(bcmsdh_cfg_write);
629 EXPORT_SYMBOL(bcmsdh_cis_read);
630 EXPORT_SYMBOL(bcmsdh_reg_read);
631 EXPORT_SYMBOL(bcmsdh_reg_write);
632 EXPORT_SYMBOL(bcmsdh_regfail);
633 EXPORT_SYMBOL(bcmsdh_send_buf);
634 EXPORT_SYMBOL(bcmsdh_recv_buf);
635
636 EXPORT_SYMBOL(bcmsdh_rwdata);
637 EXPORT_SYMBOL(bcmsdh_abort);
638 EXPORT_SYMBOL(bcmsdh_query_device);
639 EXPORT_SYMBOL(bcmsdh_query_iofnum);
640 EXPORT_SYMBOL(bcmsdh_iovar_op);
641 EXPORT_SYMBOL(bcmsdh_register);
642 EXPORT_SYMBOL(bcmsdh_unregister);
643 EXPORT_SYMBOL(bcmsdh_chipmatch);
644 EXPORT_SYMBOL(bcmsdh_reset);
645
646 EXPORT_SYMBOL(bcmsdh_get_dstatus);
647 EXPORT_SYMBOL(bcmsdh_cfg_read_word);
648 EXPORT_SYMBOL(bcmsdh_cfg_write_word);
649 EXPORT_SYMBOL(bcmsdh_cur_sbwad);
650 EXPORT_SYMBOL(bcmsdh_chipinfo);
651
652 #endif /* BCMSDH_MODULE */
653