Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79edc6ab authored by Sahitya Tummala's avatar Sahitya Tummala Committed by Xiaonian Wang
Browse files

mmc: sdhci-msm: Vote for MSM bus clocks before enabling iface_clk



The current driver just enables "iface_clk" before accessing its
registers but MSM bus clocks are also required for register access
without which any register access would result in chip reset.

The MSM bus clocks can be enabled by setting vote to MSM bus bandwidth
driver. Currently, voting is being done in sdhci_enable/disable but these
functions will not be invoked by MMC core layer for some cases such
as mmc_power_up/mmc_power_off, which require peripheral register
access.

To resolve the above mentioned problem, bus voting and de-voting will
now be done as part of clock management within the sdhci MSM driver
i.e., before enabling SDHC clocks and after disabling SDHC clocks.

Change-Id: Iff608fba4c58bf37a6f4ce8eb36876c79969feaf
Signed-off-by: default avatarSahitya Tummala <stummala@codeaurora.org>
[xiaonian@codeaurora.org: fix trivial merge conflict]
Signed-off-by: default avatarXiaonian Wang <xiaonian@codeaurora.org>
parent ea4e3aa3
Loading
Loading
Loading
Loading
+44 −17
Original line number Original line Diff line number Diff line
@@ -1150,11 +1150,23 @@ static void sdhci_msm_bus_voting(struct sdhci_host *host, u32 enable)
		return;
		return;


	bw = sdhci_get_bw_required(host, ios);
	bw = sdhci_get_bw_required(host, ios);
	if (enable)
	if (enable) {
		sdhci_msm_bus_cancel_work_and_set_vote(host, bw);
		sdhci_msm_bus_cancel_work_and_set_vote(host, bw);
	} else {
		/*
		 * If clock gating is enabled, then remove the vote
		 * immediately because clocks will be disabled only
		 * after SDHCI_MSM_MMC_CLK_GATE_DELAY and thus no
		 * additional delay is required to remove the bus vote.
		 */
#ifdef CONFIG_MMC_CLKGATE
		if (host->mmc->clkgate_delay)
			sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
		else
		else
#endif
			sdhci_msm_bus_queue_work(host);
			sdhci_msm_bus_queue_work(host);
	}
	}
}


/* Regulator utility functions */
/* Regulator utility functions */
static int sdhci_msm_vreg_init_reg(struct device *dev,
static int sdhci_msm_vreg_init_reg(struct device *dev,
@@ -1664,12 +1676,15 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
	if (enable && !atomic_read(&msm_host->clks_on)) {
	if (enable && !atomic_read(&msm_host->clks_on)) {
		pr_debug("%s: request to enable clocks\n",
		pr_debug("%s: request to enable clocks\n",
				mmc_hostname(host->mmc));
				mmc_hostname(host->mmc));

		sdhci_msm_bus_voting(host, 1);

		if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
		if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
			rc = clk_prepare_enable(msm_host->bus_clk);
			rc = clk_prepare_enable(msm_host->bus_clk);
			if (rc) {
			if (rc) {
				pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
				pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
					mmc_hostname(host->mmc), __func__, rc);
					mmc_hostname(host->mmc), __func__, rc);
				goto out;
				goto remove_vote;
			}
			}
		}
		}
		if (!IS_ERR(msm_host->pclk)) {
		if (!IS_ERR(msm_host->pclk)) {
@@ -1698,6 +1713,8 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
			clk_disable_unprepare(msm_host->pclk);
			clk_disable_unprepare(msm_host->pclk);
		if (!IS_ERR_OR_NULL(msm_host->bus_clk))
		if (!IS_ERR_OR_NULL(msm_host->bus_clk))
			clk_disable_unprepare(msm_host->bus_clk);
			clk_disable_unprepare(msm_host->bus_clk);

		sdhci_msm_bus_voting(host, 0);
	}
	}
	atomic_set(&msm_host->clks_on, enable);
	atomic_set(&msm_host->clks_on, enable);
	goto out;
	goto out;
