bcmsdh_linux.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. /*
  2. * SDIO access interface for drivers - linux specific (pci only)
  3. *
  4. * Copyright (C) 1999-2010, 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,v 1.42.10.10.2.14.4.2 2010/09/15 00:30:11 Exp $
  25. */
  26. /**
  27. * @file bcmsdh_linux.c
  28. */
  29. #define __UNDEF_NO_VERSION__
  30. #include <typedefs.h>
  31. #include <linuxver.h>
  32. #include <linux/pci.h>
  33. #include <linux/completion.h>
  34. #include <osl.h>
  35. #include <pcicfg.h>
  36. #include <bcmdefs.h>
  37. #include <bcmdevs.h>
  38. #if defined(OOB_INTR_ONLY)
  39. #include <linux/irq.h>
  40. extern void dhdsdio_isr(void * args);
  41. #include <bcmutils.h>
  42. #include <dngl_stats.h>
  43. #include <dhd.h>
  44. #endif /* defined(OOB_INTR_ONLY) */
  45. #if defined(CONFIG_MACH_SANDGATE2G) || defined(CONFIG_MACH_LOGICPD_PXA270)
  46. #if !defined(BCMPLATFORM_BUS)
  47. #define BCMPLATFORM_BUS
  48. #endif /* !defined(BCMPLATFORM_BUS) */
  49. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
  50. #include <linux/platform_device.h>
  51. #endif /* KERNEL_VERSION(2, 6, 19) */
  52. #endif /* CONFIG_MACH_SANDGATE2G || CONFIG_MACH_LOGICPD_PXA270 */
  53. /**
  54. * SDIO Host Controller info
  55. */
  56. typedef struct bcmsdh_hc bcmsdh_hc_t;
  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. #if defined(OOB_INTR_ONLY)
  72. spinlock_t irq_lock;
  73. #endif
  74. };
  75. static bcmsdh_hc_t *sdhcinfo = NULL;
  76. /* driver info, initialized when bcmsdh_register is called */
  77. static bcmsdh_driver_t drvinfo = {NULL, NULL};
  78. /* debugging macros */
  79. #define SDLX_MSG(x)
  80. /**
  81. * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
  82. */
  83. bool
  84. bcmsdh_chipmatch(uint16 vendor, uint16 device)
  85. {
  86. /* Add other vendors and devices as required */
  87. #ifdef BCMSDIOH_STD
  88. /* Check for Arasan host controller */
  89. if (vendor == VENDOR_SI_IMAGE) {
  90. return (TRUE);
  91. }
  92. /* Check for BRCM 27XX Standard host controller */
  93. if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
  94. return (TRUE);
  95. }
  96. /* Check for BRCM Standard host controller */
  97. if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
  98. return (TRUE);
  99. }
  100. /* Check for TI PCIxx21 Standard host controller */
  101. if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
  102. return (TRUE);
  103. }
  104. if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
  105. return (TRUE);
  106. }
  107. /* Ricoh R5C822 Standard SDIO Host */
  108. if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
  109. return (TRUE);
  110. }
  111. /* JMicron Standard SDIO Host */
  112. if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
  113. return (TRUE);
  114. }
  115. #endif /* BCMSDIOH_STD */
  116. #ifdef BCMSDIOH_SPI
  117. /* This is the PciSpiHost. */
  118. if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
  119. printf("Found PCI SPI Host Controller\n");
  120. return (TRUE);
  121. }
  122. #endif /* BCMSDIOH_SPI */
  123. return (FALSE);
  124. }
  125. #if defined(BCMPLATFORM_BUS)
  126. #if defined(BCMLXSDMMC)
  127. /* forward declarations */
  128. int bcmsdh_probe(struct device *dev);
  129. int bcmsdh_remove(struct device *dev);
  130. EXPORT_SYMBOL(bcmsdh_probe);
  131. EXPORT_SYMBOL(bcmsdh_remove);
  132. #else
  133. /* forward declarations */
  134. static int __devinit bcmsdh_probe(struct device *dev);
  135. static int __devexit bcmsdh_remove(struct device *dev);
  136. #endif /* BCMLXSDMMC */
  137. #ifndef BCMLXSDMMC
  138. static struct device_driver bcmsdh_driver = {
  139. .name = "pxa2xx-mci",
  140. .bus = &platform_bus_type,
  141. .probe = bcmsdh_probe,
  142. .remove = bcmsdh_remove,
  143. .suspend = NULL,
  144. .resume = NULL,
  145. };
  146. #endif /* BCMLXSDMMC */
  147. #ifndef BCMLXSDMMC
  148. static
  149. #endif /* BCMLXSDMMC */
  150. int bcmsdh_probe(struct device *dev)
  151. {
  152. osl_t *osh = NULL;
  153. bcmsdh_hc_t *sdhc = NULL;
  154. ulong regs = 0;
  155. bcmsdh_info_t *sdh = NULL;
  156. #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
  157. struct platform_device *pdev;
  158. struct resource *r;
  159. #endif /* BCMLXSDMMC */
  160. int irq = 0;
  161. uint32 vendevid;
  162. unsigned long irq_flags = 0;
  163. #if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
  164. pdev = to_platform_device(dev);
  165. r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  166. irq = platform_get_irq(pdev, 0);
  167. if (!r || irq == NO_IRQ)
  168. return -ENXIO;
  169. #endif /* BCMLXSDMMC */
  170. #if defined(OOB_INTR_ONLY)
  171. #ifdef HW_OOB
  172. irq_flags = \
  173. IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
  174. #else
  175. irq_flags = IRQF_TRIGGER_FALLING;
  176. #endif /* HW_OOB */
  177. irq = dhd_customer_oob_irq_map(&irq_flags);
  178. if (irq < 0) {
  179. SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
  180. return 1;
  181. }
  182. #endif /* defined(OOB_INTR_ONLY) */
  183. /* allocate SDIO Host Controller state info */
  184. if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
  185. SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
  186. goto err;
  187. }
  188. if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
  189. SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
  190. __FUNCTION__,
  191. MALLOCED(osh)));
  192. goto err;
  193. }
  194. bzero(sdhc, sizeof(bcmsdh_hc_t));
  195. sdhc->osh = osh;
  196. sdhc->dev = (void *)dev;
  197. #ifdef BCMLXSDMMC
  198. if (!(sdh = bcmsdh_attach(osh, (void *)0,
  199. (void **)&regs, irq))) {
  200. SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
  201. goto err;
  202. }
  203. #else
  204. if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
  205. (void **)&regs, irq))) {
  206. SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
  207. goto err;
  208. }
  209. #endif /* BCMLXSDMMC */
  210. sdhc->sdh = sdh;
  211. sdhc->oob_irq = irq;
  212. sdhc->oob_flags = irq_flags;
  213. sdhc->oob_irq_registered = FALSE; /* to make sure.. */
  214. #if defined(OOB_INTR_ONLY)
  215. spin_lock_init(&sdhc->irq_lock);
  216. #endif
  217. /* chain SDIO Host Controller info together */
  218. sdhc->next = sdhcinfo;
  219. sdhcinfo = sdhc;
  220. /* Read the vendor/device ID from the CIS */
  221. vendevid = bcmsdh_query_device(sdh);
  222. /* try to attach to the target device */
  223. if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
  224. (vendevid & 0xFFFF), 0, 0, 0, 0,
  225. (void *)regs, NULL, sdh))) {
  226. SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
  227. goto err;
  228. }
  229. return 0;
  230. /* error handling */
  231. err:
  232. if (sdhc) {
  233. if (sdhc->sdh)
  234. bcmsdh_detach(sdhc->osh, sdhc->sdh);
  235. MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
  236. }
  237. if (osh)
  238. osl_detach(osh);
  239. return -ENODEV;
  240. }
  241. #ifndef BCMLXSDMMC
  242. static
  243. #endif /* BCMLXSDMMC */
  244. int bcmsdh_remove(struct device *dev)
  245. {
  246. bcmsdh_hc_t *sdhc, *prev;
  247. osl_t *osh;
  248. sdhc = sdhcinfo;
  249. drvinfo.detach(sdhc->ch);
  250. bcmsdh_detach(sdhc->osh, sdhc->sdh);
  251. /* find the SDIO Host Controller state for this pdev and take it out from the list */
  252. for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
  253. if (sdhc->dev == (void *)dev) {
  254. if (prev)
  255. prev->next = sdhc->next;
  256. else
  257. sdhcinfo = NULL;
  258. break;
  259. }
  260. prev = sdhc;
  261. }
  262. if (!sdhc) {
  263. SDLX_MSG(("%s: failed\n", __FUNCTION__));
  264. return 0;
  265. }
  266. /* release SDIO Host Controller info */
  267. osh = sdhc->osh;
  268. MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
  269. osl_detach(osh);
  270. #if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY)
  271. dev_set_drvdata(dev, NULL);
  272. #endif /* !defined(BCMLXSDMMC) */
  273. return 0;
  274. }
  275. #else /* BCMPLATFORM_BUS */
  276. #if !defined(BCMLXSDMMC)
  277. /* forward declarations for PCI probe and remove functions. */
  278. static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
  279. static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
  280. /**
  281. * pci id table
  282. */
  283. static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
  284. { vendor: PCI_ANY_ID,
  285. device: PCI_ANY_ID,
  286. subvendor: PCI_ANY_ID,
  287. subdevice: PCI_ANY_ID,
  288. class: 0,
  289. class_mask: 0,
  290. driver_data: 0,
  291. },
  292. { 0, }
  293. };
  294. MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
  295. /**
  296. * SDIO Host Controller pci driver info
  297. */
  298. static struct pci_driver bcmsdh_pci_driver = {
  299. node: {},
  300. name: "bcmsdh",
  301. id_table: bcmsdh_pci_devid,
  302. probe: bcmsdh_pci_probe,
  303. remove: bcmsdh_pci_remove,
  304. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
  305. save_state: NULL,
  306. #endif
  307. suspend: NULL,
  308. resume: NULL,
  309. };
  310. extern uint sd_pci_slot; /* Force detection to a particular PCI */
  311. /* slot only . Allows for having multiple */
  312. /* WL devices at once in a PC */
  313. /* Only one instance of dhd will be */
  314. /* usable at a time */
  315. /* Upper word is bus number, */
  316. /* lower word is slot number */
  317. /* Default value of 0xFFFFffff turns this */
  318. /* off */
  319. module_param(sd_pci_slot, uint, 0);
  320. /**
  321. * Detect supported SDIO Host Controller and attach if found.
  322. *
  323. * Determine if the device described by pdev is a supported SDIO Host
  324. * Controller. If so, attach to it and attach to the target device.
  325. */
  326. static int __devinit
  327. bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  328. {
  329. osl_t *osh = NULL;
  330. bcmsdh_hc_t *sdhc = NULL;
  331. ulong regs;
  332. bcmsdh_info_t *sdh = NULL;
  333. int rc;
  334. if (sd_pci_slot != 0xFFFFffff) {
  335. if (pdev->bus->number != (sd_pci_slot>>16) ||
  336. PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
  337. SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
  338. __FUNCTION__,
  339. bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
  340. "Found compatible SDIOHC" :
  341. "Probing unknown device",
  342. pdev->bus->number, PCI_SLOT(pdev->devfn),
  343. pdev->vendor, pdev->device));
  344. return -ENODEV;
  345. }
  346. SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
  347. __FUNCTION__,
  348. bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
  349. "Using compatible SDIOHC" :
  350. "WARNING, forced use of unkown device",
  351. pdev->bus->number, PCI_SLOT(pdev->devfn),
  352. pdev->vendor, pdev->device));
  353. }
  354. if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
  355. (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
  356. uint32 config_reg;
  357. SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
  358. if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
  359. SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
  360. goto err;
  361. }
  362. config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
  363. /*
  364. * Set MMC_SD_DIS bit in FlashMedia Controller.
  365. * Disbling the SD/MMC Controller in the FlashMedia Controller
  366. * allows the Standard SD Host Controller to take over control
  367. * of the SD Slot.
  368. */
  369. config_reg |= 0x02;
  370. OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
  371. osl_detach(osh);
  372. }
  373. /* match this pci device with what we support */
  374. /* we can't solely rely on this to believe it is our SDIO Host Controller! */
  375. if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
  376. return -ENODEV;
  377. }
  378. /* this is a pci device we might support */
  379. SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
  380. __FUNCTION__,
  381. pdev->bus->number, PCI_SLOT(pdev->devfn),
  382. PCI_FUNC(pdev->devfn), pdev->irq));
  383. /* use bcmsdh_query_device() to get the vendor ID of the target device so
  384. * it will eventually appear in the Broadcom string on the console
  385. */
  386. /* allocate SDIO Host Controller state info */
  387. if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
  388. SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
  389. goto err;
  390. }
  391. if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
  392. SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
  393. __FUNCTION__,
  394. MALLOCED(osh)));
  395. goto err;
  396. }
  397. bzero(sdhc, sizeof(bcmsdh_hc_t));
  398. sdhc->osh = osh;
  399. sdhc->dev = pdev;
  400. /* map to address where host can access */
  401. pci_set_master(pdev);
  402. rc = pci_enable_device(pdev);
  403. if (rc) {
  404. SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__));
  405. goto err;
  406. }
  407. if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
  408. (void **)&regs, pdev->irq))) {
  409. SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
  410. goto err;
  411. }
  412. sdhc->sdh = sdh;
  413. /* try to attach to the target device */
  414. if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
  415. bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
  416. (void *)regs, NULL, sdh))) {
  417. SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
  418. goto err;
  419. }
  420. /* chain SDIO Host Controller info together */
  421. sdhc->next = sdhcinfo;
  422. sdhcinfo = sdhc;
  423. return 0;
  424. /* error handling */
  425. err:
  426. if (sdhc->sdh)
  427. bcmsdh_detach(sdhc->osh, sdhc->sdh);
  428. if (sdhc)
  429. MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
  430. if (osh)
  431. osl_detach(osh);
  432. return -ENODEV;
  433. }
  434. /**
  435. * Detach from target devices and SDIO Host Controller
  436. */
  437. static void __devexit
  438. bcmsdh_pci_remove(struct pci_dev *pdev)
  439. {
  440. bcmsdh_hc_t *sdhc, *prev;
  441. osl_t *osh;
  442. /* find the SDIO Host Controller state for this pdev and take it out from the list */
  443. for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
  444. if (sdhc->dev == pdev) {
  445. if (prev)
  446. prev->next = sdhc->next;
  447. else
  448. sdhcinfo = NULL;
  449. break;
  450. }
  451. prev = sdhc;
  452. }
  453. if (!sdhc)
  454. return;
  455. drvinfo.detach(sdhc->ch);
  456. bcmsdh_detach(sdhc->osh, sdhc->sdh);
  457. /* release SDIO Host Controller info */
  458. osh = sdhc->osh;
  459. MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
  460. osl_detach(osh);
  461. }
  462. #endif /* BCMLXSDMMC */
  463. #endif /* BCMPLATFORM_BUS */
  464. extern int sdio_function_init(void);
  465. int
  466. bcmsdh_register(bcmsdh_driver_t *driver)
  467. {
  468. int error = 0;
  469. drvinfo = *driver;
  470. #if defined(BCMPLATFORM_BUS)
  471. #if defined(BCMLXSDMMC)
  472. SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
  473. error = sdio_function_init();
  474. #else
  475. SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
  476. error = driver_register(&bcmsdh_driver);
  477. #endif /* defined(BCMLXSDMMC) */
  478. return error;
  479. #endif /* defined(BCMPLATFORM_BUS) */
  480. #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
  481. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
  482. if (!(error = pci_module_init(&bcmsdh_pci_driver)))
  483. return 0;
  484. #else
  485. if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
  486. return 0;
  487. #endif
  488. SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
  489. #endif /* BCMPLATFORM_BUS */
  490. return error;
  491. }
  492. extern void sdio_function_cleanup(void);
  493. void
  494. bcmsdh_unregister(void)
  495. {
  496. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
  497. if (bcmsdh_pci_driver.node.next)
  498. #endif
  499. #if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
  500. driver_unregister(&bcmsdh_driver);
  501. #endif
  502. #if defined(BCMLXSDMMC)
  503. sdio_function_cleanup();
  504. #endif /* BCMLXSDMMC */
  505. #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
  506. pci_unregister_driver(&bcmsdh_pci_driver);
  507. #endif /* BCMPLATFORM_BUS */
  508. }
  509. #if defined(OOB_INTR_ONLY)
  510. void bcmsdh_oob_intr_set(bool enable)
  511. {
  512. static bool curstate = 1;
  513. unsigned long flags;
  514. spin_lock_irqsave(&sdhcinfo->irq_lock, flags);
  515. if (curstate != enable) {
  516. if (enable)
  517. enable_irq(sdhcinfo->oob_irq);
  518. else
  519. disable_irq_nosync(sdhcinfo->oob_irq);
  520. curstate = enable;
  521. }
  522. spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags);
  523. }
  524. static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
  525. {
  526. dhd_pub_t *dhdp;
  527. dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev);
  528. bcmsdh_oob_intr_set(0);
  529. if (dhdp == NULL) {
  530. SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
  531. return IRQ_HANDLED;
  532. }
  533. dhdsdio_isr((void *)dhdp->bus);
  534. return IRQ_HANDLED;
  535. }
  536. int bcmsdh_register_oob_intr(void * dhdp)
  537. {
  538. int error = 0;
  539. SDLX_MSG(("%s Enter\n", __FUNCTION__));
  540. /* Example of HW_OOB for HW2: please refer to your host specifiction */
  541. /* sdhcinfo->oob_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */
  542. dev_set_drvdata(sdhcinfo->dev, dhdp);
  543. if (!sdhcinfo->oob_irq_registered) {
  544. SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__, \
  545. (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags));
  546. /* Refer to customer Host IRQ docs about proper irqflags definition */
  547. error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
  548. "bcmsdh_sdmmc", NULL);
  549. if (error)
  550. return -ENODEV;
  551. enable_irq_wake(sdhcinfo->oob_irq);
  552. sdhcinfo->oob_irq_registered = TRUE;
  553. }
  554. return 0;
  555. }
  556. void bcmsdh_set_irq(int flag)
  557. {
  558. if (sdhcinfo->oob_irq_registered) {
  559. SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag));
  560. if (flag) {
  561. enable_irq(sdhcinfo->oob_irq);
  562. enable_irq_wake(sdhcinfo->oob_irq);
  563. } else {
  564. disable_irq_wake(sdhcinfo->oob_irq);
  565. disable_irq(sdhcinfo->oob_irq);
  566. }
  567. }
  568. }
  569. void bcmsdh_unregister_oob_intr(void)
  570. {
  571. SDLX_MSG(("%s: Enter\n", __FUNCTION__));
  572. if (sdhcinfo->oob_irq_registered) {
  573. disable_irq_wake(sdhcinfo->oob_irq);
  574. disable_irq(sdhcinfo->oob_irq); /* just in case.. */
  575. free_irq(sdhcinfo->oob_irq, NULL);
  576. sdhcinfo->oob_irq_registered = FALSE;
  577. }
  578. }
  579. #endif /* defined(OOB_INTR_ONLY) */
  580. /* Module parameters specific to each host-controller driver */
  581. extern uint sd_msglevel; /* Debug message level */
  582. module_param(sd_msglevel, uint, 0);
  583. extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */
  584. module_param(sd_power, uint, 0);
  585. extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
  586. module_param(sd_clock, uint, 0);
  587. extern uint sd_divisor; /* Divisor (-1 means external clock) */
  588. module_param(sd_divisor, uint, 0);
  589. extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
  590. module_param(sd_sdmode, uint, 0);
  591. extern uint sd_hiok; /* Ok to use hi-speed mode */
  592. module_param(sd_hiok, uint, 0);
  593. extern uint sd_f2_blocksize;
  594. module_param(sd_f2_blocksize, int, 0);
  595. #ifdef BCMSDH_MODULE
  596. EXPORT_SYMBOL(bcmsdh_attach);
  597. EXPORT_SYMBOL(bcmsdh_detach);
  598. EXPORT_SYMBOL(bcmsdh_intr_query);
  599. EXPORT_SYMBOL(bcmsdh_intr_enable);
  600. EXPORT_SYMBOL(bcmsdh_intr_disable);
  601. EXPORT_SYMBOL(bcmsdh_intr_reg);
  602. EXPORT_SYMBOL(bcmsdh_intr_dereg);
  603. #if defined(DHD_DEBUG)
  604. EXPORT_SYMBOL(bcmsdh_intr_pending);
  605. #endif
  606. EXPORT_SYMBOL(bcmsdh_devremove_reg);
  607. EXPORT_SYMBOL(bcmsdh_cfg_read);
  608. EXPORT_SYMBOL(bcmsdh_cfg_write);
  609. EXPORT_SYMBOL(bcmsdh_cis_read);
  610. EXPORT_SYMBOL(bcmsdh_reg_read);
  611. EXPORT_SYMBOL(bcmsdh_reg_write);
  612. EXPORT_SYMBOL(bcmsdh_regfail);
  613. EXPORT_SYMBOL(bcmsdh_send_buf);
  614. EXPORT_SYMBOL(bcmsdh_recv_buf);
  615. EXPORT_SYMBOL(bcmsdh_rwdata);
  616. EXPORT_SYMBOL(bcmsdh_abort);
  617. EXPORT_SYMBOL(bcmsdh_query_device);
  618. EXPORT_SYMBOL(bcmsdh_query_iofnum);
  619. EXPORT_SYMBOL(bcmsdh_iovar_op);
  620. EXPORT_SYMBOL(bcmsdh_register);
  621. EXPORT_SYMBOL(bcmsdh_unregister);
  622. EXPORT_SYMBOL(bcmsdh_chipmatch);
  623. EXPORT_SYMBOL(bcmsdh_reset);
  624. EXPORT_SYMBOL(bcmsdh_get_dstatus);
  625. EXPORT_SYMBOL(bcmsdh_cfg_read_word);
  626. EXPORT_SYMBOL(bcmsdh_cfg_write_word);
  627. EXPORT_SYMBOL(bcmsdh_cur_sbwad);
  628. EXPORT_SYMBOL(bcmsdh_chipinfo);
  629. #endif /* BCMSDH_MODULE */