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 **)®s, 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 **)®s, 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 **)®s, 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