@@ -1707,6 +1724,9 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable)
disable_bus_clk:
disable_bus_clk:
	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
	if (!IS_ERR_OR_NULL(msm_host->bus_clk))
		clk_disable_unprepare(msm_host->bus_clk);
		clk_disable_unprepare(msm_host->bus_clk);
remove_vote:
	if (msm_host->msm_bus_vote.client_handle)
		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
out:
out:
	return rc;
	return rc;
}
}
@@ -1753,6 +1773,11 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
		}
		}
		msm_host->clk_rate = sup_clock;
		msm_host->clk_rate = sup_clock;
		host->clock = clock;
		host->clock = clock;
		/*
		 * Update the bus vote in case of frequency change due to
		 * clock scaling.
		 */
		sdhci_msm_bus_voting(host, 1);
	}
	}
out:
out:
	sdhci_set_clock(host, clock);
	sdhci_set_clock(host, clock);
@@ -1800,7 +1825,6 @@ static struct sdhci_ops sdhci_msm_ops = {
	.toggle_cdr = sdhci_msm_toggle_cdr,
	.toggle_cdr = sdhci_msm_toggle_cdr,
	.get_max_segments = sdhci_msm_max_segs,
	.get_max_segments = sdhci_msm_max_segs,
	.set_clock = sdhci_msm_set_clock,
	.set_clock = sdhci_msm_set_clock,
	.platform_bus_voting = sdhci_msm_bus_voting,
	.get_min_clock = sdhci_msm_get_min_clock,
	.get_min_clock = sdhci_msm_get_min_clock,
	.get_max_clock = sdhci_msm_get_max_clock,
	.get_max_clock = sdhci_msm_get_max_clock,
};
};
@@ -1902,11 +1926,20 @@ static int sdhci_msm_probe(struct platform_device *pdev)
	msm_host->clk_rate = sdhci_msm_get_min_clock(host);
	msm_host->clk_rate = sdhci_msm_get_min_clock(host);
	atomic_set(&msm_host->clks_on, 1);
	atomic_set(&msm_host->clks_on, 1);


	ret = sdhci_msm_bus_register(msm_host, pdev);
	if (ret)
		goto clk_disable;

	if (msm_host->msm_bus_vote.client_handle)
		INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
				  sdhci_msm_bus_work);
	sdhci_msm_bus_voting(host, 1);

	/* Setup regulators */
	/* Setup regulators */
	ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
	ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
	if (ret) {
	if (ret) {
		dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
		dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
		goto clk_disable;
		goto bus_unregister;
	}
	}


	/* Reset the core and Enable SDHC mode */
	/* Reset the core and Enable SDHC mode */
@@ -2030,14 +2063,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)


	host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us;
	host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us;


	ret = sdhci_msm_bus_register(msm_host, pdev);
	if (ret)
		goto vreg_deinit;

	if (msm_host->msm_bus_vote.client_handle)
		INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work,
				  sdhci_msm_bus_work);

	init_completion(&msm_host->pwr_irq_completion);
	init_completion(&msm_host->pwr_irq_completion);


	if (gpio_is_valid(msm_host->pdata->status_gpio)) {
	if (gpio_is_valid(msm_host->pdata->status_gpio)) {
@@ -2046,7 +2071,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
		if (ret) {
		if (ret) {
			dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
			dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n",
					__func__, ret);
					__func__, ret);
			goto bus_unregister;
			goto vreg_deinit;
		}
		}
	}
	}


@@ -2079,10 +2104,12 @@ static int sdhci_msm_probe(struct platform_device *pdev)
remove_host:
remove_host:
	dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
	dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
	sdhci_remove_host(host, dead);
	sdhci_remove_host(host, dead);
bus_unregister:
	sdhci_msm_bus_unregister(msm_host);
vreg_deinit:
vreg_deinit:
	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
	sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
bus_unregister:
	if (msm_host->msm_bus_vote.client_handle)
		sdhci_msm_bus_cancel_work_and_set_vote(host, 0);
	sdhci_msm_bus_unregister(msm_host);
clk_disable:
clk_disable:
	if (!IS_ERR(msm_host->clk))
	if (!IS_ERR(msm_host->clk))
		clk_disable_unprepare(msm_host->clk);
		clk_disable_unprepare(msm_host->clk);