bcmsdh_linux.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. /*
  2. * SDIO access interface for drivers - linux specific (pci only)
  3. *
  4. * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
  5. *
  6. * Copyright (C) 1999-2020, Broadcom Corporation
  7. *
  8. * Unless you and Broadcom execute a separate written software license
  9. * agreement governing use of this software, this software is licensed to you
  10. * under the terms of the GNU General Public License version 2 (the "GPL"),
  11. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  12. * following added to such license:
  13. *
  14. * As a special exception, the copyright holders of this software give you
  15. * permission to link this software with independent modules, and to copy and
  16. * distribute the resulting executable under terms of your choice, provided that
  17. * you also meet, for each linked independent module, the terms and conditions of
  18. * the license of that module. An independent module is a module which is not
  19. * derived from this software. The special exception does not apply to any
  20. * modifications of the software.
  21. *
  22. * Notwithstanding the above, under no circumstances may you combine this
  23. * software in any way with any other Broadcom software provided under a license
  24. * other than the GPL, without Broadcom's express prior written consent.
  25. *
  26. *
  27. * <<Broadcom-WL-IPTag/Open:>>
  28. *
  29. * $Id: bcmsdh_linux.c 689948 2017-03-14 05:21:03Z $
  30. */
  31. /**
  32. * @file bcmsdh_linux.c
  33. */
  34. #define __UNDEF_NO_VERSION__
  35. #include <typedefs.h>
  36. #include <linuxver.h>
  37. #include <linux/pci.h>
  38. #include <linux/completion.h>
  39. #include <osl.h>
  40. #include <pcicfg.h>
  41. #include <bcmdefs.h>
  42. #include <bcmdevs.h>
  43. #include <linux/irq.h>
  44. extern void dhdsdio_isr(void * args);
  45. #include <bcmutils.h>
  46. #include <dngl_stats.h>
  47. #include <dhd.h>
  48. #include <dhd_linux.h>
  49. /* driver info, initialized when bcmsdh_register is called */
  50. static bcmsdh_driver_t drvinfo = {NULL, NULL, NULL, NULL};
  51. typedef enum {
  52. DHD_INTR_INVALID = 0,
  53. DHD_INTR_INBAND,
  54. DHD_INTR_HWOOB,
  55. DHD_INTR_SWOOB
  56. } DHD_HOST_INTR_TYPE;
  57. /* the BCMSDH module comprises the generic part (bcmsdh.c) and OS specific layer (e.g.
  58. * bcmsdh_linux.c). Put all OS specific variables (e.g. irq number and flags) here rather
  59. * than in the common structure bcmsdh_info. bcmsdh_info only keeps a handle (os_ctx) to this
  60. * structure.
  61. */
  62. typedef struct bcmsdh_os_info {
  63. DHD_HOST_INTR_TYPE intr_type;
  64. int oob_irq_num; /* valid when hardware or software oob in use */
  65. unsigned long oob_irq_flags; /* valid when hardware or software oob in use */
  66. bool oob_irq_registered;
  67. bool oob_irq_enabled;
  68. bool oob_irq_wake_enabled;
  69. spinlock_t oob_irq_spinlock;
  70. bcmsdh_cb_fn_t oob_irq_handler;
  71. void *oob_irq_handler_context;
  72. void *context; /* context returned from upper layer */
  73. void *sdioh; /* handle to lower layer (sdioh) */
  74. void *dev; /* handle to the underlying device */
  75. bool dev_wake_enabled;
  76. } bcmsdh_os_info_t;
  77. /* debugging macros */
  78. #define SDLX_MSG(x)
  79. /**
  80. * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
  81. */
  82. bool
  83. bcmsdh_chipmatch(uint16 vendor, uint16 device)
  84. {
  85. /* Add other vendors and devices as required */
  86. #ifdef BCMSDIOH_STD
  87. /* Check for Arasan host controller */
  88. if (vendor == VENDOR_SI_IMAGE) {
  89. return (TRUE);
  90. }
  91. /* Check for BRCM 27XX Standard host controller */
  92. if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
  93. return (TRUE);
  94. }
  95. /* Check for BRCM Standard host controller */
  96. if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
  97. return (TRUE);
  98. }
  99. /* Check for TI PCIxx21 Standard host controller */
  100. if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
  101. return (TRUE);
  102. }
  103. if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
  104. return (TRUE);
  105. }
  106. /* Ricoh R5C822 Standard SDIO Host */
  107. if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
  108. return (TRUE);
  109. }
  110. /* JMicron Standard SDIO Host */
  111. if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
  112. return (TRUE);
  113. }
  114. #endif /* BCMSDIOH_STD */
  115. #ifdef BCMSDIOH_SPI
  116. /* This is the PciSpiHost. */
  117. if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
  118. printf("Found PCI SPI Host Controller\n");
  119. return (TRUE);
  120. }
  121. #endif /* BCMSDIOH_SPI */
  122. return (FALSE);
  123. }
  124. void* bcmsdh_probe(osl_t *osh, void *dev, void *sdioh, void *adapter_info, uint bus_type,
  125. uint bus_num, uint slot_num)
  126. {
  127. ulong regs;
  128. bcmsdh_info_t *bcmsdh;
  129. uint32 vendevid;
  130. bcmsdh_os_info_t *bcmsdh_osinfo = NULL;
  131. bcmsdh = bcmsdh_attach(osh, sdioh, &regs);
  132. if (bcmsdh == NULL) {
  133. SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
  134. goto err;
  135. }
  136. bcmsdh_osinfo = MALLOC(osh, sizeof(bcmsdh_os_info_t));
  137. if (bcmsdh_osinfo == NULL) {
  138. SDLX_MSG(("%s: failed to allocate bcmsdh_os_info_t\n", __FUNCTION__));
  139. goto err;
  140. }
  141. bzero((char *)bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
  142. bcmsdh->os_cxt = bcmsdh_osinfo;
  143. bcmsdh_osinfo->sdioh = sdioh;
  144. bcmsdh_osinfo->dev = dev;
  145. osl_set_bus_handle(osh, bcmsdh);
  146. #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
  147. (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  148. if (dev && device_init_wakeup(dev, true) == 0)
  149. bcmsdh_osinfo->dev_wake_enabled = TRUE;
  150. #endif /* CONFIG_PM_WAKELOCKS ||CONFIG_HAS_WAKELOCK &&
  151. * (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  152. */
  153. #if defined(OOB_INTR_ONLY)
  154. spin_lock_init(&bcmsdh_osinfo->oob_irq_spinlock);
  155. /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
  156. bcmsdh_osinfo->oob_irq_num = wifi_platform_get_irq_number(adapter_info,
  157. &bcmsdh_osinfo->oob_irq_flags);
  158. if (bcmsdh_osinfo->oob_irq_num < 0) {
  159. SDLX_MSG(("%s: Host OOB irq is not defined\n", __FUNCTION__));
  160. goto err;
  161. }
  162. #endif /* defined(BCMLXSDMMC) */
  163. /* Read the vendor/device ID from the CIS */
  164. vendevid = bcmsdh_query_device(bcmsdh);
  165. /* try to attach to the target device */
  166. bcmsdh_osinfo->context = drvinfo.probe((vendevid >> 16), (vendevid & 0xFFFF), bus_num,
  167. slot_num, 0, bus_type, (void *)regs, osh, bcmsdh);
  168. if (bcmsdh_osinfo->context == NULL) {
  169. SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
  170. goto err;
  171. }
  172. return bcmsdh;
  173. /* error handling */
  174. err:
  175. if (bcmsdh != NULL)
  176. bcmsdh_detach(osh, bcmsdh);
  177. if (bcmsdh_osinfo != NULL)
  178. MFREE(osh, bcmsdh_osinfo, sizeof(bcmsdh_os_info_t));
  179. return NULL;
  180. }
  181. int bcmsdh_remove(bcmsdh_info_t *bcmsdh)
  182. {
  183. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  184. #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
  185. (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  186. if (bcmsdh_osinfo->dev)
  187. device_init_wakeup(bcmsdh_osinfo->dev, false);
  188. bcmsdh_osinfo->dev_wake_enabled = FALSE;
  189. #endif /* CONFIG_PM_WAKELOCKS ||CONFIG_HAS_WAKELOCK &&
  190. * (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  191. */
  192. drvinfo.remove(bcmsdh_osinfo->context);
  193. MFREE(bcmsdh->osh, bcmsdh->os_cxt, sizeof(bcmsdh_os_info_t));
  194. bcmsdh_detach(bcmsdh->osh, bcmsdh);
  195. return 0;
  196. }
  197. #ifdef DHD_WAKE_STATUS
  198. int bcmsdh_get_total_wake(bcmsdh_info_t *bcmsdh)
  199. {
  200. return bcmsdh->total_wake_count;
  201. }
  202. int bcmsdh_set_get_wake(bcmsdh_info_t *bcmsdh, int flag)
  203. {
  204. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  205. unsigned long flags;
  206. int ret;
  207. spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
  208. ret = bcmsdh->pkt_wake;
  209. bcmsdh->total_wake_count += flag;
  210. bcmsdh->pkt_wake = flag;
  211. spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
  212. return ret;
  213. }
  214. #endif /* DHD_WAKE_STATUS */
  215. int bcmsdh_suspend(bcmsdh_info_t *bcmsdh)
  216. {
  217. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  218. if (drvinfo.suspend && drvinfo.suspend(bcmsdh_osinfo->context))
  219. return -EBUSY;
  220. return 0;
  221. }
  222. int bcmsdh_resume(bcmsdh_info_t *bcmsdh)
  223. {
  224. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  225. if (drvinfo.resume)
  226. return drvinfo.resume(bcmsdh_osinfo->context);
  227. return 0;
  228. }
  229. extern int bcmsdh_register_client_driver(void);
  230. extern void bcmsdh_unregister_client_driver(void);
  231. extern int sdio_func_reg_notify(void* semaphore);
  232. extern void sdio_func_unreg_notify(void);
  233. #if defined(BCMLXSDMMC)
  234. int bcmsdh_reg_sdio_notify(void* semaphore)
  235. {
  236. return sdio_func_reg_notify(semaphore);
  237. }
  238. void bcmsdh_unreg_sdio_notify(void)
  239. {
  240. sdio_func_unreg_notify();
  241. }
  242. #endif /* defined(BCMLXSDMMC) */
  243. int
  244. bcmsdh_register(bcmsdh_driver_t *driver)
  245. {
  246. int error = 0;
  247. drvinfo = *driver;
  248. SDLX_MSG(("%s: register client driver\n", __FUNCTION__));
  249. // error = bcmsdh_register_client_driver();//add 20210511
  250. if (error)
  251. SDLX_MSG(("%s: failed %d\n", __FUNCTION__, error));
  252. return error;
  253. }
  254. void
  255. bcmsdh_unregister(void)
  256. {
  257. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
  258. if (bcmsdh_pci_driver.node.next == NULL)
  259. return;
  260. #endif // endif
  261. // bcmsdh_unregister_client_driver();//add 20210511
  262. }
  263. void bcmsdh_dev_pm_stay_awake(bcmsdh_info_t *bcmsdh)
  264. {
  265. #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
  266. (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  267. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  268. pm_stay_awake(bcmsdh_osinfo->dev);
  269. #endif /* CONFIG_PM_WAKELOCKS || CONFIG_HAS_WAKELOCK &&
  270. * (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  271. */
  272. }
  273. void bcmsdh_dev_relax(bcmsdh_info_t *bcmsdh)
  274. {
  275. #if (!defined(CONFIG_PM_WAKELOCKS) || !defined(CONFIG_HAS_WAKELOCK)) && \
  276. (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  277. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  278. pm_relax(bcmsdh_osinfo->dev);
  279. #endif /* CONFIG_PM_WAKELOCKS || CONFIG_HAS_WAKELOCK &&
  280. * (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 36))
  281. */
  282. }
  283. bool bcmsdh_dev_pm_enabled(bcmsdh_info_t *bcmsdh)
  284. {
  285. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  286. return bcmsdh_osinfo->dev_wake_enabled;
  287. }
  288. #if defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID)
  289. void bcmsdh_oob_intr_set(bcmsdh_info_t *bcmsdh, bool enable)
  290. {
  291. unsigned long flags;
  292. bcmsdh_os_info_t *bcmsdh_osinfo;
  293. if (!bcmsdh)
  294. return;
  295. bcmsdh_osinfo = bcmsdh->os_cxt;
  296. spin_lock_irqsave(&bcmsdh_osinfo->oob_irq_spinlock, flags);
  297. if (bcmsdh_osinfo->oob_irq_enabled != enable) {
  298. if (enable)
  299. enable_irq(bcmsdh_osinfo->oob_irq_num);
  300. else
  301. disable_irq_nosync(bcmsdh_osinfo->oob_irq_num);
  302. bcmsdh_osinfo->oob_irq_enabled = enable;
  303. }
  304. spin_unlock_irqrestore(&bcmsdh_osinfo->oob_irq_spinlock, flags);
  305. }
  306. static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
  307. {
  308. bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)dev_id;
  309. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  310. #ifndef BCMSPI_ANDROID
  311. bcmsdh_oob_intr_set(bcmsdh, FALSE);
  312. #endif /* !BCMSPI_ANDROID */
  313. bcmsdh_osinfo->oob_irq_handler(bcmsdh_osinfo->oob_irq_handler_context);
  314. return IRQ_HANDLED;
  315. }
  316. int bcmsdh_oob_intr_register(bcmsdh_info_t *bcmsdh, bcmsdh_cb_fn_t oob_irq_handler,
  317. void* oob_irq_handler_context)
  318. {
  319. int err = 0;
  320. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  321. SDLX_MSG(("%s: Enter\n", __FUNCTION__));
  322. if (bcmsdh_osinfo->oob_irq_registered) {
  323. SDLX_MSG(("%s: irq is already registered\n", __FUNCTION__));
  324. return -EBUSY;
  325. }
  326. SDLX_MSG(("%s OOB irq=%d flags=%X \n", __FUNCTION__,
  327. (int)bcmsdh_osinfo->oob_irq_num, (int)bcmsdh_osinfo->oob_irq_flags));
  328. bcmsdh_osinfo->oob_irq_handler = oob_irq_handler;
  329. bcmsdh_osinfo->oob_irq_handler_context = oob_irq_handler_context;
  330. bcmsdh_osinfo->oob_irq_enabled = TRUE;
  331. bcmsdh_osinfo->oob_irq_registered = TRUE;
  332. err = request_irq(bcmsdh_osinfo->oob_irq_num, wlan_oob_irq,
  333. bcmsdh_osinfo->oob_irq_flags, "bcmsdh_sdmmc", bcmsdh);
  334. if (err) {
  335. SDLX_MSG(("%s: request_irq failed with %d\n", __FUNCTION__, err));
  336. bcmsdh_osinfo->oob_irq_enabled = FALSE;
  337. bcmsdh_osinfo->oob_irq_registered = FALSE;
  338. return err;
  339. }
  340. #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
  341. if (device_may_wakeup(bcmsdh_osinfo->dev)) {
  342. #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
  343. err = enable_irq_wake(bcmsdh_osinfo->oob_irq_num);
  344. if (!err)
  345. bcmsdh_osinfo->oob_irq_wake_enabled = TRUE;
  346. #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
  347. }
  348. #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
  349. return err;
  350. }
  351. void bcmsdh_oob_intr_unregister(bcmsdh_info_t *bcmsdh)
  352. {
  353. int err = 0;
  354. bcmsdh_os_info_t *bcmsdh_osinfo = bcmsdh->os_cxt;
  355. SDLX_MSG(("%s: Enter\n", __FUNCTION__));
  356. if (!bcmsdh_osinfo->oob_irq_registered) {
  357. SDLX_MSG(("%s: irq is not registered\n", __FUNCTION__));
  358. return;
  359. }
  360. if (bcmsdh_osinfo->oob_irq_wake_enabled) {
  361. #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
  362. if (device_may_wakeup(bcmsdh_osinfo->dev)) {
  363. #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
  364. err = disable_irq_wake(bcmsdh_osinfo->oob_irq_num);
  365. if (!err)
  366. bcmsdh_osinfo->oob_irq_wake_enabled = FALSE;
  367. #if defined(CONFIG_ARCH_RHEA) || defined(CONFIG_ARCH_CAPRI)
  368. }
  369. #endif /* CONFIG_ARCH_RHEA || CONFIG_ARCH_CAPRI */
  370. }
  371. if (bcmsdh_osinfo->oob_irq_enabled) {
  372. disable_irq(bcmsdh_osinfo->oob_irq_num);
  373. bcmsdh_osinfo->oob_irq_enabled = FALSE;
  374. }
  375. free_irq(bcmsdh_osinfo->oob_irq_num, bcmsdh);
  376. bcmsdh_osinfo->oob_irq_registered = FALSE;
  377. }
  378. #endif /* defined(OOB_INTR_ONLY) || defined(BCMSPI_ANDROID) */
  379. /* Module parameters specific to each host-controller driver */
  380. #if 0/*add 20210511*/
  381. extern uint sd_msglevel; /* Debug message level */
  382. module_param(sd_msglevel, uint, 0);
  383. extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */
  384. module_param(sd_power, uint, 0);
  385. extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
  386. module_param(sd_clock, uint, 0);
  387. extern uint sd_divisor; /* Divisor (-1 means external clock) */
  388. module_param(sd_divisor, uint, 0);
  389. extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
  390. module_param(sd_sdmode, uint, 0);
  391. extern uint sd_hiok; /* Ok to use hi-speed mode */
  392. module_param(sd_hiok, uint, 0);
  393. extern uint sd_f2_blocksize;
  394. module_param(sd_f2_blocksize, int, 0);
  395. extern uint sd_f1_blocksize;
  396. module_param(sd_f1_blocksize, int, 0);
  397. #endif
  398. #ifdef BCMSDIOH_STD
  399. extern int sd_uhsimode;
  400. module_param(sd_uhsimode, int, 0);
  401. extern uint sd_tuning_period;
  402. module_param(sd_tuning_period, uint, 0);
  403. extern int sd_delay_value;
  404. module_param(sd_delay_value, uint, 0);
  405. /* SDIO Drive Strength for UHSI mode specific to SDIO3.0 */
  406. extern char dhd_sdiod_uhsi_ds_override[2];
  407. module_param_string(dhd_sdiod_uhsi_ds_override, dhd_sdiod_uhsi_ds_override, 2, 0);
  408. #endif // endif
  409. #ifdef BCMSDH_MODULE
  410. EXPORT_SYMBOL(bcmsdh_attach);
  411. EXPORT_SYMBOL(bcmsdh_detach);
  412. EXPORT_SYMBOL(bcmsdh_intr_query);
  413. EXPORT_SYMBOL(bcmsdh_intr_enable);
  414. EXPORT_SYMBOL(bcmsdh_intr_disable);
  415. EXPORT_SYMBOL(bcmsdh_intr_reg);
  416. EXPORT_SYMBOL(bcmsdh_intr_dereg);
  417. #if defined(DHD_DEBUG)
  418. EXPORT_SYMBOL(bcmsdh_intr_pending);
  419. #endif // endif
  420. #if defined(BT_OVER_SDIO)
  421. EXPORT_SYMBOL(bcmsdh_btsdio_interface_init);
  422. #endif /* defined (BT_OVER_SDIO) */
  423. EXPORT_SYMBOL(bcmsdh_devremove_reg);
  424. EXPORT_SYMBOL(bcmsdh_cfg_read);
  425. EXPORT_SYMBOL(bcmsdh_cfg_write);
  426. EXPORT_SYMBOL(bcmsdh_cis_read);
  427. EXPORT_SYMBOL(bcmsdh_reg_read);
  428. EXPORT_SYMBOL(bcmsdh_reg_write);
  429. EXPORT_SYMBOL(bcmsdh_regfail);
  430. EXPORT_SYMBOL(bcmsdh_send_buf);
  431. EXPORT_SYMBOL(bcmsdh_recv_buf);
  432. EXPORT_SYMBOL(bcmsdh_rwdata);
  433. EXPORT_SYMBOL(bcmsdh_abort);
  434. EXPORT_SYMBOL(bcmsdh_query_device);
  435. EXPORT_SYMBOL(bcmsdh_query_iofnum);
  436. EXPORT_SYMBOL(bcmsdh_iovar_op);
  437. EXPORT_SYMBOL(bcmsdh_register);
  438. EXPORT_SYMBOL(bcmsdh_unregister);
  439. EXPORT_SYMBOL(bcmsdh_chipmatch);
  440. EXPORT_SYMBOL(bcmsdh_reset);
  441. EXPORT_SYMBOL(bcmsdh_waitlockfree);
  442. EXPORT_SYMBOL(bcmsdh_get_dstatus);
  443. EXPORT_SYMBOL(bcmsdh_cfg_read_word);
  444. EXPORT_SYMBOL(bcmsdh_cfg_write_word);
  445. EXPORT_SYMBOL(bcmsdh_cur_sbwad);
  446. EXPORT_SYMBOL(bcmsdh_chipinfo);
  447. #endif /* BCMSDH_MODULE */