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