diff options
author | Maxime Ripard <maxime.ripard@bootlin.com> | 2018-03-08 15:52:51 +0100 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2018-03-15 14:43:22 +0100 |
commit | 774c010350a16f44705971e8aff457580628c76e (patch) | |
tree | 865a0ad052c7eee1dbf9622ccf00efeb1aa2864f /drivers/mmc/host/sunxi-mmc.c | |
parent | e382ab741252471383e9990583258e3054f66963 (diff) | |
download | linux-774c010350a16f44705971e8aff457580628c76e.tar.bz2 |
mmc: sunxi: Move resources management to separate functions
We've had all our resources management, and especially the clocks and reset
sequence, done directly as part of the probe.
As we want to implement runtime_pm, we'll obviously want to have that
moved outside of the probe so that we can call do it in our runtime suspend
and resume hooks without too much duplication.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/sunxi-mmc.c')
-rw-r--r-- | drivers/mmc/host/sunxi-mmc.c | 142 |
1 files changed, 82 insertions, 60 deletions
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index bad612d6f879..3601746d37a9 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -268,6 +268,7 @@ struct sunxi_mmc_cfg { }; struct sunxi_mmc_host { + struct device *dev; struct mmc_host *mmc; struct reset_control *reset; const struct sunxi_mmc_cfg *cfg; @@ -1165,6 +1166,80 @@ static const struct of_device_id sunxi_mmc_of_match[] = { }; MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); +static int sunxi_mmc_enable(struct sunxi_mmc_host *host) +{ + int ret; + + ret = clk_prepare_enable(host->clk_ahb); + if (ret) { + dev_err(dev, "Couldn't enable the bus clocks (%d)\n", ret); + return ret; + } + + ret = clk_prepare_enable(host->clk_mmc); + if (ret) { + dev_err(host->dev, "Enable mmc clk err %d\n", ret); + goto error_disable_clk_ahb; + } + + ret = clk_prepare_enable(host->clk_output); + if (ret) { + dev_err(host->dev, "Enable output clk err %d\n", ret); + goto error_disable_clk_mmc; + } + + ret = clk_prepare_enable(host->clk_sample); + if (ret) { + dev_err(host->dev, "Enable sample clk err %d\n", ret); + goto error_disable_clk_output; + } + + if (!IS_ERR(host->reset)) { + ret = reset_control_reset(host->reset); + if (ret) { + dev_err(dev, "Couldn't reset the MMC controller (%d)\n", + ret); + goto error_disable_clk_sample; + } + } + + /* + * Sometimes the controller asserts the irq on boot for some reason, + * make sure the controller is in a sane state before enabling irqs. + */ + ret = sunxi_mmc_reset_host(host); + if (ret) + goto error_assert_reset; + + return 0; + +error_assert_reset: + if (!IS_ERR(host->reset)) + reset_control_assert(host->reset); +error_disable_clk_sample: + clk_disable_unprepare(host->clk_sample); +error_disable_clk_output: + clk_disable_unprepare(host->clk_output); +error_disable_clk_mmc: + clk_disable_unprepare(host->clk_mmc); +error_disable_clk_ahb: + clk_disable_unprepare(host->clk_ahb); + return ret; +} + +static void sunxi_mmc_disable(struct sunxi_mmc_host *host) +{ + sunxi_mmc_reset_host(host); + + if (!IS_ERR(host->reset)) + reset_control_assert(host->reset); + + clk_disable_unprepare(host->clk_sample); + clk_disable_unprepare(host->clk_output); + clk_disable_unprepare(host->clk_mmc); + clk_disable_unprepare(host->clk_ahb); +} + static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, struct platform_device *pdev) { @@ -1214,66 +1289,21 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, if (PTR_ERR(host->reset) == -EPROBE_DEFER) return PTR_ERR(host->reset); - ret = clk_prepare_enable(host->clk_ahb); - if (ret) { - dev_err(&pdev->dev, "Enable ahb clk err %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(host->clk_mmc); - if (ret) { - dev_err(&pdev->dev, "Enable mmc clk err %d\n", ret); - goto error_disable_clk_ahb; - } - - ret = clk_prepare_enable(host->clk_output); - if (ret) { - dev_err(&pdev->dev, "Enable output clk err %d\n", ret); - goto error_disable_clk_mmc; - } - - ret = clk_prepare_enable(host->clk_sample); - if (ret) { - dev_err(&pdev->dev, "Enable sample clk err %d\n", ret); - goto error_disable_clk_output; - } - - if (!IS_ERR(host->reset)) { - ret = reset_control_reset(host->reset); - if (ret) { - dev_err(&pdev->dev, "reset err %d\n", ret); - goto error_disable_clk_sample; - } - } - - /* - * Sometimes the controller asserts the irq on boot for some reason, - * make sure the controller is in a sane state before enabling irqs. - */ - ret = sunxi_mmc_reset_host(host); + ret = sunxi_mmc_enable(host); if (ret) - goto error_assert_reset; + return ret; host->irq = platform_get_irq(pdev, 0); if (host->irq <= 0) { ret = -EINVAL; - goto error_assert_reset; + goto error_disable_mmc; } return devm_request_threaded_irq(&pdev->dev, host->irq, sunxi_mmc_irq, sunxi_mmc_handle_manual_stop, 0, "sunxi-mmc", host); -error_assert_reset: - if (!IS_ERR(host->reset)) - reset_control_assert(host->reset); -error_disable_clk_sample: - clk_disable_unprepare(host->clk_sample); -error_disable_clk_output: - clk_disable_unprepare(host->clk_output); -error_disable_clk_mmc: - clk_disable_unprepare(host->clk_mmc); -error_disable_clk_ahb: - clk_disable_unprepare(host->clk_ahb); +error_disable_mmc: + sunxi_mmc_disable(host); return ret; } @@ -1290,6 +1320,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) } host = mmc_priv(mmc); + host->dev = &pdev->dev; host->mmc = mmc; spin_lock_init(&host->lock); @@ -1370,16 +1401,7 @@ static int sunxi_mmc_remove(struct platform_device *pdev) mmc_remove_host(mmc); disable_irq(host->irq); - sunxi_mmc_reset_host(host); - - if (!IS_ERR(host->reset)) - reset_control_assert(host->reset); - - clk_disable_unprepare(host->clk_sample); - clk_disable_unprepare(host->clk_output); - clk_disable_unprepare(host->clk_mmc); - clk_disable_unprepare(host->clk_ahb); - + sunxi_mmc_disable(host); dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); mmc_free_host(mmc); |