temp revert rk change
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / bcm4329 / bcmsdh_sdmmc.c
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>
46 extern volatile bool dhd_mmc_suspend;
47 #endif
48 #include "bcmsdh_sdmmc.h"
49
50 #ifndef BCMSDH_MODULE
51 extern int sdio_function_init(void);
52 extern void sdio_function_cleanup(void);
53 #endif /* BCMSDH_MODULE */
54
55 #if !defined(OOB_INTR_ONLY)
56 static void IRQHandler(struct sdio_func *func);
57 static void IRQHandlerF2(struct sdio_func *func);
58 #endif /* !defined(OOB_INTR_ONLY) */
59 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
60 extern int sdio_reset_comm(struct mmc_card *card);
61
62 extern PBCMSDH_SDMMC_INSTANCE gInstance;
63
64 uint sd_sdmode = SDIOH_MODE_SD4;        /* Use SD4 mode by default */
65 uint sd_f2_blocksize = 512;             /* Default blocksize */
66
67 uint sd_divisor = 2;                    /* Default 48MHz/2 = 24MHz */
68
69 uint sd_power = 1;              /* Default to SD Slot powered ON */
70 uint sd_clock = 1;              /* Default to SD Clock turned ON */
71 uint sd_hiok = FALSE;   /* Don't use hi-speed mode by default */
72 uint sd_msglevel = 0x01;
73 uint sd_use_dma = TRUE;
74 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
75 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
76 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
77 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
78
79 #define DMA_ALIGN_MASK  0x03
80
81 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
82
83 static int
84 sdioh_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  */
122 extern sdioh_info_t *
123 sdioh_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
188 extern SDIOH_API_RC
189 sdioh_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
215 extern SDIOH_API_RC
216 sdioh_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
246 extern SDIOH_API_RC
247 sdioh_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 */
278 extern SDIOH_API_RC
279 sdioh_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
309 extern SDIOH_API_RC
310 sdioh_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
339 extern SDIOH_API_RC
340 sdioh_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)
348 extern bool
349 sdioh_interrupt_pending(sdioh_info_t *sd)
350 {
351         return (0);
352 }
353 #endif
354
355 uint
356 sdioh_query_iofnum(sdioh_info_t *sd)
357 {
358         return sd->num_funcs;
359 }
360
361 /* IOVar table */
362 enum {
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
381 const 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
400 int
401 sdioh_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         }
661 exit:
662
663         return bcmerror;
664 }
665
666 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
667
668 SDIOH_API_RC
669 sdioh_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
685 extern SDIOH_API_RC
686 sdioh_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
694 extern SDIOH_API_RC
695 sdioh_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
703 static int
704 sdioh_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
724 extern SDIOH_API_RC
725 sdioh_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
756 extern SDIOH_API_RC
757 sdioh_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
839 extern SDIOH_API_RC
840 sdioh_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
887 static SDIOH_API_RC
888 sdioh_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  */
980 extern SDIOH_API_RC
981 sdioh_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 */
1069 extern int
1070 sdioh_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 */
1087 int 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 */
1095 void
1096 sdioh_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 */
1103 void
1104 sdioh_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 */
1111 int
1112 sdioh_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 */
1137 static 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) */
1163 static 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 */
1177 static int
1178 sdioh_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
1202 int
1203 sdioh_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
1279 int
1280 sdioh_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 }