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