diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0394eaf50d86..abde70324954 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1693,6 +1693,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) unsigned long flags; u8 ctrl; struct mmc_host *mmc = host->mmc; + int ret; if (host->flags & SDHCI_DEVICE_DEAD) { if (!IS_ERR(mmc->supply.vmmc) && @@ -1706,6 +1707,25 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) sdhci_enable_preset_value(host, false); + /* + * The controller clocks may be off during power-up and we may end up + * enabling card clock before giving power to the card. Hence, during + * MMC_POWER_UP enable the controller clock and turn-on the regulators. + * The mmc_power_up would provide the necessary delay before turning on + * the clocks to the card. + */ + if (ios->power_mode & MMC_POWER_UP) { + if (host->ops->enable_controller_clock) { + ret = host->ops->enable_controller_clock(host); + if (ret) { + pr_err("%s: enabling controller clock: failed: %d\n", + mmc_hostname(host->mmc), ret); + } else { + sdhci_set_power(host, ios->power_mode, ios->vdd); + } + } + } + spin_lock_irqsave(&host->lock, flags); if (!ios->clock || ios->clock != host->clock) { spin_unlock_irqrestore(&host->lock, flags); @@ -1727,7 +1747,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) } spin_unlock_irqrestore(&host->lock, flags); - if (ios->power_mode & (MMC_POWER_UP | MMC_POWER_ON)) + if (!host->ops->enable_controller_clock && (ios->power_mode & + (MMC_POWER_UP | + MMC_POWER_ON))) sdhci_set_power(host, ios->power_mode, ios->vdd); spin_lock_irqsave(&host->lock, flags); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 1430ca98dd94..f6c1ce0b0475 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -640,6 +640,7 @@ struct sdhci_ops { int (*config_auto_tuning_cmd)(struct sdhci_host *host, bool enable, u32 type); + int (*enable_controller_clock)(struct sdhci_host *host); void (*dump_vendor_regs)(struct sdhci_host *host); void (*toggle_cdr)(struct sdhci_host *host, bool enable); void (*voltage_switch)(struct sdhci_host *host);