Skip to content

Commit

Permalink
mmc: sdhci-xenon: add runtime pm support and reimplement standby
Browse files Browse the repository at this point in the history
Enable runtime pm support for xenon controller, which uses 50ms
auto runtime suspend by default.
Reimplement system standby based on runtime pm API.
Introduce restore_needed to restore the Xenon specific registers
when resume.

Signed-off-by: Zhoujie Wu <zjwu@marvell.com>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
  • Loading branch information
Zhoujie Wu authored and Ulf Hansson committed Aug 30, 2017
1 parent 689dc7e commit a027b2c
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 16 deletions.
87 changes: 71 additions & 16 deletions drivers/mmc/host/sdhci-xenon.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>

#include "sdhci-pltfm.h"
#include "sdhci-xenon.h"
Expand Down Expand Up @@ -506,13 +508,24 @@ static int xenon_probe(struct platform_device *pdev)
if (err)
goto err_clk;

pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1);

err = sdhci_add_host(host);
if (err)
goto remove_sdhc;

pm_runtime_put_autosuspend(&pdev->dev);

return 0;

remove_sdhc:
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
xenon_sdhc_unprepare(host);
err_clk:
clk_disable_unprepare(pltfm_host->clk);
Expand All @@ -526,6 +539,10 @@ static int xenon_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);

pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);

sdhci_remove_host(host, 0);

xenon_sdhc_unprepare(host);
Expand All @@ -542,40 +559,78 @@ static int xenon_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;

ret = sdhci_suspend_host(host);
if (ret)
return ret;
ret = pm_runtime_force_suspend(dev);

clk_disable_unprepare(pltfm_host->clk);
priv->restore_needed = true;
return ret;
}
#endif

static int xenon_resume(struct device *dev)
#ifdef CONFIG_PM
static int xenon_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;

ret = clk_prepare_enable(pltfm_host->clk);
ret = sdhci_runtime_suspend_host(host);
if (ret)
return ret;

if (host->tuning_mode != SDHCI_TUNING_MODE_3)
mmc_retune_needed(host->mmc);

clk_disable_unprepare(pltfm_host->clk);
/*
* If SoCs power off the entire Xenon, registers setting will
* be lost.
* Re-configure Xenon specific register to enable current SDHC
* Need to update the priv->clock here, or when runtime resume
* back, phy don't aware the clock change and won't adjust phy
* which will cause cmd err
*/
ret = xenon_sdhc_prepare(host);
if (ret)
priv->clock = 0;
return 0;
}

static int xenon_runtime_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret;

ret = clk_prepare_enable(pltfm_host->clk);
if (ret) {
dev_err(dev, "can't enable mainck\n");
return ret;
}

return sdhci_resume_host(host);
}
#endif
if (priv->restore_needed) {
ret = xenon_sdhc_prepare(host);
if (ret)
goto out;
priv->restore_needed = false;
}

static SIMPLE_DEV_PM_OPS(xenon_pmops, xenon_suspend, xenon_resume);
ret = sdhci_runtime_resume_host(host);
if (ret)
goto out;
return 0;
out:
clk_disable_unprepare(pltfm_host->clk);
return ret;
}
#endif /* CONFIG_PM */

static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(xenon_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(xenon_runtime_suspend,
xenon_runtime_resume,
NULL)
};

static const struct of_device_id sdhci_xenon_dt_ids[] = {
{ .compatible = "marvell,armada-ap806-sdhci",},
Expand All @@ -589,7 +644,7 @@ static struct platform_driver sdhci_xenon_driver = {
.driver = {
.name = "xenon-sdhci",
.of_match_table = sdhci_xenon_dt_ids,
.pm = &xenon_pmops,
.pm = &sdhci_xenon_dev_pm_ops,
},
.probe = xenon_probe,
.remove = xenon_remove,
Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/host/sdhci-xenon.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ struct xenon_priv {
*/
void *phy_params;
struct xenon_emmc_phy_regs *emmc_phy_regs;
bool restore_needed;
};

int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
Expand Down

0 comments on commit a027b2c

Please sign in to comment.