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