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