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