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