summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsutosh Das <asutoshd@codeaurora.org>2013-11-08 12:33:47 +0530
committerSubhash Jadavani <subhashj@codeaurora.org>2016-05-27 10:28:57 -0700
commit21512ff94960e3d9bfdfae860dcbdca698578f95 (patch)
tree1a59e108f0e086535082d9ec9b7a0761444aed93
parentdeba741527aa75d03e2d0d1f6010b5bae538a4ac (diff)
mmc: sdhci-msm: enable controller clocks at MMC_POWER_UP
A callback to turn-on the controller clocks is implemented. This callback would ensure that the pclk and mclk are enabled but the output clock to the card is disabled. CRs-Fixed: 567658 Change-Id: Ic97e600a6388fb64f1267a097b201f31d114a1fb Signed-off-by: Asutosh Das <asutoshd@codeaurora.org> Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
-rw-r--r--drivers/mmc/host/sdhci-msm.c88
1 files changed, 66 insertions, 22 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 2a5f2cc6b758..d4517938cb64 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -301,6 +301,7 @@ struct sdhci_msm_host {
u8 saved_tuning_phase;
bool en_auto_cmd21;
struct device_attribute auto_cmd21_attr;
+ atomic_t controller_clock;
};
enum vdd_io_level {
@@ -2297,6 +2298,50 @@ static unsigned int sdhci_msm_get_sup_clk_rate(struct sdhci_host *host,
return sel_clk;
}
+static int sdhci_msm_enable_controller_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int rc = 0;
+
+ if (atomic_read(&msm_host->controller_clock))
+ return 0;
+
+ sdhci_msm_bus_voting(host, 1);
+
+ if (!IS_ERR(msm_host->pclk)) {
+ rc = clk_prepare_enable(msm_host->pclk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the pclk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto remove_vote;
+ }
+ }
+
+ rc = clk_prepare_enable(msm_host->clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the host-clk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_pclk;
+ }
+
+ atomic_set(&msm_host->controller_clock, 1);
+ pr_debug("%s: %s: enabled controller clock\n",
+ mmc_hostname(host->mmc), __func__);
+ goto out;
+
+disable_pclk:
+ if (!IS_ERR(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+remove_vote:
+ if (msm_host->msm_bus_vote.client_handle)
+ sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
+out:
+ return rc;
+}
+
+
+
static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -2307,36 +2352,32 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
pr_debug("%s: request to enable clocks\n",
mmc_hostname(host->mmc));
- sdhci_msm_bus_voting(host, 1);
+ /*
+ * The bus-width or the clock rate might have changed
+ * after controller clocks are enbaled, update bus vote
+ * in such case.
+ */
+ if (atomic_read(&msm_host->controller_clock))
+ sdhci_msm_bus_voting(host, 1);
+
+ rc = sdhci_msm_enable_controller_clock(host);
+ if (rc)
+ goto remove_vote;
if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
rc = clk_prepare_enable(msm_host->bus_clk);
if (rc) {
pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto remove_vote;
+ goto disable_controller_clk;
}
}
- if (!IS_ERR(msm_host->pclk)) {
- rc = clk_prepare_enable(msm_host->pclk);
- if (rc) {
- pr_err("%s: %s: failed to enable the pclk with error %d\n",
- mmc_hostname(host->mmc), __func__, rc);
- goto disable_bus_clk;
- }
- }
- rc = clk_prepare_enable(msm_host->clk);
- if (rc) {
- pr_err("%s: %s: failed to enable the host-clk with error %d\n",
- mmc_hostname(host->mmc), __func__, rc);
- goto disable_pclk;
- }
if (!IS_ERR(msm_host->ff_clk)) {
rc = clk_prepare_enable(msm_host->ff_clk);
if (rc) {
pr_err("%s: %s: failed to enable the ff_clk with error %d\n",
mmc_hostname(host->mmc), __func__, rc);
- goto disable_clk;
+ goto disable_bus_clk;
}
}
if (!IS_ERR(msm_host->sleep_clk)) {
@@ -2372,6 +2413,7 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
+ atomic_set(&msm_host->controller_clock, 0);
sdhci_msm_bus_voting(host, 0);
}
atomic_set(&msm_host->clks_on, enable);
@@ -2379,15 +2421,15 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
disable_ff_clk:
if (!IS_ERR_OR_NULL(msm_host->ff_clk))
clk_disable_unprepare(msm_host->ff_clk);
-disable_clk:
+disable_bus_clk:
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+ clk_disable_unprepare(msm_host->bus_clk);
+disable_controller_clk:
if (!IS_ERR_OR_NULL(msm_host->clk))
clk_disable_unprepare(msm_host->clk);
-disable_pclk:
if (!IS_ERR_OR_NULL(msm_host->pclk))
clk_disable_unprepare(msm_host->pclk);
-disable_bus_clk:
- if (!IS_ERR_OR_NULL(msm_host->bus_clk))
- clk_disable_unprepare(msm_host->bus_clk);
+ atomic_set(&msm_host->controller_clock, 0);
remove_vote:
if (msm_host->msm_bus_vote.client_handle)
sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
@@ -2656,6 +2698,7 @@ static struct sdhci_ops sdhci_msm_ops = {
.get_max_clock = sdhci_msm_get_max_clock,
.dump_vendor_regs = sdhci_msm_dump_vendor_regs,
.config_auto_tuning_cmd = sdhci_msm_config_auto_tuning_cmd,
+ .enable_controller_clock = sdhci_msm_enable_controller_clock,
};
static int sdhci_msm_probe(struct platform_device *pdev)
@@ -2734,6 +2777,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
if (ret)
goto bus_clk_disable;
}
+ atomic_set(&msm_host->controller_clock, 1);
/* Setup SDC MMC clock */
msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");