2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
16 #include <linux/types.h>
17 #include <linux/netdevice.h>
21 #include <sdio.h> /* SDIO Device and Protocol Specs */
22 #include <sdioh.h> /* SDIO Host Controller Specification */
23 #include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
24 #include <sdiovar.h> /* ioctl/iovars */
26 #include <linux/mmc/core.h>
27 #include <linux/mmc/sdio_func.h>
28 #include <linux/mmc/sdio_ids.h>
30 #include <dngl_stats.h>
33 #if defined(CONFIG_PM_SLEEP)
34 #include <linux/suspend.h>
35 extern volatile bool dhd_mmc_suspend;
37 #include "bcmsdh_sdmmc.h"
39 extern int sdio_function_init(void);
40 extern void sdio_function_cleanup(void);
42 #if !defined(OOB_INTR_ONLY)
43 static void IRQHandler(struct sdio_func *func);
44 static void IRQHandlerF2(struct sdio_func *func);
45 #endif /* !defined(OOB_INTR_ONLY) */
46 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, u32 regaddr);
47 extern int sdio_reset_comm(struct mmc_card *card);
49 extern PBCMSDH_SDMMC_INSTANCE gInstance;
51 uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
52 uint sd_f2_blocksize = 512; /* Default blocksize */
54 uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
56 uint sd_power = 1; /* Default to SD Slot powered ON */
57 uint sd_clock = 1; /* Default to SD Clock turned ON */
58 uint sd_hiok = false; /* Don't use hi-speed mode by default */
59 uint sd_msglevel = 0x01;
60 uint sd_use_dma = true;
61 DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
62 DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
63 DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
64 DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
66 #define DMA_ALIGN_MASK 0x03
68 int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, u32 regaddr,
69 int regsize, u32 *data);
71 static int sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
77 sd_trace(("%s\n", __func__));
79 /* Get the Card's common CIS address */
80 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
81 sd->func_cis_ptr[0] = sd->com_cis_ptr;
82 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
85 /* Get the Card's function CIS (for each function) */
86 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
87 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
88 sd->func_cis_ptr[func] =
89 sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
90 sd_info(("%s: Function %d CIS Ptr = 0x%x\n", __func__, func,
91 sd->func_cis_ptr[func]));
94 sd->func_cis_ptr[0] = sd->com_cis_ptr;
95 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
98 /* Enable Function 1 */
99 sdio_claim_host(gInstance->func[1]);
100 err_ret = sdio_enable_func(gInstance->func[1]);
101 sdio_release_host(gInstance->func[1]);
103 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x",
111 * Public entry points & extern's
113 sdioh_info_t *sdioh_attach(void *bar0, uint irq)
118 sd_trace(("%s\n", __func__));
120 if (gInstance == NULL) {
121 sd_err(("%s: SDIO Device not present\n", __func__));
125 sd = kzalloc(sizeof(sdioh_info_t), GFP_ATOMIC);
127 sd_err(("sdioh_attach: out of memory\n"));
130 if (sdioh_sdmmc_osinit(sd) != 0) {
131 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __func__));
137 sd->sd_blockmode = true;
138 sd->use_client_ints = true;
139 sd->client_block_size[0] = 64;
143 /* Claim host controller */
144 sdio_claim_host(gInstance->func[1]);
146 sd->client_block_size[1] = 64;
147 err_ret = sdio_set_block_size(gInstance->func[1], 64);
149 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
151 /* Release host controller F1 */
152 sdio_release_host(gInstance->func[1]);
154 if (gInstance->func[2]) {
155 /* Claim host controller F2 */
156 sdio_claim_host(gInstance->func[2]);
158 sd->client_block_size[2] = sd_f2_blocksize;
160 sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
162 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize "
163 "to %d\n", sd_f2_blocksize));
165 /* Release host controller F2 */
166 sdio_release_host(gInstance->func[2]);
169 sdioh_sdmmc_card_enablefuncs(sd);
171 sd_trace(("%s: Done\n", __func__));
175 extern SDIOH_API_RC sdioh_detach(sdioh_info_t *sd)
177 sd_trace(("%s\n", __func__));
181 /* Disable Function 2 */
182 sdio_claim_host(gInstance->func[2]);
183 sdio_disable_func(gInstance->func[2]);
184 sdio_release_host(gInstance->func[2]);
186 /* Disable Function 1 */
187 sdio_claim_host(gInstance->func[1]);
188 sdio_disable_func(gInstance->func[1]);
189 sdio_release_host(gInstance->func[1]);
192 sdioh_sdmmc_osfree(sd);
196 return SDIOH_API_RC_SUCCESS;
199 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
201 extern SDIOH_API_RC sdioh_enable_func_intr(void)
206 if (gInstance->func[0]) {
207 sdio_claim_host(gInstance->func[0]);
209 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
211 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n",
213 sdio_release_host(gInstance->func[0]);
214 return SDIOH_API_RC_FAIL;
217 /* Enable F1 and F2 interrupts, set master enable */
219 (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN |
222 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
223 sdio_release_host(gInstance->func[0]);
226 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n",
228 return SDIOH_API_RC_FAIL;
232 return SDIOH_API_RC_SUCCESS;
235 extern SDIOH_API_RC sdioh_disable_func_intr(void)
240 if (gInstance->func[0]) {
241 sdio_claim_host(gInstance->func[0]);
242 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
244 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n",
246 sdio_release_host(gInstance->func[0]);
247 return SDIOH_API_RC_FAIL;
250 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
251 /* Disable master interrupt with the last function interrupt */
254 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
256 sdio_release_host(gInstance->func[0]);
258 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n",
260 return SDIOH_API_RC_FAIL;
263 return SDIOH_API_RC_SUCCESS;
265 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
267 /* Configure callback to client when we receive client interrupt */
269 sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
271 sd_trace(("%s: Entering\n", __func__));
273 sd_err(("%s: interrupt handler is NULL, not registering\n",
275 return SDIOH_API_RC_FAIL;
277 #if !defined(OOB_INTR_ONLY)
278 sd->intr_handler = fn;
279 sd->intr_handler_arg = argh;
280 sd->intr_handler_valid = true;
282 /* register and unmask irq */
283 if (gInstance->func[2]) {
284 sdio_claim_host(gInstance->func[2]);
285 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
286 sdio_release_host(gInstance->func[2]);
289 if (gInstance->func[1]) {
290 sdio_claim_host(gInstance->func[1]);
291 sdio_claim_irq(gInstance->func[1], IRQHandler);
292 sdio_release_host(gInstance->func[1]);
294 #elif defined(HW_OOB)
295 sdioh_enable_func_intr();
296 #endif /* defined(OOB_INTR_ONLY) */
297 return SDIOH_API_RC_SUCCESS;
300 extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *sd)
302 sd_trace(("%s: Entering\n", __func__));
304 #if !defined(OOB_INTR_ONLY)
305 if (gInstance->func[1]) {
306 /* register and unmask irq */
307 sdio_claim_host(gInstance->func[1]);
308 sdio_release_irq(gInstance->func[1]);
309 sdio_release_host(gInstance->func[1]);
312 if (gInstance->func[2]) {
313 /* Claim host controller F2 */
314 sdio_claim_host(gInstance->func[2]);
315 sdio_release_irq(gInstance->func[2]);
316 /* Release host controller F2 */
317 sdio_release_host(gInstance->func[2]);
320 sd->intr_handler_valid = false;
321 sd->intr_handler = NULL;
322 sd->intr_handler_arg = NULL;
323 #elif defined(HW_OOB)
324 sdioh_disable_func_intr();
325 #endif /* !defined(OOB_INTR_ONLY) */
326 return SDIOH_API_RC_SUCCESS;
329 extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
331 sd_trace(("%s: Entering\n", __func__));
332 *onoff = sd->client_intr_enabled;
333 return SDIOH_API_RC_SUCCESS;
336 #if defined(DHD_DEBUG)
337 extern bool sdioh_interrupt_pending(sdioh_info_t *sd)
343 uint sdioh_query_iofnum(sdioh_info_t *sd)
345 return sd->num_funcs;
368 const bcm_iovar_t sdioh_iovars[] = {
369 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0},
370 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0},
371 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0},/* ((fn << 16) |
373 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0},
374 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0},
375 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0},
376 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0},
377 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t)}
379 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t)}
381 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0}
383 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0}
385 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0}
387 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100}
389 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0}
391 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0}
397 sdioh_iovar_op(sdioh_info_t *si, const char *name,
398 void *params, int plen, void *arg, int len, bool set)
400 const bcm_iovar_t *vi = NULL;
410 /* Get must have return space; Set does not take qualifiers */
411 ASSERT(set || (arg && len));
412 ASSERT(!set || (!params && !plen));
414 sd_trace(("%s: Enter (%s %s)\n", __func__, (set ? "set" : "get"),
417 vi = bcm_iovar_lookup(sdioh_iovars, name);
419 bcmerror = BCME_UNSUPPORTED;
423 bcmerror = bcm_iovar_lencheck(vi, arg, len, set);
427 /* Set up params so get and set can share the convenience variables */
428 if (params == NULL) {
433 if (vi->type == IOVT_VOID)
435 else if (vi->type == IOVT_BUFFER)
438 val_size = sizeof(int);
440 if (plen >= (int)sizeof(int_val))
441 memcpy(&int_val, params, sizeof(int_val));
443 bool_val = (int_val != 0) ? true : false;
445 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
447 case IOV_GVAL(IOV_MSGLEVEL):
448 int_val = (s32) sd_msglevel;
449 memcpy(arg, &int_val, val_size);
452 case IOV_SVAL(IOV_MSGLEVEL):
453 sd_msglevel = int_val;
456 case IOV_GVAL(IOV_BLOCKMODE):
457 int_val = (s32) si->sd_blockmode;
458 memcpy(arg, &int_val, val_size);
461 case IOV_SVAL(IOV_BLOCKMODE):
462 si->sd_blockmode = (bool) int_val;
463 /* Haven't figured out how to make non-block mode with DMA */
466 case IOV_GVAL(IOV_BLOCKSIZE):
467 if ((u32) int_val > si->num_funcs) {
468 bcmerror = BCME_BADARG;
471 int_val = (s32) si->client_block_size[int_val];
472 memcpy(arg, &int_val, val_size);
475 case IOV_SVAL(IOV_BLOCKSIZE):
477 uint func = ((u32) int_val >> 16);
478 uint blksize = (u16) int_val;
481 if (func > si->num_funcs) {
482 bcmerror = BCME_BADARG;
491 maxsize = BLOCK_SIZE_4318;
494 maxsize = BLOCK_SIZE_4328;
499 if (blksize > maxsize) {
500 bcmerror = BCME_BADARG;
507 si->client_block_size[func] = blksize;
512 case IOV_GVAL(IOV_RXCHAIN):
514 memcpy(arg, &int_val, val_size);
517 case IOV_GVAL(IOV_DMA):
518 int_val = (s32) si->sd_use_dma;
519 memcpy(arg, &int_val, val_size);
522 case IOV_SVAL(IOV_DMA):
523 si->sd_use_dma = (bool) int_val;
526 case IOV_GVAL(IOV_USEINTS):
527 int_val = (s32) si->use_client_ints;
528 memcpy(arg, &int_val, val_size);
531 case IOV_SVAL(IOV_USEINTS):
532 si->use_client_ints = (bool) int_val;
533 if (si->use_client_ints)
534 si->intmask |= CLIENT_INTR;
536 si->intmask &= ~CLIENT_INTR;
540 case IOV_GVAL(IOV_DIVISOR):
541 int_val = (u32) sd_divisor;
542 memcpy(arg, &int_val, val_size);
545 case IOV_SVAL(IOV_DIVISOR):
546 sd_divisor = int_val;
549 case IOV_GVAL(IOV_POWER):
550 int_val = (u32) sd_power;
551 memcpy(arg, &int_val, val_size);
554 case IOV_SVAL(IOV_POWER):
558 case IOV_GVAL(IOV_CLOCK):
559 int_val = (u32) sd_clock;
560 memcpy(arg, &int_val, val_size);
563 case IOV_SVAL(IOV_CLOCK):
567 case IOV_GVAL(IOV_SDMODE):
568 int_val = (u32) sd_sdmode;
569 memcpy(arg, &int_val, val_size);
572 case IOV_SVAL(IOV_SDMODE):
576 case IOV_GVAL(IOV_HISPEED):
577 int_val = (u32) sd_hiok;
578 memcpy(arg, &int_val, val_size);
581 case IOV_SVAL(IOV_HISPEED):
585 case IOV_GVAL(IOV_NUMINTS):
586 int_val = (s32) si->intrcount;
587 memcpy(arg, &int_val, val_size);
590 case IOV_GVAL(IOV_NUMLOCALINTS):
592 memcpy(arg, &int_val, val_size);
595 case IOV_GVAL(IOV_HOSTREG):
597 sdreg_t *sd_ptr = (sdreg_t *) params;
599 if (sd_ptr->offset < SD_SysAddr
600 || sd_ptr->offset > SD_MaxCurCap) {
601 sd_err(("%s: bad offset 0x%x\n", __func__,
603 bcmerror = BCME_BADARG;
607 sd_trace(("%s: rreg%d at offset %d\n", __func__,
608 (sd_ptr->offset & 1) ? 8
609 : ((sd_ptr->offset & 2) ? 16 : 32),
611 if (sd_ptr->offset & 1)
612 int_val = 8; /* sdioh_sdmmc_rreg8(si,
614 else if (sd_ptr->offset & 2)
615 int_val = 16; /* sdioh_sdmmc_rreg16(si,
618 int_val = 32; /* sdioh_sdmmc_rreg(si,
621 memcpy(arg, &int_val, sizeof(int_val));
625 case IOV_SVAL(IOV_HOSTREG):
627 sdreg_t *sd_ptr = (sdreg_t *) params;
629 if (sd_ptr->offset < SD_SysAddr
630 || sd_ptr->offset > SD_MaxCurCap) {
631 sd_err(("%s: bad offset 0x%x\n", __func__,
633 bcmerror = BCME_BADARG;
637 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n",
638 __func__, sd_ptr->value,
639 (sd_ptr->offset & 1) ? 8
640 : ((sd_ptr->offset & 2) ? 16 : 32),
645 case IOV_GVAL(IOV_DEVREG):
647 sdreg_t *sd_ptr = (sdreg_t *) params;
651 (si, sd_ptr->func, sd_ptr->offset, &data)) {
652 bcmerror = BCME_SDIO_ERROR;
657 memcpy(arg, &int_val, sizeof(int_val));
661 case IOV_SVAL(IOV_DEVREG):
663 sdreg_t *sd_ptr = (sdreg_t *) params;
664 u8 data = (u8) sd_ptr->value;
667 (si, sd_ptr->func, sd_ptr->offset, &data)) {
668 bcmerror = BCME_SDIO_ERROR;
675 bcmerror = BCME_UNSUPPORTED;
683 #if defined(OOB_INTR_ONLY) && defined(HW_OOB)
685 SDIOH_API_RC sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
691 data = 3; /* enable hw oob interrupt */
693 data = 4; /* disable hw oob interrupt */
694 data |= 4; /* Active HIGH */
696 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
699 #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
702 sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, u32 addr, u8 *data)
705 /* No lock needed since sdioh_request_byte does locking */
706 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
711 sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, u32 addr, u8 *data)
713 /* No lock needed since sdioh_request_byte does locking */
715 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
719 static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, u32 regaddr)
721 /* read 24 bits and return valid 17 bit addr */
723 u32 scratch, regdata;
724 u8 *ptr = (u8 *)&scratch;
725 for (i = 0; i < 3; i++) {
726 if ((sdioh_sdmmc_card_regread(sd, 0, regaddr, 1, ®data)) !=
728 sd_err(("%s: Can't read!\n", __func__));
730 *ptr++ = (u8) regdata;
734 /* Only the lower 17-bits are valid */
735 scratch = le32_to_cpu(scratch);
736 scratch &= 0x0001FFFF;
741 sdioh_cis_read(sdioh_info_t *sd, uint func, u8 *cisd, u32 length)
748 sd_trace(("%s: Func = %d\n", __func__, func));
750 if (!sd->func_cis_ptr[func]) {
751 memset(cis, 0, length);
752 sd_err(("%s: no func_cis_ptr[%d]\n", __func__, func));
753 return SDIOH_API_RC_FAIL;
756 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __func__, func,
757 sd->func_cis_ptr[func]));
759 for (count = 0; count < length; count++) {
760 offset = sd->func_cis_ptr[func] + count;
761 if (sdioh_sdmmc_card_regread(sd, 0, offset, 1, &foo) < 0) {
762 sd_err(("%s: regread failed: Can't read CIS\n",
764 return SDIOH_API_RC_FAIL;
767 *cis = (u8) (foo & 0xff);
771 return SDIOH_API_RC_SUCCESS;
775 sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr,
780 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __func__, rw, func,
783 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
784 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
785 if (rw) { /* CMD52 Write */
787 /* Can only directly write to some F0 registers.
791 if (regaddr == SDIOD_CCCR_IOEN) {
792 if (gInstance->func[2]) {
793 sdio_claim_host(gInstance->func[2]);
794 if (*byte & SDIO_FUNC_ENABLE_2) {
795 /* Enable Function 2 */
798 (gInstance->func[2]);
800 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
803 /* Disable Function 2 */
806 (gInstance->func[2]);
808 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
811 sdio_release_host(gInstance->func[2]);
814 #if defined(MMC_SDIO_ABORT)
815 /* to allow abort command through F1 */
816 else if (regaddr == SDIOD_CCCR_IOABORT) {
817 sdio_claim_host(gInstance->func[func]);
819 * this sdio_f0_writeb() can be replaced
821 * depending upon MMC driver change.
822 * As of this time, this is temporaray one
824 sdio_writeb(gInstance->func[func], *byte,
826 sdio_release_host(gInstance->func[func]);
828 #endif /* MMC_SDIO_ABORT */
829 else if (regaddr < 0xF0) {
830 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write "
831 "disallowed\n", regaddr));
833 /* Claim host controller, perform F0 write,
835 sdio_claim_host(gInstance->func[func]);
836 sdio_f0_writeb(gInstance->func[func], *byte,
838 sdio_release_host(gInstance->func[func]);
841 /* Claim host controller, perform Fn write,
843 sdio_claim_host(gInstance->func[func]);
844 sdio_writeb(gInstance->func[func], *byte, regaddr,
846 sdio_release_host(gInstance->func[func]);
848 } else { /* CMD52 Read */
849 /* Claim host controller, perform Fn read, and release */
850 sdio_claim_host(gInstance->func[func]);
854 sdio_f0_readb(gInstance->func[func], regaddr,
858 sdio_readb(gInstance->func[func], regaddr,
862 sdio_release_host(gInstance->func[func]);
866 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, "
867 "Err: %d\n", rw ? "Write" : "Read", func, regaddr,
870 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
874 sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func,
875 uint addr, u32 *word, uint nbytes)
877 int err_ret = SDIOH_API_RC_FAIL;
880 sd_err(("%s: Only CMD52 allowed to F0.\n", __func__));
881 return SDIOH_API_RC_FAIL;
884 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
885 __func__, cmd_type, rw, func, addr, nbytes));
887 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
888 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
889 /* Claim host controller */
890 sdio_claim_host(gInstance->func[func]);
892 if (rw) { /* CMD52 Write */
894 sdio_writel(gInstance->func[func], *word, addr,
896 } else if (nbytes == 2) {
897 sdio_writew(gInstance->func[func], (*word & 0xFFFF),
900 sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
902 } else { /* CMD52 Read */
905 sdio_readl(gInstance->func[func], addr, &err_ret);
906 } else if (nbytes == 2) {
908 sdio_readw(gInstance->func[func], addr,
911 sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
915 /* Release host controller */
916 sdio_release_host(gInstance->func[func]);
919 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
920 rw ? "Write" : "Read", err_ret));
923 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
927 sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
928 uint addr, struct sk_buff *pkt)
930 bool fifo = (fix_inc == SDIOH_DATA_FIX);
934 struct sk_buff *pnext;
936 sd_trace(("%s: Enter\n", __func__));
939 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
940 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
942 /* Claim host controller */
943 sdio_claim_host(gInstance->func[func]);
944 for (pnext = pkt; pnext; pnext = pnext->next) {
945 uint pkt_len = pnext->len;
947 pkt_len &= 0xFFFFFFFC;
949 #ifdef CONFIG_MMC_MSM7X00A
950 if ((pkt_len % 64) == 32) {
951 sd_trace(("%s: Rounding up TX packet +=32\n",
955 #endif /* CONFIG_MMC_MSM7X00A */
956 /* Make sure the packet is aligned properly.
957 * If it isn't, then this
958 * is the fault of sdioh_request_buffer() which
959 * is supposed to give
960 * us something we can work with.
962 ASSERT(((u32) (pkt->data) & DMA_ALIGN_MASK) == 0);
964 if ((write) && (!fifo)) {
965 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
966 ((u8 *) (pnext->data)),
969 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
970 ((u8 *) (pnext->data)),
973 err_ret = sdio_readsb(gInstance->func[func],
974 ((u8 *) (pnext->data)),
977 err_ret = sdio_memcpy_fromio(gInstance->func[func],
978 ((u8 *) (pnext->data)),
983 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d,"
984 "ERR=0x%08x\n", __func__,
985 (write) ? "TX" : "RX",
986 pnext, SGCount, addr, pkt_len, err_ret));
988 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
990 (write) ? "TX" : "RX",
991 pnext, SGCount, addr, pkt_len));
1000 /* Release host controller */
1001 sdio_release_host(gInstance->func[func]);
1003 sd_trace(("%s: Exit\n", __func__));
1004 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
1008 * This function takes a buffer or packet, and fixes everything up
1010 * end, a DMA-able packet is created.
1012 * A buffer does not have an associated packet pointer,
1013 * and may or may not be aligned.
1014 * A packet may consist of a single packet, or a packet chain.
1015 * If it is a packet chain,
1016 * then all the packets in the chain must be properly aligned.
1017 * If the packet data is not
1018 * aligned, then there may only be one packet, and in this case,
1019 * it is copied to a new
1024 sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write,
1025 uint func, uint addr, uint reg_width, uint buflen_u,
1026 u8 *buffer, struct sk_buff *pkt)
1028 SDIOH_API_RC Status;
1029 struct sk_buff *mypkt = NULL;
1031 sd_trace(("%s: Enter\n", __func__));
1033 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
1034 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
1035 /* Case 1: we don't have a packet. */
1037 sd_data(("%s: Creating new %s Packet, len=%d\n",
1038 __func__, write ? "TX" : "RX", buflen_u));
1039 mypkt = pkt_buf_get_skb(buflen_u);
1041 sd_err(("%s: pkt_buf_get_skb failed: len %d\n",
1042 __func__, buflen_u));
1043 return SDIOH_API_RC_FAIL;
1046 /* For a write, copy the buffer data into the packet. */
1048 memcpy(mypkt->data, buffer, buflen_u);
1051 sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1053 /* For a read, copy the packet data back to the buffer. */
1055 memcpy(buffer, mypkt->data, buflen_u);
1057 pkt_buf_free_skb(mypkt);
1058 } else if (((u32) (pkt->data) & DMA_ALIGN_MASK) != 0) {
1059 /* Case 2: We have a packet, but it is unaligned. */
1061 /* In this case, we cannot have a chain. */
1062 ASSERT(pkt->next == NULL);
1064 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1065 __func__, write ? "TX" : "RX", pkt->len));
1066 mypkt = pkt_buf_get_skb(pkt->len);
1068 sd_err(("%s: pkt_buf_get_skb failed: len %d\n",
1069 __func__, pkt->len));
1070 return SDIOH_API_RC_FAIL;
1073 /* For a write, copy the buffer data into the packet. */
1075 memcpy(mypkt->data, pkt->data, pkt->len);
1078 sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1080 /* For a read, copy the packet data back to the buffer. */
1082 memcpy(pkt->data, mypkt->data, mypkt->len);
1084 pkt_buf_free_skb(mypkt);
1085 } else { /* case 3: We have a packet and
1087 sd_data(("%s: Aligned %s Packet, direct DMA\n",
1088 __func__, write ? "Tx" : "Rx"));
1090 sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1096 /* this function performs "abort" for both of host & device */
1097 extern int sdioh_abort(sdioh_info_t *sd, uint func)
1099 #if defined(MMC_SDIO_ABORT)
1100 char t_func = (char)func;
1101 #endif /* defined(MMC_SDIO_ABORT) */
1102 sd_trace(("%s: Enter\n", __func__));
1104 #if defined(MMC_SDIO_ABORT)
1105 /* issue abort cmd52 command through F1 */
1106 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT,
1108 #endif /* defined(MMC_SDIO_ABORT) */
1110 sd_trace(("%s: Exit\n", __func__));
1111 return SDIOH_API_RC_SUCCESS;
1114 /* Reset and re-initialize the device */
1115 int sdioh_sdio_reset(sdioh_info_t *si)
1117 sd_trace(("%s: Enter\n", __func__));
1118 sd_trace(("%s: Exit\n", __func__));
1119 return SDIOH_API_RC_SUCCESS;
1122 /* Disable device interrupt */
1123 void sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1125 sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
1126 sd->intmask &= ~CLIENT_INTR;
1129 /* Enable device interrupt */
1130 void sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1132 sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
1133 sd->intmask |= CLIENT_INTR;
1136 /* Read client card reg */
1138 sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, u32 regaddr,
1139 int regsize, u32 *data)
1142 if ((func == 0) || (regsize == 1)) {
1145 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1148 sd_data(("%s: byte read data=0x%02x\n", __func__, *data));
1150 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data,
1155 sd_data(("%s: word read data=0x%08x\n", __func__, *data));
1161 #if !defined(OOB_INTR_ONLY)
1162 /* bcmsdh_sdmmc interrupt handler */
1163 static void IRQHandler(struct sdio_func *func)
1167 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1171 sdio_release_host(gInstance->func[0]);
1173 if (sd->use_client_ints) {
1175 ASSERT(sd->intr_handler);
1176 ASSERT(sd->intr_handler_arg);
1177 (sd->intr_handler) (sd->intr_handler_arg);
1179 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1181 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1182 __func__, sd->client_intr_enabled, sd->intr_handler));
1185 sdio_claim_host(gInstance->func[0]);
1188 /* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1189 static void IRQHandlerF2(struct sdio_func *func)
1193 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1199 #endif /* !defined(OOB_INTR_ONLY) */
1202 /* Write client card reg */
1204 sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, u32 regaddr,
1205 int regsize, u32 data)
1208 if ((func == 0) || (regsize == 1)) {
1212 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1213 sd_data(("%s: byte write data=0x%02x\n", __func__, data));
1218 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data,
1221 sd_data(("%s: word write data=0x%08x\n", __func__, data));
1226 #endif /* NOTUSED */
1228 int sdioh_start(sdioh_info_t *si, int stage)
1233 int sdioh_stop(sdioh_info_t *si)