OSDN Git Service

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