aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c')
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c1304
1 files changed, 1304 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c
new file mode 100644
index 00000000000..031367b8f18
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c
@@ -0,0 +1,1304 @@
1/*
2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
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_sdmmc.c,v 1.1.2.5.6.30.4.1 2010/09/02 23:12:21 Exp $
25 */
26#include <typedefs.h>
27
28#include <bcmdevs.h>
29#include <bcmendian.h>
30#include <bcmutils.h>
31#include <osl.h>
32#include <sdio.h> /* SDIO Device and Protocol Specs */
33#include <sdioh.h> /* SDIO Host Controller Specification */
34#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
35#include <sdiovar.h> /* ioctl/iovars */
36
37#include <linux/mmc/core.h>
38#include <linux/mmc/sdio_func.h>
39#include <linux/mmc/sdio_ids.h>
40
41#include <dngl_stats.h>
42#include <dhd.h>
43
44#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
45#include <linux/suspend.h>
46extern volatile bool dhd_mmc_suspend;
47#endif
48#include "bcmsdh_sdmmc.h"
49
50#ifndef BCMSDH_MODULE
51extern int sdio_function_init(void);
52extern void sdio_function_cleanup(void);
53#endif /* BCMSDH_MODULE */
54
55#if !defined(OOB_INTR_ONLY)
56static void IRQHandler(struct sdio_func *func);
57static void IRQHandlerF2(struct sdio_func *func);
58#endif /* !defined(OOB_INTR_ONLY) */
59static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
60extern int sdio_reset_comm(struct mmc_card *card);
61
62extern PBCMSDH_SDMMC_INSTANCE gInstance;
63
64uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
65uint sd_f2_blocksize = 512; /* Default blocksize */
66
67uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
68
69uint sd_power = 1; /* Default to SD Slot powered ON */
70uint sd_clock = 1; /* Default to SD Clock turned ON */
71uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */
72uint sd_msglevel = 0x01;
73uint sd_use_dma = TRUE;
74DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
75DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
76DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
77DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
78
79#define DMA_ALIGN_MASK 0x03
80
81int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
82
83static int
84sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
85{
86 int err_ret;
87 uint32 fbraddr;
88 uint8 func;
89
90 sd_trace(("%s\n", __FUNCTION__));
91
92 /* Get the Card's common CIS address */
93 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
94 sd->func_cis_ptr[0] = sd->com_cis_ptr;
95 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
96
97 /* Get the Card's function CIS (for each function) */
98 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
99 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
100 sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
101 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
102 __FUNCTION__, func, sd->func_cis_ptr[func]));
103 }
104
105 sd->func_cis_ptr[0] = sd->com_cis_ptr;
106 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
107
108 /* Enable Function 1 */
109 sdio_claim_host(gInstance->func[1]);
110 err_ret = sdio_enable_func(gInstance->func[1]);
111 sdio_release_host(gInstance->func[1]);
112 if (err_ret) {
113 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret));
114 }
115
116 return FALSE;
117}
118
119/*
120 * Public entry points & extern's
121 */
122extern sdioh_info_t *
123sdioh_attach(osl_t *osh, void *bar0, uint irq)
124{
125 sdioh_info_t *sd;
126 int err_ret;
127
128 sd_trace(("%s\n", __FUNCTION__));
129
130 if (gInstance == NULL) {
131 sd_err(("%s: SDIO Device not present\n", __FUNCTION__));
132 return NULL;
133 }
134
135 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
136 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
137 return NULL;
138 }
139 bzero((char *)sd, sizeof(sdioh_info_t));
140 sd->osh = osh;
141 if (sdioh_sdmmc_osinit(sd) != 0) {
142 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__));
143 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
144 return NULL;
145 }
146
147 sd->num_funcs = 2;
148 sd->sd_blockmode = TRUE;
149 sd->use_client_ints = TRUE;
150 sd->client_block_size[0] = 64;
151
152 gInstance->sd = sd;
153
154 /* Claim host controller */
155 sdio_claim_host(gInstance->func[1]);
156
157 sd->client_block_size[1] = 64;
158 err_ret = sdio_set_block_size(gInstance->func[1], 64);
159 if (err_ret) {
160 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
161 }
162
163 /* Release host controller F1 */
164 sdio_release_host(gInstance->func[1]);
165
166 if (gInstance->func[2]) {
167 /* Claim host controller F2 */
168 sdio_claim_host(gInstance->func[2]);
169
170 sd->client_block_size[2] = sd_f2_blocksize;
171 err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
172 if (err_ret) {
173 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n",
174 sd_f2_blocksize));
175 }
176
177 /* Release host controller F2 */
178 sdio_release_host(gInstance->func[2]);
179 }
180
181 sdioh_sdmmc_card_enablefuncs(sd);
182
183 sd_trace(("%s: Done\n", __FUNCTION__));
184 return sd;
185}
186
187
188extern SDIOH_API_RC
189sdioh_detach(osl_t *osh, sdioh_info_t *sd)
190{
191 sd_trace(("%s\n", __FUNCTION__));
192
193 if (sd) {
194
195 /* Disable Function 2 */
196 sdio_claim_host(gInstance->func[2]);
197 sdio_disable_func(gInstance->func[2]);
198 sdio_release_host(gInstance->func[2]);
199
200 /* Disable Function 1 */
201 sdio_claim_host(gInstance->func[1]);
202 sdio_disable_func(gInstance->func[1]);
203 sdio_release_host(gInstance->func[1]);
204
205 /* deregister irq */
206 sdioh_sdmmc_osfree(sd);
207
208 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
209 }
210 return SDIOH_API_RC_SUCCESS;
211}
212
213#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
214
215extern SDIOH_API_RC
216sdioh_enable_func_intr(void)
217{
218 uint8 reg;
219 int err;
220
221 if (gInstance->func[0]) {
222 sdio_claim_host(gInstance->func[0]);
223
224 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
225 if (err) {
226 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
227 sdio_release_host(gInstance->func[0]);
228 return SDIOH_API_RC_FAIL;
229 }
230
231 /* Enable F1 and F2 interrupts, set master enable */
232 reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN);
233
234 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
235 sdio_release_host(gInstance->func[0]);
236
237 if (err) {
238 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
239 return SDIOH_API_RC_FAIL;
240 }
241 }
242
243 return SDIOH_API_RC_SUCCESS;
244}
245
246extern SDIOH_API_RC
247sdioh_disable_func_intr(void)
248{
249 uint8 reg;
250 int err;
251
252 if (gInstance->func[0]) {
253 sdio_claim_host(gInstance->func[0]);
254 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
255 if (err) {
256 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
257 sdio_release_host(gInstance->func[0]);
258 return SDIOH_API_RC_FAIL;
259 }
260
261 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
262 /* Disable master interrupt with the last function interrupt */
263 if (!(reg & 0xFE))
264 reg = 0;
265 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
266
267 sdio_release_host(gInstance->func[0]);
268 if (err) {
269 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
270 return SDIOH_API_RC_FAIL;
271 }
272 }
273 return SDIOH_API_RC_SUCCESS;
274}
275#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
276
277/* Configure callback to client when we recieve client interrupt */
278extern SDIOH_API_RC
279sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
280{
281 sd_trace(("%s: Entering\n", __FUNCTION__));
282 if (fn == NULL) {
283 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
284 return SDIOH_API_RC_FAIL;
285 }
286#if !defined(OOB_INTR_ONLY)
287 sd->intr_handler = fn;
288 sd->intr_handler_arg = argh;
289 sd->intr_handler_valid = TRUE;
290
291 /* register and unmask irq */
292 if (gInstance->func[2]) {
293 sdio_claim_host(gInstance->func[2]);
294 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
295 sdio_release_host(gInstance->func[2]);
296 }
297
298 if (gInstance->func[1]) {
299 sdio_claim_host(gInstance->func[1]);
300 sdio_claim_irq(gInstance->func[1], IRQHandler);
301 sdio_release_host(gInstance->func[1]);
302 }
303#elif defined(HW_OOB)
304 sdioh_enable_func_intr();
305#endif /* defined(OOB_INTR_ONLY) */
306 return SDIOH_API_RC_SUCCESS;
307}
308
309extern SDIOH_API_RC
310sdioh_interrupt_deregister(sdioh_info_t *sd)
311{
312 sd_trace(("%s: Entering\n", __FUNCTION__));
313
314#if !defined(OOB_INTR_ONLY)
315 if (gInstance->func[1]) {
316 /* register and unmask irq */
317 sdio_claim_host(gInstance->func[1]);
318 sdio_release_irq(gInstance->func[1]);
319 sdio_release_host(gInstance->func[1]);
320 }
321
322 if (gInstance->func[2]) {
323 /* Claim host controller F2 */
324 sdio_claim_host(gInstance->func[2]);
325 sdio_release_irq(gInstance->func[2]);
326 /* Release host controller F2 */
327 sdio_release_host(gInstance->func[2]);
328 }
329
330 sd->intr_handler_valid = FALSE;
331 sd->intr_handler = NULL;
332 sd->intr_handler_arg = NULL;
333#elif defined(HW_OOB)
334 sdioh_disable_func_intr();
335#endif /* !defined(OOB_INTR_ONLY) */
336 return SDIOH_API_RC_SUCCESS;
337}
338
339extern SDIOH_API_RC
340sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
341{
342 sd_trace(("%s: Entering\n", __FUNCTION__));
343 *onoff = sd->client_intr_enabled;
344 return SDIOH_API_RC_SUCCESS;
345}
346
347#if defined(DHD_DEBUG)
348extern bool
349sdioh_interrupt_pending(sdioh_info_t *sd)
350{
351 return (0);
352}
353#endif
354
355uint
356sdioh_query_iofnum(sdioh_info_t *sd)
357{
358 return sd->num_funcs;
359}
360
361/* IOVar table */
362enum {
363 IOV_MSGLEVEL = 1,
364 IOV_BLOCKMODE,
365 IOV_BLOCKSIZE,
366 IOV_DMA,
367 IOV_USEINTS,
368 IOV_NUMINTS,
369 IOV_NUMLOCALINTS,
370 IOV_HOSTREG,
371 IOV_DEVREG,
372 IOV_DIVISOR,
373 IOV_SDMODE,
374 IOV_HISPEED,
375 IOV_HCIREGS,
376 IOV_POWER,
377 IOV_CLOCK,
378 IOV_RXCHAIN
379};
380
381const bcm_iovar_t sdioh_iovars[] = {
382 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
383 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
384 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
385 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
386 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
387 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
388 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
389 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
390 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
391 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
392 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
393 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
394 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
395 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 },
396 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 },
397 {NULL, 0, 0, 0, 0 }
398};
399
400int
401sdioh_iovar_op(sdioh_info_t *si, const char *name,
402 void *params, int plen, void *arg, int len, bool set)
403{
404 const bcm_iovar_t *vi = NULL;
405 int bcmerror = 0;
406 int val_size;
407 int32 int_val = 0;
408 bool bool_val;
409 uint32 actionid;
410
411 ASSERT(name);
412 ASSERT(len >= 0);
413
414 /* Get must have return space; Set does not take qualifiers */
415 ASSERT(set || (arg && len));
416 ASSERT(!set || (!params && !plen));
417
418 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
419
420 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
421 bcmerror = BCME_UNSUPPORTED;
422 goto exit;
423 }
424
425 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
426 goto exit;
427
428 /* Set up params so get and set can share the convenience variables */
429 if (params == NULL) {
430 params = arg;
431 plen = len;
432 }
433
434 if (vi->type == IOVT_VOID)
435 val_size = 0;
436 else if (vi->type == IOVT_BUFFER)
437 val_size = len;
438 else
439 val_size = sizeof(int);
440
441 if (plen >= (int)sizeof(int_val))
442 bcopy(params, &int_val, sizeof(int_val));
443
444 bool_val = (int_val != 0) ? TRUE : FALSE;
445
446 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
447 switch (actionid) {
448 case IOV_GVAL(IOV_MSGLEVEL):
449 int_val = (int32)sd_msglevel;
450 bcopy(&int_val, arg, val_size);
451 break;
452
453 case IOV_SVAL(IOV_MSGLEVEL):
454 sd_msglevel = int_val;
455 break;
456
457 case IOV_GVAL(IOV_BLOCKMODE):
458 int_val = (int32)si->sd_blockmode;
459 bcopy(&int_val, arg, val_size);
460 break;
461
462 case IOV_SVAL(IOV_BLOCKMODE):
463 si->sd_blockmode = (bool)int_val;
464 /* Haven't figured out how to make non-block mode with DMA */
465 break;
466
467 case IOV_GVAL(IOV_BLOCKSIZE):
468 if ((uint32)int_val > si->num_funcs) {
469 bcmerror = BCME_BADARG;
470 break;
471 }
472 int_val = (int32)si->client_block_size[int_val];
473 bcopy(&int_val, arg, val_size);
474 break;
475
476 case IOV_SVAL(IOV_BLOCKSIZE):
477 {
478 uint func = ((uint32)int_val >> 16);
479 uint blksize = (uint16)int_val;
480 uint maxsize;
481
482 if (func > si->num_funcs) {
483 bcmerror = BCME_BADARG;
484 break;
485 }
486
487 switch (func) {
488 case 0: maxsize = 32; break;
489 case 1: maxsize = BLOCK_SIZE_4318; break;
490 case 2: maxsize = BLOCK_SIZE_4328; break;
491 default: maxsize = 0;
492 }
493 if (blksize > maxsize) {
494 bcmerror = BCME_BADARG;
495 break;
496 }
497 if (!blksize) {
498 blksize = maxsize;
499 }
500
501 /* Now set it */
502 si->client_block_size[func] = blksize;
503
504 break;
505 }
506
507 case IOV_GVAL(IOV_RXCHAIN):
508 int_val = FALSE;
509 bcopy(&int_val, arg, val_size);
510 break;
511
512 case IOV_GVAL(IOV_DMA):
513 int_val = (int32)si->sd_use_dma;
514 bcopy(&int_val, arg, val_size);
515 break;
516
517 case IOV_SVAL(IOV_DMA):
518 si->sd_use_dma = (bool)int_val;
519 break;
520
521 case IOV_GVAL(IOV_USEINTS):
522 int_val = (int32)si->use_client_ints;
523 bcopy(&int_val, arg, val_size);
524 break;
525
526 case IOV_SVAL(IOV_USEINTS):
527 si->use_client_ints = (bool)int_val;
528 if (si->use_client_ints)
529 si->intmask |= CLIENT_INTR;
530 else
531 si->intmask &= ~CLIENT_INTR;
532
533 break;
534
535 case IOV_GVAL(IOV_DIVISOR):
536 int_val = (uint32)sd_divisor;
537 bcopy(&int_val, arg, val_size);
538 break;
539
540 case IOV_SVAL(IOV_DIVISOR):
541 sd_divisor = int_val;
542 break;
543
544 case IOV_GVAL(IOV_POWER):
545 int_val = (uint32)sd_power;
546 bcopy(&int_val, arg, val_size);
547 break;
548
549 case IOV_SVAL(IOV_POWER):
550 sd_power = int_val;
551 break;
552
553 case IOV_GVAL(IOV_CLOCK):
554 int_val = (uint32)sd_clock;
555 bcopy(&int_val, arg, val_size);
556 break;
557
558 case IOV_SVAL(IOV_CLOCK):
559 sd_clock = int_val;
560 break;
561
562 case IOV_GVAL(IOV_SDMODE):
563 int_val = (uint32)sd_sdmode;
564 bcopy(&int_val, arg, val_size);
565 break;
566
567 case IOV_SVAL(IOV_SDMODE):
568 sd_sdmode = int_val;
569 break;
570
571 case IOV_GVAL(IOV_HISPEED):
572 int_val = (uint32)sd_hiok;
573 bcopy(&int_val, arg, val_size);
574 break;
575
576 case IOV_SVAL(IOV_HISPEED):
577 sd_hiok = int_val;
578 break;
579
580 case IOV_GVAL(IOV_NUMINTS):
581 int_val = (int32)si->intrcount;
582 bcopy(&int_val, arg, val_size);
583 break;
584
585 case IOV_GVAL(IOV_NUMLOCALINTS):
586 int_val = (int32)0;
587 bcopy(&int_val, arg, val_size);
588 break;
589
590 case IOV_GVAL(IOV_HOSTREG):
591 {
592 sdreg_t *sd_ptr = (sdreg_t *)params;
593
594 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
595 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
596 bcmerror = BCME_BADARG;
597 break;
598 }
599
600 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
601 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
602 sd_ptr->offset));
603 if (sd_ptr->offset & 1)
604 int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
605 else if (sd_ptr->offset & 2)
606 int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
607 else
608 int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
609
610 bcopy(&int_val, arg, sizeof(int_val));
611 break;
612 }
613
614 case IOV_SVAL(IOV_HOSTREG):
615 {
616 sdreg_t *sd_ptr = (sdreg_t *)params;
617
618 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
619 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
620 bcmerror = BCME_BADARG;
621 break;
622 }
623
624 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
625 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
626 sd_ptr->offset));
627 break;
628 }
629
630 case IOV_GVAL(IOV_DEVREG):
631 {
632 sdreg_t *sd_ptr = (sdreg_t *)params;
633 uint8 data = 0;
634
635 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
636 bcmerror = BCME_SDIO_ERROR;
637 break;
638 }
639
640 int_val = (int)data;
641 bcopy(&int_val, arg, sizeof(int_val));
642 break;
643 }
644
645 case IOV_SVAL(IOV_DEVREG):
646 {
647 sdreg_t *sd_ptr = (sdreg_t *)params;
648 uint8 data = (uint8)sd_ptr->value;
649
650 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
651 bcmerror = BCME_SDIO_ERROR;
652 break;
653 }
654 break;
655 }
656
657 default:
658 bcmerror = BCME_UNSUPPORTED;
659 break;
660 }
661exit:
662
663 return bcmerror;
664}
665
666#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
667
668SDIOH_API_RC
669sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
670{
671 SDIOH_API_RC status;
672 uint8 data;
673
674 if (enable)
675 data = 3; /* enable hw oob interrupt */
676 else
677 data = 4; /* disable hw oob interrupt */
678 data |= 4; /* Active HIGH */
679
680 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
681 return status;
682}
683#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
684
685extern SDIOH_API_RC
686sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
687{
688 SDIOH_API_RC status;
689 /* No lock needed since sdioh_request_byte does locking */
690 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
691 return status;
692}
693
694extern SDIOH_API_RC
695sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
696{
697 /* No lock needed since sdioh_request_byte does locking */
698 SDIOH_API_RC status;
699 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
700 return status;
701}
702
703static int
704sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
705{
706 /* read 24 bits and return valid 17 bit addr */
707 int i;
708 uint32 scratch, regdata;
709 uint8 *ptr = (uint8 *)&scratch;
710 for (i = 0; i < 3; i++) {
711 if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
712 sd_err(("%s: Can't read!\n", __FUNCTION__));
713
714 *ptr++ = (uint8) regdata;
715 regaddr++;
716 }
717
718 /* Only the lower 17-bits are valid */
719 scratch = ltoh32(scratch);
720 scratch &= 0x0001FFFF;
721 return (scratch);
722}
723
724extern SDIOH_API_RC
725sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
726{
727 uint32 count;
728 int offset;
729 uint32 foo;
730 uint8 *cis = cisd;
731
732 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
733
734 if (!sd->func_cis_ptr[func]) {
735 bzero(cis, length);
736 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
737 return SDIOH_API_RC_FAIL;
738 }
739
740 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
741
742 for (count = 0; count < length; count++) {
743 offset = sd->func_cis_ptr[func] + count;
744 if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) {
745 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
746 return SDIOH_API_RC_FAIL;
747 }
748
749 *cis = (uint8)(foo & 0xff);
750 cis++;
751 }
752
753 return SDIOH_API_RC_SUCCESS;
754}
755
756extern SDIOH_API_RC
757sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
758{
759 int err_ret;
760
761 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
762
763 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
764 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
765 if(rw) { /* CMD52 Write */
766 if (func == 0) {
767 /* Can only directly write to some F0 registers. Handle F2 enable
768 * as a special case.
769 */
770 if (regaddr == SDIOD_CCCR_IOEN) {
771 if (gInstance->func[2]) {
772 sdio_claim_host(gInstance->func[2]);
773 if (*byte & SDIO_FUNC_ENABLE_2) {
774 /* Enable Function 2 */
775 err_ret = sdio_enable_func(gInstance->func[2]);
776 if (err_ret) {
777 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
778 err_ret));
779 }
780 } else {
781 /* Disable Function 2 */
782 err_ret = sdio_disable_func(gInstance->func[2]);
783 if (err_ret) {
784 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
785 err_ret));
786 }
787 }
788 sdio_release_host(gInstance->func[2]);
789 }
790 }
791#if defined(MMC_SDIO_ABORT)
792 /* to allow abort command through F1 */
793 else if (regaddr == SDIOD_CCCR_IOABORT) {
794 sdio_claim_host(gInstance->func[func]);
795 /*
796 * this sdio_f0_writeb() can be replaced with another api
797 * depending upon MMC driver change.
798 * As of this time, this is temporaray one
799 */
800 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
801 sdio_release_host(gInstance->func[func]);
802 }
803#endif /* MMC_SDIO_ABORT */
804 else if (regaddr < 0xF0) {
805 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr));
806 } else {
807 /* Claim host controller, perform F0 write, and release */
808 sdio_claim_host(gInstance->func[func]);
809 sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
810 sdio_release_host(gInstance->func[func]);
811 }
812 } else {
813 /* Claim host controller, perform Fn write, and release */
814 sdio_claim_host(gInstance->func[func]);
815 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
816 sdio_release_host(gInstance->func[func]);
817 }
818 } else { /* CMD52 Read */
819 /* Claim host controller, perform Fn read, and release */
820 sdio_claim_host(gInstance->func[func]);
821
822 if (func == 0) {
823 *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret);
824 } else {
825 *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret);
826 }
827
828 sdio_release_host(gInstance->func[func]);
829 }
830
831 if (err_ret) {
832 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
833 rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
834 }
835
836 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
837}
838
839extern SDIOH_API_RC
840sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
841 uint32 *word, uint nbytes)
842{
843 int err_ret = SDIOH_API_RC_FAIL;
844
845 if (func == 0) {
846 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
847 return SDIOH_API_RC_FAIL;
848 }
849
850 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
851 __FUNCTION__, cmd_type, rw, func, addr, nbytes));
852
853 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
854 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
855 /* Claim host controller */
856 sdio_claim_host(gInstance->func[func]);
857
858 if(rw) { /* CMD52 Write */
859 if (nbytes == 4) {
860 sdio_writel(gInstance->func[func], *word, addr, &err_ret);
861 } else if (nbytes == 2) {
862 sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret);
863 } else {
864 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
865 }
866 } else { /* CMD52 Read */
867 if (nbytes == 4) {
868 *word = sdio_readl(gInstance->func[func], addr, &err_ret);
869 } else if (nbytes == 2) {
870 *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF;
871 } else {
872 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
873 }
874 }
875
876 /* Release host controller */
877 sdio_release_host(gInstance->func[func]);
878
879 if (err_ret) {
880 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
881 rw ? "Write" : "Read", err_ret));
882 }
883
884 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
885}
886
887static SDIOH_API_RC
888sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
889 uint addr, void *pkt)
890{
891 bool fifo = (fix_inc == SDIOH_DATA_FIX);
892 uint32 SGCount = 0;
893 int err_ret = 0;
894
895 void *pnext;
896
897 sd_trace(("%s: Enter\n", __FUNCTION__));
898
899 ASSERT(pkt);
900 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
901 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
902
903 /* Claim host controller */
904 sdio_claim_host(gInstance->func[func]);
905 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
906 uint pkt_len = PKTLEN(sd->osh, pnext);
907 pkt_len += 3;
908 pkt_len &= 0xFFFFFFFC;
909
910#ifdef CONFIG_MMC_MSM7X00A
911 if ((pkt_len % 64) == 32) {
912 sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
913 pkt_len += 32;
914 }
915#endif /* CONFIG_MMC_MSM7X00A */
916 /* Make sure the packet is aligned properly. If it isn't, then this
917 * is the fault of sdioh_request_buffer() which is supposed to give
918 * us something we can work with.
919 */
920 ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
921
922 if ((write) && (!fifo)) {
923 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
924 ((uint8*)PKTDATA(sd->osh, pnext)),
925 pkt_len);
926 } else if (write) {
927 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
928 ((uint8*)PKTDATA(sd->osh, pnext)),
929 pkt_len);
930 } else if (fifo) {
931 err_ret = sdio_readsb(gInstance->func[func],
932 ((uint8*)PKTDATA(sd->osh, pnext)),
933 addr,
934 pkt_len);
935 } else {
936 err_ret = sdio_memcpy_fromio(gInstance->func[func],
937 ((uint8*)PKTDATA(sd->osh, pnext)),
938 addr,
939 pkt_len);
940 }
941
942 if (err_ret) {
943 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
944 __FUNCTION__,
945 (write) ? "TX" : "RX",
946 pnext, SGCount, addr, pkt_len, err_ret));
947 } else {
948 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
949 __FUNCTION__,
950 (write) ? "TX" : "RX",
951 pnext, SGCount, addr, pkt_len));
952 }
953
954 if (!fifo) {
955 addr += pkt_len;
956 }
957 SGCount ++;
958
959 }
960
961 /* Release host controller */
962 sdio_release_host(gInstance->func[func]);
963
964 sd_trace(("%s: Exit\n", __FUNCTION__));
965 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
966}
967
968
969/*
970 * This function takes a buffer or packet, and fixes everything up so that in the
971 * end, a DMA-able packet is created.
972 *
973 * A buffer does not have an associated packet pointer, and may or may not be aligned.
974 * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
975 * then all the packets in the chain must be properly aligned. If the packet data is not
976 * aligned, then there may only be one packet, and in this case, it is copied to a new
977 * aligned packet.
978 *
979 */
980extern SDIOH_API_RC
981sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
982 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
983{
984 SDIOH_API_RC Status;
985 void *mypkt = NULL;
986
987 sd_trace(("%s: Enter\n", __FUNCTION__));
988
989 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
990 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
991 /* Case 1: we don't have a packet. */
992 if (pkt == NULL) {
993 sd_data(("%s: Creating new %s Packet, len=%d\n",
994 __FUNCTION__, write ? "TX" : "RX", buflen_u));
995#ifdef DHD_USE_STATIC_BUF
996 if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
997#else
998 if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
999#endif /* DHD_USE_STATIC_BUF */
1000 sd_err(("%s: PKTGET failed: len %d\n",
1001 __FUNCTION__, buflen_u));
1002 return SDIOH_API_RC_FAIL;
1003 }
1004
1005 /* For a write, copy the buffer data into the packet. */
1006 if (write) {
1007 bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u);
1008 }
1009
1010 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1011
1012 /* For a read, copy the packet data back to the buffer. */
1013 if (!write) {
1014 bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
1015 }
1016#ifdef DHD_USE_STATIC_BUF
1017 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1018#else
1019 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1020#endif /* DHD_USE_STATIC_BUF */
1021 } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
1022 /* Case 2: We have a packet, but it is unaligned. */
1023
1024 /* In this case, we cannot have a chain. */
1025 ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
1026
1027 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1028 __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
1029#ifdef DHD_USE_STATIC_BUF
1030 if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1031#else
1032 if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1033#endif /* DHD_USE_STATIC_BUF */
1034 sd_err(("%s: PKTGET failed: len %d\n",
1035 __FUNCTION__, PKTLEN(sd->osh, pkt)));
1036 return SDIOH_API_RC_FAIL;
1037 }
1038
1039 /* For a write, copy the buffer data into the packet. */
1040 if (write) {
1041 bcopy(PKTDATA(sd->osh, pkt),
1042 PKTDATA(sd->osh, mypkt),
1043 PKTLEN(sd->osh, pkt));
1044 }
1045
1046 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1047
1048 /* For a read, copy the packet data back to the buffer. */
1049 if (!write) {
1050 bcopy(PKTDATA(sd->osh, mypkt),
1051 PKTDATA(sd->osh, pkt),
1052 PKTLEN(sd->osh, mypkt));
1053 }
1054#ifdef DHD_USE_STATIC_BUF
1055 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1056#else
1057 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1058#endif /* DHD_USE_STATIC_BUF */
1059 } else { /* case 3: We have a packet and it is aligned. */
1060 sd_data(("%s: Aligned %s Packet, direct DMA\n",
1061 __FUNCTION__, write ? "Tx" : "Rx"));
1062 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1063 }
1064
1065 return (Status);
1066}
1067
1068/* this function performs "abort" for both of host & device */
1069extern int
1070sdioh_abort(sdioh_info_t *sd, uint func)
1071{
1072#if defined(MMC_SDIO_ABORT)
1073 char t_func = (char) func;
1074#endif /* defined(MMC_SDIO_ABORT) */
1075 sd_trace(("%s: Enter\n", __FUNCTION__));
1076
1077#if defined(MMC_SDIO_ABORT)
1078 /* issue abort cmd52 command through F1 */
1079 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func);
1080#endif /* defined(MMC_SDIO_ABORT) */
1081
1082 sd_trace(("%s: Exit\n", __FUNCTION__));
1083 return SDIOH_API_RC_SUCCESS;
1084}
1085
1086/* Reset and re-initialize the device */
1087int sdioh_sdio_reset(sdioh_info_t *si)
1088{
1089 sd_trace(("%s: Enter\n", __FUNCTION__));
1090 sd_trace(("%s: Exit\n", __FUNCTION__));
1091 return SDIOH_API_RC_SUCCESS;
1092}
1093
1094/* Disable device interrupt */
1095void
1096sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1097{
1098 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1099 sd->intmask &= ~CLIENT_INTR;
1100}
1101
1102/* Enable device interrupt */
1103void
1104sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1105{
1106 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1107 sd->intmask |= CLIENT_INTR;
1108}
1109
1110/* Read client card reg */
1111int
1112sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
1113{
1114
1115 if ((func == 0) || (regsize == 1)) {
1116 uint8 temp = 0;
1117
1118 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1119 *data = temp;
1120 *data &= 0xff;
1121 sd_data(("%s: byte read data=0x%02x\n",
1122 __FUNCTION__, *data));
1123 } else {
1124 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
1125 if (regsize == 2)
1126 *data &= 0xffff;
1127
1128 sd_data(("%s: word read data=0x%08x\n",
1129 __FUNCTION__, *data));
1130 }
1131
1132 return SUCCESS;
1133}
1134
1135#if !defined(OOB_INTR_ONLY)
1136/* bcmsdh_sdmmc interrupt handler */
1137static void IRQHandler(struct sdio_func *func)
1138{
1139 sdioh_info_t *sd;
1140
1141 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1142 sd = gInstance->sd;
1143
1144 ASSERT(sd != NULL);
1145 sdio_release_host(gInstance->func[0]);
1146
1147 if (sd->use_client_ints) {
1148 sd->intrcount++;
1149 ASSERT(sd->intr_handler);
1150 ASSERT(sd->intr_handler_arg);
1151 (sd->intr_handler)(sd->intr_handler_arg);
1152 } else {
1153 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1154
1155 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1156 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
1157 }
1158
1159 sdio_claim_host(gInstance->func[0]);
1160}
1161
1162/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1163static void IRQHandlerF2(struct sdio_func *func)
1164{
1165 sdioh_info_t *sd;
1166
1167 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1168
1169 sd = gInstance->sd;
1170
1171 ASSERT(sd != NULL);
1172}
1173#endif /* !defined(OOB_INTR_ONLY) */
1174
1175#ifdef NOTUSED
1176/* Write client card reg */
1177static int
1178sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
1179{
1180
1181 if ((func == 0) || (regsize == 1)) {
1182 uint8 temp;
1183
1184 temp = data & 0xff;
1185 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1186 sd_data(("%s: byte write data=0x%02x\n",
1187 __FUNCTION__, data));
1188 } else {
1189 if (regsize == 2)
1190 data &= 0xffff;
1191
1192 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
1193
1194 sd_data(("%s: word write data=0x%08x\n",
1195 __FUNCTION__, data));
1196 }
1197
1198 return SUCCESS;
1199}
1200#endif /* NOTUSED */
1201
1202int
1203sdioh_start(sdioh_info_t *si, int stage)
1204{
1205 int ret;
1206 sdioh_info_t *sd = gInstance->sd;
1207
1208 /* Need to do this stages as we can't enable the interrupt till
1209 downloading of the firmware is complete, other wise polling
1210 sdio access will come in way
1211 */
1212 if (gInstance->func[0]) {
1213 if (stage == 0) {
1214 /* Since the power to the chip is killed, we will have
1215 re enumerate the device again. Set the block size
1216 and enable the fucntion 1 for in preparation for
1217 downloading the code
1218 */
1219 /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
1220 2.6.27. The implementation prior to that is buggy, and needs broadcom's
1221 patch for it
1222 */
1223 if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
1224 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
1225 else {
1226 sd->num_funcs = 2;
1227 sd->sd_blockmode = TRUE;
1228 sd->use_client_ints = TRUE;
1229 sd->client_block_size[0] = 64;
1230
1231 /* Claim host controller */
1232 sdio_claim_host(gInstance->func[1]);
1233
1234 sd->client_block_size[1] = 64;
1235 if (sdio_set_block_size(gInstance->func[1], 64)) {
1236 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
1237 }
1238
1239 /* Release host controller F1 */
1240 sdio_release_host(gInstance->func[1]);
1241
1242 if (gInstance->func[2]) {
1243 /* Claim host controller F2 */
1244 sdio_claim_host(gInstance->func[2]);
1245
1246 sd->client_block_size[2] = sd_f2_blocksize;
1247 if (sdio_set_block_size(gInstance->func[2],
1248 sd_f2_blocksize)) {
1249 sd_err(("bcmsdh_sdmmc: Failed to set F2 "
1250 "blocksize to %d\n", sd_f2_blocksize));
1251 }
1252
1253 /* Release host controller F2 */
1254 sdio_release_host(gInstance->func[2]);
1255 }
1256
1257 sdioh_sdmmc_card_enablefuncs(sd);
1258 }
1259 } else {
1260#if !defined(OOB_INTR_ONLY)
1261 sdio_claim_host(gInstance->func[0]);
1262 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
1263 sdio_claim_irq(gInstance->func[1], IRQHandler);
1264 sdio_release_host(gInstance->func[0]);
1265#else /* defined(OOB_INTR_ONLY) */
1266#if defined(HW_OOB)
1267 sdioh_enable_func_intr();
1268#endif
1269 bcmsdh_oob_intr_set(TRUE);
1270#endif /* !defined(OOB_INTR_ONLY) */
1271 }
1272 }
1273 else
1274 sd_err(("%s Failed\n", __FUNCTION__));
1275
1276 return (0);
1277}
1278
1279int
1280sdioh_stop(sdioh_info_t *si)
1281{
1282 /* MSM7201A Android sdio stack has bug with interrupt
1283 So internaly within SDIO stack they are polling
1284 which cause issue when device is turned off. So
1285 unregister interrupt with SDIO stack to stop the
1286 polling
1287 */
1288 if (gInstance->func[0]) {
1289#if !defined(OOB_INTR_ONLY)
1290 sdio_claim_host(gInstance->func[0]);
1291 sdio_release_irq(gInstance->func[1]);
1292 sdio_release_irq(gInstance->func[2]);
1293 sdio_release_host(gInstance->func[0]);
1294#else /* defined(OOB_INTR_ONLY) */
1295#if defined(HW_OOB)
1296 sdioh_disable_func_intr();
1297#endif
1298 bcmsdh_oob_intr_set(FALSE);
1299#endif /* !defined(OOB_INTR_ONLY) */
1300 }
1301 else
1302 sd_err(("%s Failed\n", __FUNCTION__));
1303 return (0);
1304}