xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/bcmsdh_linux.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * SDIO access interface for drivers - linux specific (pci only)
3  *
4  * Copyright (C) 2020, Broadcom.
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  *
21  * <<Broadcom-WL-IPTag/Open:>>
22  *
23  * $Id$
24  */
25 
26 /**
27  * @file bcmsdh_linux.c
28  */
29 
30 #define __UNDEF_NO_VERSION__
31 
32 #include <typedefs.h>
33 #include <linuxver.h>
34 #include <linux/pci.h>
35 #include <linux/completion.h>
36 
37 #include <osl.h>
38 #include <pcicfg.h>
39 #include <bcmdefs.h>
40 #include <bcmdevs.h>
41 #include <linux/irq.h>
42 extern void dhdsdio_isr(void * args);
43 #include <bcmutils.h>
44 #include <dngl_stats.h>
45 #include <dhd.h>
46 #if defined(CONFIG_ARCH_ODIN)
47 #include <linux/platform_data/gpio-odin.h>
48 #endif /* defined(CONFIG_ARCH_ODIN) */
49 #include <dhd_linux.h>
50 
51 /* driver info, initialized when bcmsdh_register is called */
52 static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL};
53 
54 typedef enum {
55 	DHD_INTR_INVALID = 0,
56 	DHD_INTR_INBAND,
57 	DHD_INTR_HWOOB,
58 	DHD_INTR_SWOOB
59 } DHD_HOST_INTR_TYPE;
60 
61 /* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g.
62  * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather
63  * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this
64  * structure.
65  */
66 typedef struct bcmsdh_os_info {
67 	DHD_HOST_INTR_TYPE	intr_type;
68 	int			oob_irq_num;	/* valid when hardware or software oob in use */
69 	unsigned long		oob_irq_flags;	/* valid when hardware or software oob in use */
70 	bool			oob_irq_registered;
71 	bool			oob_irq_enabled;
72 	bool			oob_irq_wake_enabled;
73 	spinlock_t		oob_irq_spinlock;
74 	bcmsdh_cb_fn_t		oob_irq_handler;
75 	void			*oob_irq_handler_context;
76 	void			*context;	/* context returned from upper layer */
77 	void			*sdioh;		/* handle to lower layer (sdioh) */
78 	void			*dev;		/* handle to the underlying device */
79 	bool			dev_wake_enabled;
80 } bcmsdh_os_info_t;
81 
82 /* debugging macros */
83 #ifdef BCMDBG_ERR
84 #define SDLX_ERR(x) printf x
85 #define SDLX_MSG(x)	printf x
86 #else
87 #define SDLX_ERR(x) printf x
88 #define SDLX_MSG(x)	printf x
89 #endif /* BCMDBG_ERR */
90 
91 /**
92  * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
93  */
94 bool
bcmsdh_chipmatch(uint16 vendor,uint16 device)95 bcmsdh_chipmatch(uint16 vendor, uint16 device)
96 {
97 	/* Add other vendors and devices as required */
98 #ifdef BCMINTERNAL
99 #ifdef BCMSDIOH_BCM
100 	if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
101 		return (TRUE);
102 	}
103 	if (device == BCM_SDIOH_ID && vendor == VENDOR_BROADCOM) {
104 		return (TRUE);
105 	}
106 	if (device == BCM4710_DEVICE_ID && vendor == VENDOR_BROADCOM) {
107 		return (TRUE);
108 	}
109 	/* For now still accept the old devid */
110 	if (device == 0x4380 && vendor == VENDOR_BROADCOM) {
111 		return (TRUE);
112 	}
113 #endif /* BCMSDIOH_BCM */
114 #endif /* BCMINTERNAL */
115 
116 #ifdef BCMSDIOH_STD
117 	/* Check for Arasan host controller */
118 	if (vendor == VENDOR_SI_IMAGE) {
119 		return (TRUE);
120 	}
121 	/* Check for BRCM 27XX Standard host controller */
122 	if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
123 		return (TRUE);
124 	}
125 	/* Check for BRCM Standard host controller */
126 	if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
127 		return (TRUE);
128 	}
129 	/* Check for TI PCIxx21 Standard host controller */
130 	if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
131 		return (TRUE);
132 	}
133 	if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
134 		return (TRUE);
135 	}
136 	/* Ricoh R5C822 Standard SDIO Host */
137 	if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
138 		return (TRUE);
139 	}
140 	/* JMicron Standard SDIO Host */
141 	if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
142 		return (TRUE);
143 	}
144 
145 #ifdef BCMINTERNAL
146 	/* Check for Jinvani (C-Guys) host controller */
147 	if (device == JINVANI_SDIOH_ID && vendor == VENDOR_JINVANI) {
148 		return (TRUE);
149 	}
150 #endif /* BCMINTERNAL */
151 #endif /* BCMSDIOH_STD */
152 #ifdef BCMSDIOH_SPI
153 	/* This is the PciSpiHost. */
154 	if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
155 		printf("Found PCI SPI Host Controller\n");
156 		return (TRUE);
157 	}
158 
159 #ifdef BCMINTERNAL
160 	/* This is the SPI Host for QT. */
161 	if (device == BCM_SPIH_ID && vendor == VENDOR_BROADCOM) {
162 		printf("Found SPI Host Controller\n");
163 		return (TRUE);
164 	}
165 #endif /* BCMINTERNAL */
166 #endif /* BCMSDIOH_SPI */
167 
168 #ifdef BCMINTERNAL
169 	/*
170 	 * XXX - This is a hack to get the GPL SdioLinux driver to load on Arasan/x86
171 	 * This is accomplished by installing a PciSpiHost into the system alongside the
172 	 * Arasan controller.  The PciSpiHost is just used to get BCMSDH loaded.
173 	 */
174 #ifdef BCMSDH_FD
175 	if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
176 		printf("Found SdioLinux Host Controller\n");
177 		return (TRUE);
178 	}
179 #endif /* BCMSDH_FD */
180 #endif /* BCMINTERNAL */
181 	return (FALSE);
182 }
183 
bcmsdh_probe(osl_t * osh,void * dev,void * sdioh,void * adapter_info,uint bus_type,uint bus_num,uint slot_num)184 void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type,
185 	uint bus_num, uint slot_num)
186 {
187 	ulong regs;
188 	bcmsdh_info_t *bcmsdh;
189 	uint32 vendevid;
190 	bcmsdh_os_info_t *bcmsdh_osinfo = NULL;
191 
192 	bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
193 	if (bcmsdh == NULL) {
194 		SDLX_ERR(("%s: bcmsdh_attach failed\n", __FUNCTION__));
195 		goto err;
196 	}
197 	bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
198 	if (bcmsdh_osinfo == NULL) {
199 		SDLX_ERR(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__));
200 		goto err;
201 	}
202 	bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
203 	bcmsdh->os_cxt = bcmsdh_osinfo;
204 	bcmsdh_osinfo->sdioh = sdioh;
205 	bcmsdh_osinfo->dev = dev;
206 	osl_set_bus_handle(osh, bcmsdh);
207 
208 #if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
209 	if (dev && device_init_wakeup(dev, true) == 0)
210 		bcmsdh_osinfo->dev_wake_enabled = TRUE;
211 #endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
212 
213 #if defined(OOB_INTR_ONLY)
214 	spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock);
215 	/* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
216 	bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info,
217 		&bcmsdh_osinfo->oob_irq_flags);
218 	if  (bcmsdh_osinfo->oob_irq_num < 0) {
219 		SDLX_ERR(("%s: Host OOB irq is not defined\n", __FUNCTION__));
220 		goto err;
221 	}
222 #endif /* defined(BCMLXSDMMC) */
223 
224 	/* Read the vendor/device ID from the CIS */
225 	vendevid = bcmsdh_query_device(bcmsdh);
226 	/* try to attach to the target device */
227 	bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num,
228 		slot_num, 0, bus_type, (void *)regs, osh, bcmsdh);
229 	if (bcmsdh_osinfo->context == NULL) {
230 		SDLX_ERR(("%s: device attach failed\n", __FUNCTION__));
231 		goto err;
232 	}
233 
234 	return bcmsdh;
235 
236 	/* error handling */
237 err:
238 	if (bcmsdh != NULL)
239 		bcmsdh_detach(osh, bcmsdh);
240 	if (bcmsdh_osinfo != NULL)
241 		MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
242 	return NULL;
243 }
244 
bcmsdh_remove(bcmsdh_info_t * bcmsdh)245 int bcmsdh_remove(bcmsdh_info_t *bcmsdh)
246 {
247 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
248 
249 #if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
250 	if (bcmsdh_osinfo->dev)
251 		device_init_wakeup(bcmsdh_osinfo->dev, false);
252 	bcmsdh_osinfo->dev_wake_enabled = FALSE;
253 #endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
254 
255 	drvinfo.remove(bcmsdh_osinfo->context);
256 	MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t));
257 	bcmsdh_detach(bcmsdh->osh, bcmsdh);
258 
259 	return 0;
260 }
261 
262 #ifdef DHD_WAKE_STATUS
bcmsdh_get_total_wake(bcmsdh_info_t * bcmsdh)263 int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh)
264 {
265 	return bcmsdh->total_wake_count;
266 }
267 
bcmsdh_set_get_wake(bcmsdh_info_t * bcmsdh,int flag)268 int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag)
269 {
270 #if defined(OOB_INTR_ONLY)
271 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
272 	unsigned long flags;
273 #endif
274 	int ret = 0;
275 
276 #if defined(OOB_INTR_ONLY)
277 	spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
278 
279 	ret = bcmsdh->pkt_wake;
280 	bcmsdh->total_wake_count += flag;
281 	bcmsdh->pkt_wake = flag;
282 
283 	spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
284 #endif
285 	return ret;
286 }
287 #endif /* DHD_WAKE_STATUS */
288 
bcmsdh_suspend(bcmsdh_info_t * bcmsdh)289 int bcmsdh_suspend(bcmsdh_info_t *bcmsdh)
290 {
291 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
292 
293 	if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context))
294 		return -EBUSY;
295 	return 0;
296 }
297 
bcmsdh_resume(bcmsdh_info_t * bcmsdh)298 int bcmsdh_resume(bcmsdh_info_t *bcmsdh)
299 {
300 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
301 
302 	if (drvinfo.resume)
303 		return drvinfo.resume(bcmsdh_osinfo->context);
304 	return 0;
305 }
306 
307 extern int bcmsdh_register_client_driver(void);
308 extern void bcmsdh_unregister_client_driver(void);
309 extern int sdio_func_reg_notify(void* semaphore);
310 extern void sdio_func_unreg_notify(void);
311 
312 #if defined(BCMLXSDMMC)
bcmsdh_reg_sdio_notify(void * semaphore)313 int bcmsdh_reg_sdio_notify(void* semaphore)
314 {
315 	return sdio_func_reg_notify(semaphore);
316 }
317 
bcmsdh_unreg_sdio_notify(void)318 void bcmsdh_unreg_sdio_notify(void)
319 {
320 	sdio_func_unreg_notify();
321 }
322 #endif /* defined(BCMLXSDMMC) */
323 
324 int
bcmsdh_register(bcmsdh_driver_t * driver)325 bcmsdh_register(bcmsdh_driver_t *driver)
326 {
327 	int error = 0;
328 
329 	drvinfo = *driver;
330 	SDLX_MSG(("%s: register client driver\n", __FUNCTION__));
331 	error = bcmsdh_register_client_driver();
332 	if (error)
333 		SDLX_ERR(("%s: failed %d\n", __FUNCTION__, error));
334 
335 	return error;
336 }
337 
338 void
bcmsdh_unregister(void)339 bcmsdh_unregister(void)
340 {
341 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
342 		if (bcmsdh_pci_driver.node.next == NULL)
343 			return;
344 #endif
345 
346 	bcmsdh_unregister_client_driver();
347 }
348 
bcmsdh_get_dev(bcmsdh_info_t * sdh)349 void *bcmsdh_get_dev(bcmsdh_info_t *sdh)
350 {
351 	bcmsdh_os_info_t *bcmsdh_osinfo = sdh->os_cxt;
352 	return bcmsdh_osinfo->dev;
353 }
354 
bcmsdh_dev_pm_stay_awake(bcmsdh_info_t * bcmsdh)355 void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh)
356 {
357 #if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
358 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
359 	pm_stay_awake(bcmsdh_osinfo->dev);
360 #endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
361 }
362 
bcmsdh_dev_relax(bcmsdh_info_t * bcmsdh)363 void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh)
364 {
365 #if !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
366 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
367 	pm_relax(bcmsdh_osinfo->dev);
368 #endif /* !defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36)) */
369 }
370 
bcmsdh_dev_pm_enabled(bcmsdh_info_t * bcmsdh)371 bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh)
372 {
373 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
374 
375 	return bcmsdh_osinfo->dev_wake_enabled;
376 }
377 
378 #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
bcmsdh_get_oob_intr_num(bcmsdh_info_t * bcmsdh)379 int bcmsdh_get_oob_intr_num(bcmsdh_info_t *bcmsdh)
380 {
381 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
382 
383 	return bcmsdh_osinfo->oob_irq_num;
384 }
385 
bcmsdh_oob_intr_set(bcmsdh_info_t * bcmsdh,bool enable)386 void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable)
387 {
388 	unsigned long flags;
389 	bcmsdh_os_info_t *bcmsdh_osinfo;
390 
391 	if (!bcmsdh)
392 		return;
393 
394 	bcmsdh_osinfo = bcmsdh->os_cxt;
395 	spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
396 	if (bcmsdh_osinfo->oob_irq_enabled != enable) {
397 		if (enable)
398 			enable_irq(bcmsdh_osinfo->oob_irq_num);
399 		else
400 			disable_irq_nosync(bcmsdh_osinfo->oob_irq_num);
401 		bcmsdh_osinfo->oob_irq_enabled = enable;
402 	}
403 	spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
404 }
405 
406 #ifdef ENABLE_WAKEUP_PKT_DUMP
407 extern volatile bool dhd_mmc_suspend;
408 extern volatile bool dhd_mmc_wake;
409 #endif /* ENABLE_WAKEUP_PKT_DUMP */
410 
wlan_oob_irq(int irq,void * dev_id)411 static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
412 {
413 	bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id;
414 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
415 
416 #ifndef BCMSPI_ANDROID
417 	bcmsdh_oob_intr_set(bcmsdh, FALSE);
418 #endif /* !BCMSPI_ANDROID */
419 	bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context);
420 
421 #ifdef ENABLE_WAKEUP_PKT_DUMP
422 	if (dhd_mmc_suspend) {
423 		dhd_mmc_wake = TRUE;
424 	}
425 #endif /* ENABLE_WAKEUP_PKT_DUMP */
426 
427 	return IRQ_HANDLED;
428 }
429 
bcmsdh_oob_intr_register(bcmsdh_info_t * bcmsdh,bcmsdh_cb_fn_t oob_irq_handler,void * oob_irq_handler_context)430 int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler,
431 	void* oob_irq_handler_context)
432 {
433 	int err = 0;
434 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
435 
436 	if (bcmsdh_osinfo->oob_irq_registered) {
437 		SDLX_ERR(("%s: irq is already registered\n", __FUNCTION__));
438 		return -EBUSY;
439 	}
440 #ifdef HW_OOB
441 	SDLX_MSG(("%s: HW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
442 		(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
443 #else
444 	SDLX_MSG(("%s: SW_OOB irq=%d flags=0x%X\n", __FUNCTION__,
445 		(int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
446 #endif
447 	bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
448 	bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
449 	bcmsdh_osinfo->oob_irq_enabled = TRUE;
450 	bcmsdh_osinfo->oob_irq_registered = TRUE;
451 #if defined(CONFIG_ARCH_ODIN)
452 	err = odin_gpio_sms_request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
453 		bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
454 #else
455 	err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
456 		bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
457 #endif /* defined(CONFIG_ARCH_ODIN) */
458 	if (err) {
459 		SDLX_ERR(("%s: request_irq failed with %d\n", __FUNCTION__, err));
460 		bcmsdh_osinfo->oob_irq_enabled = FALSE;
461 		bcmsdh_osinfo->oob_irq_registered = FALSE;
462 		return err;
463 	}
464 
465 #if defined(DISABLE_WOWLAN)
466 	SDLX_MSG(("%s: disable_irq_wake\n", __FUNCTION__));
467 	bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
468 #else
469 #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
470 	if (device_may_wakeup(bcmsdh_osinfo->dev)) {
471 #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
472 		err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
473 		if (err)
474 			SDLX_ERR(("%s: enable_irq_wake failed with %d\n", __FUNCTION__, err));
475 		else
476 			bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
477 #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
478 	}
479 #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
480 #endif
481 
482 	return 0;
483 }
484 
bcmsdh_oob_intr_unregister(bcmsdh_info_t * bcmsdh)485 void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
486 {
487 	int err = 0;
488 	bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
489 
490 	SDLX_MSG(("%s: Enter\n", __FUNCTION__));
491 	if (!bcmsdh_osinfo->oob_irq_registered) {
492 		SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__));
493 		return;
494 	}
495 	if (bcmsdh_osinfo->oob_irq_wake_enabled) {
496 #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
497 		if (device_may_wakeup(bcmsdh_osinfo->dev)) {
498 #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
499 			err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
500 			if (!err)
501 				bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
502 #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
503 		}
504 #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
505 	}
506 	if (bcmsdh_osinfo->oob_irq_enabled) {
507 		disable_irq(bcmsdh_osinfo->oob_irq_num);
508 		bcmsdh_osinfo->oob_irq_enabled = FALSE;
509 	}
510 	free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
511 	bcmsdh_osinfo->oob_irq_registered = FALSE;
512 }
513 #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
514 
515 /* Module parameters specific to each host-controller driver */
516 /* XXX Need to move these to where they really belong! */
517 
518 extern uint sd_msglevel;	/* Debug message level */
519 module_param(sd_msglevel, uint, 0);
520 
521 extern uint sd_power;	/* 0 = SD Power OFF, 1 = SD Power ON. */
522 module_param(sd_power, uint, 0);
523 
524 extern uint sd_clock;	/* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
525 module_param(sd_clock, uint, 0);
526 
527 extern uint sd_divisor;	/* Divisor (-1 means external clock) */
528 module_param(sd_divisor, uint, 0);
529 
530 extern uint sd_sdmode;	/* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
531 module_param(sd_sdmode, uint, 0);
532 
533 extern uint sd_hiok;	/* Ok to use hi-speed mode */
534 module_param(sd_hiok, uint, 0);
535 
536 extern uint sd_f2_blocksize;
537 module_param(sd_f2_blocksize, int, 0);
538 
539 extern uint sd_f1_blocksize;
540 module_param(sd_f1_blocksize, int, 0);
541 
542 #ifdef BCMSDIOH_STD
543 extern int sd_uhsimode;
544 module_param(sd_uhsimode, int, 0);
545 extern uint sd_tuning_period;
546 module_param(sd_tuning_period, uint, 0);
547 extern int sd_delay_value;
548 module_param(sd_delay_value, uint, 0);
549 
550 /* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */
551 extern char dhd_sdiod_uhsi_ds_override[2];
552 module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0);
553 
554 #endif
555 
556 #ifdef BCMSDH_MODULE
557 EXPORT_SYMBOL(bcmsdh_attach);
558 EXPORT_SYMBOL(bcmsdh_detach);
559 EXPORT_SYMBOL(bcmsdh_intr_query);
560 EXPORT_SYMBOL(bcmsdh_intr_enable);
561 EXPORT_SYMBOL(bcmsdh_intr_disable);
562 EXPORT_SYMBOL(bcmsdh_intr_reg);
563 EXPORT_SYMBOL(bcmsdh_intr_dereg);
564 
565 #if defined(DHD_DEBUG) || defined(BCMDBG)
566 EXPORT_SYMBOL(bcmsdh_intr_pending);
567 #endif
568 
569 #if defined (BT_OVER_SDIO)
570 EXPORT_SYMBOL(bcmsdh_btsdio_interface_init);
571 #endif /* defined (BT_OVER_SDIO) */
572 
573 EXPORT_SYMBOL(bcmsdh_devremove_reg);
574 EXPORT_SYMBOL(bcmsdh_cfg_read);
575 EXPORT_SYMBOL(bcmsdh_cfg_write);
576 EXPORT_SYMBOL(bcmsdh_cis_read);
577 EXPORT_SYMBOL(bcmsdh_reg_read);
578 EXPORT_SYMBOL(bcmsdh_reg_write);
579 EXPORT_SYMBOL(bcmsdh_regfail);
580 EXPORT_SYMBOL(bcmsdh_send_buf);
581 EXPORT_SYMBOL(bcmsdh_recv_buf);
582 
583 EXPORT_SYMBOL(bcmsdh_rwdata);
584 EXPORT_SYMBOL(bcmsdh_abort);
585 EXPORT_SYMBOL(bcmsdh_query_device);
586 EXPORT_SYMBOL(bcmsdh_query_iofnum);
587 EXPORT_SYMBOL(bcmsdh_iovar_op);
588 EXPORT_SYMBOL(bcmsdh_register);
589 EXPORT_SYMBOL(bcmsdh_unregister);
590 EXPORT_SYMBOL(bcmsdh_chipmatch);
591 EXPORT_SYMBOL(bcmsdh_reset);
592 EXPORT_SYMBOL(bcmsdh_waitlockfree);
593 
594 EXPORT_SYMBOL(bcmsdh_get_dstatus);
595 EXPORT_SYMBOL(bcmsdh_cfg_read_word);
596 EXPORT_SYMBOL(bcmsdh_cfg_write_word);
597 EXPORT_SYMBOL(bcmsdh_cur_sbwad);
598 EXPORT_SYMBOL(bcmsdh_chipinfo);
599 
600 #endif /* BCMSDH_MODULE */
601