diff options
Diffstat (limited to 'drivers/mmc/core/sdio.c')
| -rw-r--r-- | drivers/mmc/core/sdio.c | 217 |
1 files changed, 115 insertions, 102 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2273ce6b6c1..e636d9e99e4 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -157,10 +157,7 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr) if (ret) goto out; - if (card->host->caps & - (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | - MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | - MMC_CAP_UHS_DDR50)) { + if (mmc_host_uhs(card->host)) { if (data & SDIO_UHS_DDR50) card->sw_caps.sd3_bus_mode |= SD_MODE_UHS_DDR50; @@ -366,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) { unsigned max_dtr; - if (mmc_card_highspeed(card)) { + if (mmc_card_hs(card)) { /* * The SDIO specification doesn't mention how * the CIS transfer speed register relates to @@ -478,8 +475,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) * If the host doesn't support any of the UHS-I modes, fallback on * default speed. */ - if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | - MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) + if (!mmc_host_uhs(card->host)) return 0; bus_speed = SDIO_SPEED_SDR12; @@ -489,23 +485,27 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) bus_speed = SDIO_SPEED_SDR104; timing = MMC_TIMING_UHS_SDR104; card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; + card->sd_bus_speed = UHS_SDR104_BUS_SPEED; } else if ((card->host->caps & MMC_CAP_UHS_DDR50) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { bus_speed = SDIO_SPEED_DDR50; timing = MMC_TIMING_UHS_DDR50; card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; + card->sd_bus_speed = UHS_DDR50_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50)) { bus_speed = SDIO_SPEED_SDR50; timing = MMC_TIMING_UHS_SDR50; card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; + card->sd_bus_speed = UHS_SDR50_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { bus_speed = SDIO_SPEED_SDR25; timing = MMC_TIMING_UHS_SDR25; card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; + card->sd_bus_speed = UHS_SDR25_BUS_SPEED; } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & @@ -513,6 +513,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) bus_speed = SDIO_SPEED_SDR12; timing = MMC_TIMING_UHS_SDR12; card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; + card->sd_bus_speed = UHS_SDR12_BUS_SPEED; } err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); @@ -562,10 +563,18 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) if (err) goto out; - /* Initialize and start re-tuning timer */ - if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) + /* + * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and + * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. + */ + if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning && + ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) || + (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) { + mmc_host_clk_hold(card->host); err = card->host->ops->execute_tuning(card->host, MMC_SEND_TUNING_BLOCK); + mmc_host_clk_release(card->host); + } out: @@ -583,15 +592,29 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, { struct mmc_card *card; int err; + int retries = 10; + u32 rocr = 0; + u32 ocr_card = ocr; BUG_ON(!host); WARN_ON(!host->claimed); + /* to query card if 1.8V signalling is supported */ + if (mmc_host_uhs(host)) + ocr |= R4_18V_PRESENT; + +try_again: + if (!retries) { + pr_warning("%s: Skipping voltage switch\n", + mmc_hostname(host)); + ocr &= ~R4_18V_PRESENT; + } + /* * Inform the card of the voltage */ if (!powered_resume) { - err = mmc_send_io_op_cond(host, host->ocr, &ocr); + err = mmc_send_io_op_cond(host, ocr, &rocr); if (err) goto err; } @@ -614,8 +637,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, goto err; } - if ((ocr & R4_MEMORY_PRESENT) && - mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) { + if ((rocr & R4_MEMORY_PRESENT) && + mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) { card->type = MMC_TYPE_SD_COMBO; if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || @@ -645,21 +668,22 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, * systems that claim 1.8v signalling in fact do not support * it. */ - if ((ocr & R4_18V_PRESENT) && - (host->caps & - (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | - MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | - MMC_CAP_UHS_DDR50))) { + if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - true); - if (err) { + ocr); + if (err == -EAGAIN) { + sdio_reset(host); + mmc_go_idle(host); + mmc_send_if_cond(host, host->ocr_avail); + mmc_remove_card(card); + retries--; + goto try_again; + } else if (err) { ocr &= ~R4_18V_PRESENT; - host->ocr &= ~R4_18V_PRESENT; } err = 0; } else { ocr &= ~R4_18V_PRESENT; - host->ocr &= ~R4_18V_PRESENT; } /* @@ -709,7 +733,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, mmc_set_clock(host, card->cis.max_dtr); if (card->cccr.high_speed) { - mmc_card_set_highspeed(card); mmc_set_timing(card->host, MMC_TIMING_SD_HS); } @@ -739,6 +762,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, card = oldcard; } + card->ocr = ocr_card; mmc_fixup_device(card, NULL); if (card->type == MMC_TYPE_SD_COMBO) { @@ -767,16 +791,13 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, err = mmc_sdio_init_uhs_card(card); if (err) goto remove; - - /* Card is an ultra-high-speed card */ - mmc_card_set_uhs(card); } else { /* * Switch to high-speed (if supported). */ err = sdio_enable_hs(card); if (err > 0) - mmc_sd_go_highspeed(card); + mmc_set_timing(card->host, MMC_TIMING_SD_HS); else if (err) goto remove; @@ -849,8 +870,10 @@ static void mmc_sdio_detect(struct mmc_host *host) /* Make sure card is powered before detecting it */ if (host->caps & MMC_CAP_POWER_OFF_CARD) { err = pm_runtime_get_sync(&host->card->dev); - if (err < 0) + if (err < 0) { + pm_runtime_put_noidle(&host->card->dev); goto out; + } } mmc_claim_host(host); @@ -888,11 +911,11 @@ out: } /* - * SDIO suspend. We need to suspend all functions separately. + * SDIO pre_suspend. We need to suspend all functions separately. * Therefore all registered functions must have drivers with suspend * and resume methods. Failing that we simply remove the whole card. */ -static int mmc_sdio_suspend(struct mmc_host *host) +static int mmc_sdio_pre_suspend(struct mmc_host *host) { int i, err = 0; @@ -903,32 +926,34 @@ static int mmc_sdio_suspend(struct mmc_host *host) if (!pmops || !pmops->suspend || !pmops->resume) { /* force removal of entire card in that case */ err = -ENOSYS; - } else - err = pmops->suspend(&func->dev); - if (err) break; - } - } - while (err && --i >= 0) { - struct sdio_func *func = host->card->sdio_func[i]; - if (func && sdio_func_present(func) && func->dev.driver) { - const struct dev_pm_ops *pmops = func->dev.driver->pm; - pmops->resume(&func->dev); + } } } - if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { + return err; +} + +/* + * SDIO suspend. Suspend all functions separately. + */ +static int mmc_sdio_suspend(struct mmc_host *host) +{ + if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { mmc_claim_host(host); sdio_disable_wide(host->card); mmc_release_host(host); } - return err; + if (!mmc_card_keep_power(host)) + mmc_power_off(host); + + return 0; } static int mmc_sdio_resume(struct mmc_host *host) { - int i, err = 0; + int err = 0; BUG_ON(!host); BUG_ON(!host->card); @@ -936,11 +961,29 @@ static int mmc_sdio_resume(struct mmc_host *host) /* Basic card reinitialization. */ mmc_claim_host(host); + /* Restore power if needed */ + if (!mmc_card_keep_power(host)) { + mmc_power_up(host, host->card->ocr); + /* + * Tell runtime PM core we just powered up the card, + * since it still believes the card is powered off. + * Note that currently runtime PM is only enabled + * for SDIO cards that are MMC_CAP_POWER_OFF_CARD + */ + if (host->caps & MMC_CAP_POWER_OFF_CARD) { + pm_runtime_disable(&host->card->dev); + pm_runtime_set_active(&host->card->dev); + pm_runtime_enable(&host->card->dev); + } + } + /* No need to reinitialize powered-resumed nonremovable cards */ - if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) - err = mmc_sdio_init_card(host, host->ocr, host->card, + if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { + sdio_reset(host); + mmc_go_idle(host); + err = mmc_sdio_init_card(host, host->card->ocr, host->card, mmc_card_keep_power(host)); - else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { + } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); if (err > 0) { @@ -953,31 +996,13 @@ static int mmc_sdio_resume(struct mmc_host *host) wake_up_process(host->sdio_irq_thread); mmc_release_host(host); - /* - * If the card looked to be the same as before suspending, then - * we proceed to resume all card functions. If one of them returns - * an error then we simply return that error to the core and the - * card will be redetected as new. It is the responsibility of - * the function driver to perform further tests with the extra - * knowledge it has of the card to confirm the card is indeed the - * same as before suspending (same MAC address for network cards, - * etc.) and return an error otherwise. - */ - for (i = 0; !err && i < host->card->sdio_funcs; i++) { - struct sdio_func *func = host->card->sdio_func[i]; - if (func && sdio_func_present(func) && func->dev.driver) { - const struct dev_pm_ops *pmops = func->dev.driver->pm; - err = pmops->resume(&func->dev); - } - } - + host->pm_flags &= ~MMC_PM_KEEP_POWER; return err; } static int mmc_sdio_power_restore(struct mmc_host *host) { int ret; - u32 ocr; BUG_ON(!host); BUG_ON(!host->card); @@ -999,28 +1024,17 @@ static int mmc_sdio_power_restore(struct mmc_host *host) * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and * harmless in other situations. * - * With these steps taken, mmc_select_voltage() is also required to - * restore the correct voltage setting of the card. */ sdio_reset(host); mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); - ret = mmc_send_io_op_cond(host, 0, &ocr); + ret = mmc_send_io_op_cond(host, 0, NULL); if (ret) goto out; - if (host->ocr_avail_sdio) - host->ocr_avail = host->ocr_avail_sdio; - - host->ocr = mmc_select_voltage(host, ocr & ~0x7F); - if (!host->ocr) { - ret = -EINVAL; - goto out; - } - - ret = mmc_sdio_init_card(host, host->ocr, host->card, + ret = mmc_sdio_init_card(host, host->card->ocr, host->card, mmc_card_keep_power(host)); if (!ret && host->sdio_irqs) mmc_signal_sdio_irq(host); @@ -1031,11 +1045,28 @@ out: return ret; } +static int mmc_sdio_runtime_suspend(struct mmc_host *host) +{ + /* No references to the card, cut the power to it. */ + mmc_power_off(host); + return 0; +} + +static int mmc_sdio_runtime_resume(struct mmc_host *host) +{ + /* Restore power and re-initialize. */ + mmc_power_up(host, host->card->ocr); + return mmc_sdio_power_restore(host); +} + static const struct mmc_bus_ops mmc_sdio_ops = { .remove = mmc_sdio_remove, .detect = mmc_sdio_detect, + .pre_suspend = mmc_sdio_pre_suspend, .suspend = mmc_sdio_suspend, .resume = mmc_sdio_resume, + .runtime_suspend = mmc_sdio_runtime_suspend, + .runtime_resume = mmc_sdio_runtime_resume, .power_restore = mmc_sdio_power_restore, .alive = mmc_sdio_alive, }; @@ -1047,7 +1078,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { int mmc_attach_sdio(struct mmc_host *host) { int err, i, funcs; - u32 ocr; + u32 ocr, rocr; struct mmc_card *card; BUG_ON(!host); @@ -1061,23 +1092,13 @@ int mmc_attach_sdio(struct mmc_host *host) if (host->ocr_avail_sdio) host->ocr_avail = host->ocr_avail_sdio; - /* - * Sanity check the voltages that the card claims to - * support. - */ - if (ocr & 0x7F) { - pr_warning("%s: card claims to support voltages " - "below the defined range. These will be ignored.\n", - mmc_hostname(host)); - ocr &= ~0x7F; - } - host->ocr = mmc_select_voltage(host, ocr); + rocr = mmc_select_voltage(host, ocr); /* * Can we support the voltage(s) of the card(s)? */ - if (!host->ocr) { + if (!rocr) { err = -EINVAL; goto err; } @@ -1085,18 +1106,10 @@ int mmc_attach_sdio(struct mmc_host *host) /* * Detect and init the card. */ - err = mmc_sdio_init_card(host, host->ocr, NULL, 0); - if (err) { - if (err == -EAGAIN) { - /* - * Retry initialization with S18R set to 0. - */ - host->ocr &= ~R4_18V_PRESENT; - err = mmc_sdio_init_card(host, host->ocr, NULL, 0); - } - if (err) - goto err; - } + err = mmc_sdio_init_card(host, rocr, NULL, 0); + if (err) + goto err; + card = host->card; /* |
