From deba741527aa75d03e2d0d1f6010b5bae538a4ac Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Fri, 8 Nov 2013 12:31:48 +0530 Subject: [PATCH] mmc: sdhci: Turn on controller clocks and card power at MMC_POWER_UP Currently, the clock to the card is enabled prior to enabling the power to card. Specification requires that the power be supplied first and then a delay of 10ms and then clock be provided to the card. In this, during MMC_POWER_UP mode, the controller clocks would be ON and the power would be supplied to the card. In the MMC_POWER_ON mode, the clocks to the card would be enabled and the rate set. A callback has been provided to facilitate the enabling of controller clocks. CRs-Fixed: 567658 Change-Id: I2d66eae1581b9b136faaba4cafc330aeb6a3f364 Signed-off-by: Asutosh Das [venkatg@codeaurora.org: Fix sdhci_set_power fn signature as it changed in 3.14 kernel] Signed-off-by: Venkat Gopalakrishnan [subhashj@codeaurora.org: fixed minor merge conflict] Signed-off-by: Subhash Jadavani --- drivers/mmc/host/sdhci.c | 24 +++++++++++++++++++++++- drivers/mmc/host/sdhci.h | 1 + 2 files changed, 24 insertions(+), 1 deletion(-) 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);