diff options
Diffstat (limited to 'drivers/mmc/core/sdio.c')
| -rw-r--r-- | drivers/mmc/core/sdio.c | 135 |
1 files changed, 114 insertions, 21 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 47d1708810b..b0b6ce93e51 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
| @@ -160,9 +160,7 @@ static int sdio_enable_wide(struct mmc_card *card) | |||
| 160 | if (ret) | 160 | if (ret) |
| 161 | return ret; | 161 | return ret; |
| 162 | 162 | ||
| 163 | mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); | 163 | return 1; |
| 164 | |||
| 165 | return 0; | ||
| 166 | } | 164 | } |
| 167 | 165 | ||
| 168 | /* | 166 | /* |
| @@ -222,10 +220,34 @@ static int sdio_disable_wide(struct mmc_card *card) | |||
| 222 | return 0; | 220 | return 0; |
| 223 | } | 221 | } |
| 224 | 222 | ||
| 223 | |||
| 224 | static int sdio_enable_4bit_bus(struct mmc_card *card) | ||
| 225 | { | ||
| 226 | int err; | ||
| 227 | |||
| 228 | if (card->type == MMC_TYPE_SDIO) | ||
| 229 | return sdio_enable_wide(card); | ||
| 230 | |||
| 231 | if ((card->host->caps & MMC_CAP_4_BIT_DATA) && | ||
| 232 | (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { | ||
| 233 | err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); | ||
| 234 | if (err) | ||
| 235 | return err; | ||
| 236 | } else | ||
| 237 | return 0; | ||
| 238 | |||
| 239 | err = sdio_enable_wide(card); | ||
| 240 | if (err <= 0) | ||
| 241 | mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); | ||
| 242 | |||
| 243 | return err; | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 225 | /* | 247 | /* |
| 226 | * Test if the card supports high-speed mode and, if so, switch to it. | 248 | * Test if the card supports high-speed mode and, if so, switch to it. |
| 227 | */ | 249 | */ |
| 228 | static int sdio_enable_hs(struct mmc_card *card) | 250 | static int mmc_sdio_switch_hs(struct mmc_card *card, int enable) |
| 229 | { | 251 | { |
| 230 | int ret; | 252 | int ret; |
| 231 | u8 speed; | 253 | u8 speed; |
| @@ -240,7 +262,10 @@ static int sdio_enable_hs(struct mmc_card *card) | |||
| 240 | if (ret) | 262 | if (ret) |
| 241 | return ret; | 263 | return ret; |
| 242 | 264 | ||
| 243 | speed |= SDIO_SPEED_EHS; | 265 | if (enable) |
| 266 | speed |= SDIO_SPEED_EHS; | ||
| 267 | else | ||
| 268 | speed &= ~SDIO_SPEED_EHS; | ||
| 244 | 269 | ||
| 245 | ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); | 270 | ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); |
| 246 | if (ret) | 271 | if (ret) |
| @@ -249,6 +274,24 @@ static int sdio_enable_hs(struct mmc_card *card) | |||
| 249 | return 1; | 274 | return 1; |
| 250 | } | 275 | } |
| 251 | 276 | ||
| 277 | /* | ||
| 278 | * Enable SDIO/combo card's high-speed mode. Return 0/1 if [not]supported. | ||
| 279 | */ | ||
| 280 | static int sdio_enable_hs(struct mmc_card *card) | ||
| 281 | { | ||
| 282 | int ret; | ||
| 283 | |||
| 284 | ret = mmc_sdio_switch_hs(card, true); | ||
| 285 | if (ret <= 0 || card->type == MMC_TYPE_SDIO) | ||
| 286 | return ret; | ||
| 287 | |||
| 288 | ret = mmc_sd_switch_hs(card); | ||
| 289 | if (ret <= 0) | ||
| 290 | mmc_sdio_switch_hs(card, false); | ||
| 291 | |||
| 292 | return ret; | ||
| 293 | } | ||
| 294 | |||
| 252 | static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) | 295 | static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) |
| 253 | { | 296 | { |
| 254 | unsigned max_dtr; | 297 | unsigned max_dtr; |
| @@ -265,6 +308,9 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) | |||
| 265 | max_dtr = card->cis.max_dtr; | 308 | max_dtr = card->cis.max_dtr; |
| 266 | } | 309 | } |
| 267 | 310 | ||
| 311 | if (card->type == MMC_TYPE_SD_COMBO) | ||
| 312 | max_dtr = min(max_dtr, mmc_sd_get_max_clock(card)); | ||
| 313 | |||
| 268 | return max_dtr; | 314 | return max_dtr; |
| 269 | } | 315 | } |
| 270 | 316 | ||
| @@ -310,7 +356,24 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
| 310 | goto err; | 356 | goto err; |
| 311 | } | 357 | } |
| 312 | 358 | ||
| 313 | card->type = MMC_TYPE_SDIO; | 359 | err = mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid); |
| 360 | |||
| 361 | if (!err) { | ||
| 362 | card->type = MMC_TYPE_SD_COMBO; | ||
| 363 | |||
| 364 | if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || | ||
| 365 | memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) { | ||
| 366 | mmc_remove_card(card); | ||
| 367 | return -ENOENT; | ||
| 368 | } | ||
| 369 | } else { | ||
| 370 | card->type = MMC_TYPE_SDIO; | ||
| 371 | |||
| 372 | if (oldcard && oldcard->type != MMC_TYPE_SDIO) { | ||
| 373 | mmc_remove_card(card); | ||
| 374 | return -ENOENT; | ||
| 375 | } | ||
| 376 | } | ||
| 314 | 377 | ||
| 315 | /* | 378 | /* |
| 316 | * Call the optional HC's init_card function to handle quirks. | 379 | * Call the optional HC's init_card function to handle quirks. |
| @@ -330,6 +393,17 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
| 330 | } | 393 | } |
| 331 | 394 | ||
| 332 | /* | 395 | /* |
| 396 | * Read CSD, before selecting the card | ||
| 397 | */ | ||
| 398 | if (!oldcard && card->type == MMC_TYPE_SD_COMBO) { | ||
| 399 | err = mmc_sd_get_csd(host, card); | ||
| 400 | if (err) | ||
| 401 | return err; | ||
| 402 | |||
| 403 | mmc_decode_cid(card); | ||
| 404 | } | ||
| 405 | |||
| 406 | /* | ||
| 333 | * Select card, as all following commands rely on that. | 407 | * Select card, as all following commands rely on that. |
| 334 | */ | 408 | */ |
| 335 | if (!powered_resume && !mmc_host_is_spi(host)) { | 409 | if (!powered_resume && !mmc_host_is_spi(host)) { |
| @@ -356,14 +430,33 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
| 356 | int same = (card->cis.vendor == oldcard->cis.vendor && | 430 | int same = (card->cis.vendor == oldcard->cis.vendor && |
| 357 | card->cis.device == oldcard->cis.device); | 431 | card->cis.device == oldcard->cis.device); |
| 358 | mmc_remove_card(card); | 432 | mmc_remove_card(card); |
| 359 | if (!same) { | 433 | if (!same) |
| 360 | err = -ENOENT; | 434 | return -ENOENT; |
| 361 | goto err; | 435 | |
| 362 | } | ||
| 363 | card = oldcard; | 436 | card = oldcard; |
| 364 | return 0; | 437 | return 0; |
| 365 | } | 438 | } |
| 366 | 439 | ||
| 440 | if (card->type == MMC_TYPE_SD_COMBO) { | ||
| 441 | err = mmc_sd_setup_card(host, card, oldcard != NULL); | ||
| 442 | /* handle as SDIO-only card if memory init failed */ | ||
| 443 | if (err) { | ||
| 444 | mmc_go_idle(host); | ||
| 445 | if (mmc_host_is_spi(host)) | ||
| 446 | /* should not fail, as it worked previously */ | ||
| 447 | mmc_spi_set_crc(host, use_spi_crc); | ||
| 448 | card->type = MMC_TYPE_SDIO; | ||
| 449 | } else | ||
| 450 | card->dev.type = &sd_type; | ||
| 451 | } | ||
| 452 | |||
| 453 | /* | ||
| 454 | * If needed, disconnect card detection pull-up resistor. | ||
| 455 | */ | ||
| 456 | err = sdio_disable_cd(card); | ||
| 457 | if (err) | ||
| 458 | goto remove; | ||
| 459 | |||
| 367 | /* | 460 | /* |
| 368 | * Switch to high-speed (if supported). | 461 | * Switch to high-speed (if supported). |
| 369 | */ | 462 | */ |
| @@ -381,8 +474,10 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
| 381 | /* | 474 | /* |
| 382 | * Switch to wider bus (if supported). | 475 | * Switch to wider bus (if supported). |
| 383 | */ | 476 | */ |
| 384 | err = sdio_enable_wide(card); | 477 | err = sdio_enable_4bit_bus(card); |
| 385 | if (err) | 478 | if (err > 0) |
| 479 | mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); | ||
| 480 | else if (err) | ||
| 386 | goto remove; | 481 | goto remove; |
| 387 | 482 | ||
| 388 | if (!oldcard) | 483 | if (!oldcard) |
| @@ -496,9 +591,14 @@ static int mmc_sdio_resume(struct mmc_host *host) | |||
| 496 | mmc_claim_host(host); | 591 | mmc_claim_host(host); |
| 497 | err = mmc_sdio_init_card(host, host->ocr, host->card, | 592 | err = mmc_sdio_init_card(host, host->ocr, host->card, |
| 498 | (host->pm_flags & MMC_PM_KEEP_POWER)); | 593 | (host->pm_flags & MMC_PM_KEEP_POWER)); |
| 499 | if (!err) | 594 | if (!err) { |
| 500 | /* We may have switched to 1-bit mode during suspend. */ | 595 | /* We may have switched to 1-bit mode during suspend. */ |
| 501 | err = sdio_enable_wide(host->card); | 596 | err = sdio_enable_4bit_bus(host->card); |
| 597 | if (err > 0) { | ||
| 598 | mmc_set_bus_width(host, MMC_BUS_WIDTH_4); | ||
| 599 | err = 0; | ||
| 600 | } | ||
| 601 | } | ||
| 502 | if (!err && host->sdio_irqs) | 602 | if (!err && host->sdio_irqs) |
| 503 | mmc_signal_sdio_irq(host); | 603 | mmc_signal_sdio_irq(host); |
| 504 | mmc_release_host(host); | 604 | mmc_release_host(host); |
| @@ -583,13 +683,6 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | |||
| 583 | card->sdio_funcs = 0; | 683 | card->sdio_funcs = 0; |
| 584 | 684 | ||
| 585 | /* | 685 | /* |
| 586 | * If needed, disconnect card detection pull-up resistor. | ||
| 587 | */ | ||
| 588 | err = sdio_disable_cd(card); | ||
| 589 | if (err) | ||
| 590 | goto remove; | ||
| 591 | |||
| 592 | /* | ||
| 593 | * Initialize (but don't add) all present functions. | 686 | * Initialize (but don't add) all present functions. |
| 594 | */ | 687 | */ |
| 595 | for (i = 0; i < funcs; i++, card->sdio_funcs++) { | 688 | for (i = 0; i < funcs; i++, card->sdio_funcs++) { |
