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