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