Home | History | Annotate | Download | only in sys
      1 /*
      2  * SDIO access interface for drivers - linux specific (pci only)
      3  *
      4  * Copyright (C) 1999-2010, 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.12 2010/03/10 03:09:48 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 	unsigned long oob_flags;
     79 };
     80 static bcmsdh_hc_t *sdhcinfo = NULL;
     81 
     82 /* driver info, initialized when bcmsdh_register is called */
     83 static bcmsdh_driver_t drvinfo = {NULL, NULL};
     84 
     85 /* debugging macros */
     86 #define SDLX_MSG(x)
     87 
     88 /**
     89  * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
     90  */
     91 bool
     92 bcmsdh_chipmatch(uint16 vendor, uint16 device)
     93 {
     94 	/* Add other vendors and devices as required */
     95 
     96 #ifdef BCMSDIOH_STD
     97 	/* Check for Arasan host controller */
     98 	if (vendor == VENDOR_SI_IMAGE) {
     99 		return (TRUE);
    100 	}
    101 	/* Check for BRCM 27XX Standard host controller */
    102 	if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
    103 		return (TRUE);
    104 	}
    105 	/* Check for BRCM Standard host controller */
    106 	if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
    107 		return (TRUE);
    108 	}
    109 	/* Check for TI PCIxx21 Standard host controller */
    110 	if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
    111 		return (TRUE);
    112 	}
    113 	if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
    114 		return (TRUE);
    115 	}
    116 	/* Ricoh R5C822 Standard SDIO Host */
    117 	if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
    118 		return (TRUE);
    119 	}
    120 	/* JMicron Standard SDIO Host */
    121 	if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
    122 		return (TRUE);
    123 	}
    124 
    125 #endif /* BCMSDIOH_STD */
    126 #ifdef BCMSDIOH_SPI
    127 	/* This is the PciSpiHost. */
    128 	if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
    129 		printf("Found PCI SPI Host Controller\n");
    130 		return (TRUE);
    131 	}
    132 
    133 #endif /* BCMSDIOH_SPI */
    134 
    135 	return (FALSE);
    136 }
    137 
    138 #if defined(BCMPLATFORM_BUS)
    139 #if defined(BCMLXSDMMC)
    140 /* forward declarations */
    141 int bcmsdh_probe(struct device *dev);
    142 int bcmsdh_remove(struct device *dev);
    143 
    144 EXPORT_SYMBOL(bcmsdh_probe);
    145 EXPORT_SYMBOL(bcmsdh_remove);
    146 
    147 #else
    148 /* forward declarations */
    149 static int __devinit bcmsdh_probe(struct device *dev);
    150 static int __devexit bcmsdh_remove(struct device *dev);
    151 #endif /* BCMLXSDMMC */
    152 
    153 #ifndef BCMLXSDMMC
    154 static struct device_driver bcmsdh_driver = {
    155 	.name		= "pxa2xx-mci",
    156 	.bus		= &platform_bus_type,
    157 	.probe		= bcmsdh_probe,
    158 	.remove		= bcmsdh_remove,
    159 	.suspend	= NULL,
    160 	.resume		= NULL,
    161 	};
    162 #endif /* BCMLXSDMMC */
    163 
    164 #ifndef BCMLXSDMMC
    165 static
    166 #endif /* BCMLXSDMMC */
    167 int bcmsdh_probe(struct device *dev)
    168 {
    169 	osl_t *osh = NULL;
    170 	bcmsdh_hc_t *sdhc = NULL;
    171 	ulong regs = 0;
    172 	bcmsdh_info_t *sdh = NULL;
    173 #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
    174 	struct platform_device *pdev;
    175 	struct resource *r;
    176 #endif /* BCMLXSDMMC */
    177 	int irq = 0;
    178 	uint32 vendevid;
    179 	unsigned long irq_flags = IRQF_TRIGGER_FALLING;
    180 
    181 #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
    182 	pdev = to_platform_device(dev);
    183 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    184 	irq = platform_get_irq(pdev, 0);
    185 	if (!r || irq == NO_IRQ)
    186 		return -ENXIO;
    187 #endif /* BCMLXSDMMC */
    188 
    189 #if defined(OOB_INTR_ONLY)
    190 	irq = dhd_customer_oob_irq_map(&irq_flags);
    191 	if  (irq < 0) {
    192 		SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
    193 		return 1;
    194 	}
    195 #endif /* defined(OOB_INTR_ONLY) */
    196 	/* allocate SDIO Host Controller state info */
    197 	if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
    198 		SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
    199 		goto err;
    200 	}
    201 	if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
    202 		SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
    203 			__FUNCTION__,
    204 			MALLOCED(osh)));
    205 		goto err;
    206 	}
    207 	bzero(sdhc, sizeof(bcmsdh_hc_t));
    208 	sdhc->osh = osh;
    209 
    210 	sdhc->dev = (void *)dev;
    211 
    212 #ifdef BCMLXSDMMC
    213 	if (!(sdh = bcmsdh_attach(osh, (void *)0,
    214 	                          (void **)&regs, irq))) {
    215 		SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
    216 		goto err;
    217 	}
    218 #else
    219 	if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
    220 	                          (void **)&regs, irq))) {
    221 		SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
    222 		goto err;
    223 	}
    224 #endif /* BCMLXSDMMC */
    225 	sdhc->sdh = sdh;
    226 	sdhc->oob_irq = irq;
    227 	sdhc->oob_flags = irq_flags;
    228 
    229 	/* chain SDIO Host Controller info together */
    230 	sdhc->next = sdhcinfo;
    231 	sdhcinfo = sdhc;
    232 	/* Read the vendor/device ID from the CIS */
    233 	vendevid = bcmsdh_query_device(sdh);
    234 
    235 	/* try to attach to the target device */
    236 	if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
    237 	                                 (vendevid & 0xFFFF), 0, 0, 0, 0,
    238 	                                (void *)regs, NULL, sdh))) {
    239 		SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
    240 		goto err;
    241 	}
    242 
    243 	return 0;
    244 
    245 	/* error handling */
    246 err:
    247 	if (sdhc) {
    248 		if (sdhc->sdh)
    249 			bcmsdh_detach(sdhc->osh, sdhc->sdh);
    250 		MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
    251 	}
    252 	if (osh)
    253 		osl_detach(osh);
    254 	return -ENODEV;
    255 }
    256 
    257 #ifndef BCMLXSDMMC
    258 static
    259 #endif /* BCMLXSDMMC */
    260 int bcmsdh_remove(struct device *dev)
    261 {
    262 	bcmsdh_hc_t *sdhc, *prev;
    263 	osl_t *osh;
    264 
    265 	sdhc = sdhcinfo;
    266 	drvinfo.detach(sdhc->ch);
    267 	bcmsdh_detach(sdhc->osh, sdhc->sdh);
    268 	/* find the SDIO Host Controller state for this pdev and take it out from the list */
    269 	for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
    270 		if (sdhc->dev == (void *)dev) {
    271 			if (prev)
    272 				prev->next = sdhc->next;
    273 			else
    274 				sdhcinfo = NULL;
    275 			break;
    276 		}
    277 		prev = sdhc;
    278 	}
    279 	if (!sdhc) {
    280 		SDLX_MSG(("%s: failed\n", __FUNCTION__));
    281 		return 0;
    282 	}
    283 
    284 
    285 	/* release SDIO Host Controller info */
    286 	osh = sdhc->osh;
    287 	MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
    288 	osl_detach(osh);
    289 
    290 #if !defined(BCMLXSDMMC)
    291 	dev_set_drvdata(dev, NULL);
    292 #endif /* !defined(BCMLXSDMMC) */
    293 
    294 	return 0;
    295 }
    296 
    297 #else /* BCMPLATFORM_BUS */
    298 
    299 #if !defined(BCMLXSDMMC)
    300 /* forward declarations for PCI probe and remove functions. */
    301 static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
    302 static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
    303 
    304 /**
    305  * pci id table
    306  */
    307 static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
    308 	{ vendor: PCI_ANY_ID,
    309 	device: PCI_ANY_ID,
    310 	subvendor: PCI_ANY_ID,
    311 	subdevice: PCI_ANY_ID,
    312 	class: 0,
    313 	class_mask: 0,
    314 	driver_data: 0,
    315 	},
    316 	{ 0, }
    317 };
    318 MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
    319 
    320 /**
    321  * SDIO Host Controller pci driver info
    322  */
    323 static struct pci_driver bcmsdh_pci_driver = {
    324 	node:		{},
    325 	name:		"bcmsdh",
    326 	id_table:	bcmsdh_pci_devid,
    327 	probe:		bcmsdh_pci_probe,
    328 	remove:		bcmsdh_pci_remove,
    329 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
    330 	save_state:	NULL,
    331 #endif
    332 	suspend:	NULL,
    333 	resume:		NULL,
    334 };
    335 
    336 
    337 extern uint sd_pci_slot;	/* Force detection to a particular PCI */
    338 				/* slot only . Allows for having multiple */
    339 				/* WL devices at once in a PC */
    340 				/* Only one instance of dhd will be */
    341 				/* useable at a time */
    342 				/* Upper word is bus number, */
    343 				/* lower word is slot number */
    344 				/* Default value of 0xFFFFffff turns this */
    345 				/* off */
    346 module_param(sd_pci_slot, uint, 0);
    347 
    348 
    349 /**
    350  * Detect supported SDIO Host Controller and attach if found.
    351  *
    352  * Determine if the device described by pdev is a supported SDIO Host
    353  * Controller.  If so, attach to it and attach to the target device.
    354  */
    355 static int __devinit
    356 bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
    357 {
    358 	osl_t *osh = NULL;
    359 	bcmsdh_hc_t *sdhc = NULL;
    360 	ulong regs;
    361 	bcmsdh_info_t *sdh = NULL;
    362 	int rc;
    363 
    364 	if (sd_pci_slot != 0xFFFFffff) {
    365 		if (pdev->bus->number != (sd_pci_slot>>16) ||
    366 			PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
    367 			SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
    368 				__FUNCTION__,
    369 				bcmsdh_chipmatch(pdev->vendor, pdev->device)
    370 				? "Found compatible SDIOHC"
    371 				: "Probing unknown device",
    372 				pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
    373 				pdev->device));
    374 			return -ENODEV;
    375 		}
    376 		SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
    377 			__FUNCTION__,
    378 			bcmsdh_chipmatch(pdev->vendor, pdev->device)
    379 			? "Using compatible SDIOHC"
    380 			: "WARNING, forced use of unkown device",
    381 			pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device));
    382 	}
    383 
    384 	if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
    385 	    (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
    386 		uint32 config_reg;
    387 
    388 		SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
    389 		if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
    390 			SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
    391 			goto err;
    392 		}
    393 
    394 		config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
    395 
    396 		/*
    397 		 * Set MMC_SD_DIS bit in FlashMedia Controller.
    398 		 * Disbling the SD/MMC Controller in the FlashMedia Controller
    399 		 * allows the Standard SD Host Controller to take over control
    400 		 * of the SD Slot.
    401 		 */
    402 		config_reg |= 0x02;
    403 		OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
    404 		osl_detach(osh);
    405 	}
    406 	/* match this pci device with what we support */
    407 	/* we can't solely rely on this to believe it is our SDIO Host Controller! */
    408 	if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
    409 		return -ENODEV;
    410 	}
    411 
    412 	/* this is a pci device we might support */
    413 	SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
    414 		__FUNCTION__,
    415 		pdev->bus->number, PCI_SLOT(pdev->devfn),
    416 		PCI_FUNC(pdev->devfn), pdev->irq));
    417 
    418 	/* use bcmsdh_query_device() to get the vendor ID of the target device so
    419 	 * it will eventually appear in the Broadcom string on the console
    420 	 */
    421 
    422 	/* allocate SDIO Host Controller state info */
    423 	if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
    424 		SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
    425 		goto err;
    426 	}
    427 	if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
    428 		SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
    429 			__FUNCTION__,
    430 			MALLOCED(osh)));
    431 		goto err;
    432 	}
    433 	bzero(sdhc, sizeof(bcmsdh_hc_t));
    434 	sdhc->osh = osh;
    435 
    436 	sdhc->dev = pdev;
    437 
    438 	/* map to address where host can access */
    439 	pci_set_master(pdev);
    440 	rc = pci_enable_device(pdev);
    441 	if (rc) {
    442 		SDLX_MSG(("%s: Cannot enble PCI device\n", __FUNCTION__));
    443 		goto err;
    444 	}
    445 	if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
    446 	                          (void **)&regs, pdev->irq))) {
    447 		SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
    448 		goto err;
    449 	}
    450 
    451 	sdhc->sdh = sdh;
    452 
    453 	/* try to attach to the target device */
    454 	if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
    455 	                                bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
    456 	                                (void *)regs, NULL, sdh))) {
    457 		SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
    458 		goto err;
    459 	}
    460 
    461 	/* chain SDIO Host Controller info together */
    462 	sdhc->next = sdhcinfo;
    463 	sdhcinfo = sdhc;
    464 
    465 	return 0;
    466 
    467 	/* error handling */
    468 err:
    469 	if (sdhc->sdh)
    470 		bcmsdh_detach(sdhc->osh, sdhc->sdh);
    471 	if (sdhc)
    472 		MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
    473 	if (osh)
    474 		osl_detach(osh);
    475 	return -ENODEV;
    476 }
    477 
    478 
    479 /**
    480  * Detach from target devices and SDIO Host Controller
    481  */
    482 static void __devexit
    483 bcmsdh_pci_remove(struct pci_dev *pdev)
    484 {
    485 	bcmsdh_hc_t *sdhc, *prev;
    486 	osl_t *osh;
    487 
    488 	/* find the SDIO Host Controller state for this pdev and take it out from the list */
    489 	for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
    490 		if (sdhc->dev == pdev) {
    491 			if (prev)
    492 				prev->next = sdhc->next;
    493 			else
    494 				sdhcinfo = NULL;
    495 			break;
    496 		}
    497 		prev = sdhc;
    498 	}
    499 	if (!sdhc)
    500 		return;
    501 
    502 	drvinfo.detach(sdhc->ch);
    503 
    504 	bcmsdh_detach(sdhc->osh, sdhc->sdh);
    505 
    506 	/* release SDIO Host Controller info */
    507 	osh = sdhc->osh;
    508 	MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
    509 	osl_detach(osh);
    510 }
    511 #endif /* BCMLXSDMMC */
    512 #endif /* BCMPLATFORM_BUS */
    513 
    514 extern int sdio_function_init(void);
    515 
    516 int
    517 bcmsdh_register(bcmsdh_driver_t *driver)
    518 {
    519 	int error = 0;
    520 
    521 	drvinfo = *driver;
    522 
    523 #if defined(BCMPLATFORM_BUS)
    524 #if defined(BCMLXSDMMC)
    525 	SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
    526 	error = sdio_function_init();
    527 #else
    528 	SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
    529 	error = driver_register(&bcmsdh_driver);
    530 #endif /* defined(BCMLXSDMMC) */
    531 	return error;
    532 #endif /* defined(BCMPLATFORM_BUS) */
    533 
    534 #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
    535 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
    536 	if (!(error = pci_module_init(&bcmsdh_pci_driver)))
    537 		return 0;
    538 #else
    539 	if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
    540 		return 0;
    541 #endif
    542 
    543 	SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
    544 #endif /* BCMPLATFORM_BUS */
    545 
    546 	return error;
    547 }
    548 
    549 extern void sdio_function_cleanup(void);
    550 
    551 void
    552 bcmsdh_unregister(void)
    553 {
    554 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
    555 	if (bcmsdh_pci_driver.node.next)
    556 #endif
    557 
    558 #if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
    559 		driver_unregister(&bcmsdh_driver);
    560 #endif
    561 #if defined(BCMLXSDMMC)
    562 	sdio_function_cleanup();
    563 #endif /* BCMLXSDMMC */
    564 #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
    565 		pci_unregister_driver(&bcmsdh_pci_driver);
    566 #endif /* BCMPLATFORM_BUS */
    567 }
    568 
    569 #if defined(OOB_INTR_ONLY)
    570 static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
    571 {
    572 	dhd_pub_t *dhdp;
    573 
    574 	dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev);
    575 
    576 	if (dhdp == NULL) {
    577 		disable_irq(sdhcinfo->oob_irq);
    578 		SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
    579 		return IRQ_HANDLED;
    580 	}
    581 
    582 	dhdsdio_isr((void *)dhdp->bus);
    583 
    584 	return IRQ_HANDLED;
    585 }
    586 
    587 int bcmsdh_register_oob_intr(void * dhdp)
    588 {
    589 	int error = 0;
    590 
    591 	SDLX_MSG(("%s Enter\n", __FUNCTION__));
    592 
    593 	dev_set_drvdata(sdhcinfo->dev, dhdp);
    594 
    595 	/* Refer to customer Host IRQ docs about proper irqflags definition */
    596 	error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
    597 		"bcmsdh_sdmmc", NULL);
    598 
    599 	if (error)
    600 		return -ENODEV;
    601 
    602 	set_irq_wake(sdhcinfo->oob_irq, 1);
    603 
    604 	return 0;
    605 }
    606 
    607 void bcmsdh_unregister_oob_intr(void)
    608 {
    609 	SDLX_MSG(("%s: Enter\n", __FUNCTION__));
    610 
    611 	set_irq_wake(sdhcinfo->oob_irq, 0);
    612 	disable_irq(sdhcinfo->oob_irq);	/* just in case.. */
    613 	free_irq(sdhcinfo->oob_irq, NULL);
    614 }
    615 
    616 void bcmsdh_oob_intr_set(bool enable)
    617 {
    618 	if (enable)
    619 		enable_irq(sdhcinfo->oob_irq);
    620 	else
    621 		disable_irq(sdhcinfo->oob_irq);
    622 }
    623 #endif /* defined(OOB_INTR_ONLY) */
    624 /* Module parameters specific to each host-controller driver */
    625 
    626 extern uint sd_msglevel;	/* Debug message level */
    627 module_param(sd_msglevel, uint, 0);
    628 
    629 extern uint sd_power;	/* 0 = SD Power OFF, 1 = SD Power ON. */
    630 module_param(sd_power, uint, 0);
    631 
    632 extern uint sd_clock;	/* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
    633 module_param(sd_clock, uint, 0);
    634 
    635 extern uint sd_divisor;	/* Divisor (-1 means external clock) */
    636 module_param(sd_divisor, uint, 0);
    637 
    638 extern uint sd_sdmode;	/* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
    639 module_param(sd_sdmode, uint, 0);
    640 
    641 extern uint sd_hiok;	/* Ok to use hi-speed mode */
    642 module_param(sd_hiok, uint, 0);
    643 
    644 extern uint sd_f2_blocksize;
    645 module_param(sd_f2_blocksize, int, 0);
    646 
    647 
    648 #ifdef BCMSDH_MODULE
    649 EXPORT_SYMBOL(bcmsdh_attach);
    650 EXPORT_SYMBOL(bcmsdh_detach);
    651 EXPORT_SYMBOL(bcmsdh_intr_query);
    652 EXPORT_SYMBOL(bcmsdh_intr_enable);
    653 EXPORT_SYMBOL(bcmsdh_intr_disable);
    654 EXPORT_SYMBOL(bcmsdh_intr_reg);
    655 EXPORT_SYMBOL(bcmsdh_intr_dereg);
    656 
    657 #if defined(DHD_DEBUG)
    658 EXPORT_SYMBOL(bcmsdh_intr_pending);
    659 #endif
    660 
    661 EXPORT_SYMBOL(bcmsdh_devremove_reg);
    662 EXPORT_SYMBOL(bcmsdh_cfg_read);
    663 EXPORT_SYMBOL(bcmsdh_cfg_write);
    664 EXPORT_SYMBOL(bcmsdh_cis_read);
    665 EXPORT_SYMBOL(bcmsdh_reg_read);
    666 EXPORT_SYMBOL(bcmsdh_reg_write);
    667 EXPORT_SYMBOL(bcmsdh_regfail);
    668 EXPORT_SYMBOL(bcmsdh_send_buf);
    669 EXPORT_SYMBOL(bcmsdh_recv_buf);
    670 
    671 EXPORT_SYMBOL(bcmsdh_rwdata);
    672 EXPORT_SYMBOL(bcmsdh_abort);
    673 EXPORT_SYMBOL(bcmsdh_query_device);
    674 EXPORT_SYMBOL(bcmsdh_query_iofnum);
    675 EXPORT_SYMBOL(bcmsdh_iovar_op);
    676 EXPORT_SYMBOL(bcmsdh_register);
    677 EXPORT_SYMBOL(bcmsdh_unregister);
    678 EXPORT_SYMBOL(bcmsdh_chipmatch);
    679 EXPORT_SYMBOL(bcmsdh_reset);
    680 
    681 EXPORT_SYMBOL(bcmsdh_get_dstatus);
    682 EXPORT_SYMBOL(bcmsdh_cfg_read_word);
    683 EXPORT_SYMBOL(bcmsdh_cfg_write_word);
    684 EXPORT_SYMBOL(bcmsdh_cur_sbwad);
    685 EXPORT_SYMBOL(bcmsdh_chipinfo);
    686 
    687 #endif /* BCMSDH_MODULE */
    688