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