Skip to content

Commit a027b2c

Browse files
Zhoujie Wustorulf
authored andcommitted
mmc: sdhci-xenon: add runtime pm support and reimplement standby
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 <[email protected]> Acked-by: Adrian Hunter <[email protected]> Signed-off-by: Ulf Hansson <[email protected]>
1 parent 689dc7e commit a027b2c

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

drivers/mmc/host/sdhci-xenon.c

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <linux/ktime.h>
1919
#include <linux/module.h>
2020
#include <linux/of.h>
21+
#include <linux/pm.h>
22+
#include <linux/pm_runtime.h>
2123

2224
#include "sdhci-pltfm.h"
2325
#include "sdhci-xenon.h"
@@ -506,13 +508,24 @@ static int xenon_probe(struct platform_device *pdev)
506508
if (err)
507509
goto err_clk;
508510

511+
pm_runtime_get_noresume(&pdev->dev);
512+
pm_runtime_set_active(&pdev->dev);
513+
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
514+
pm_runtime_use_autosuspend(&pdev->dev);
515+
pm_runtime_enable(&pdev->dev);
516+
pm_suspend_ignore_children(&pdev->dev, 1);
517+
509518
err = sdhci_add_host(host);
510519
if (err)
511520
goto remove_sdhc;
512521

522+
pm_runtime_put_autosuspend(&pdev->dev);
523+
513524
return 0;
514525

515526
remove_sdhc:
527+
pm_runtime_disable(&pdev->dev);
528+
pm_runtime_put_noidle(&pdev->dev);
516529
xenon_sdhc_unprepare(host);
517530
err_clk:
518531
clk_disable_unprepare(pltfm_host->clk);
@@ -526,6 +539,10 @@ static int xenon_remove(struct platform_device *pdev)
526539
struct sdhci_host *host = platform_get_drvdata(pdev);
527540
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
528541

542+
pm_runtime_get_sync(&pdev->dev);
543+
pm_runtime_disable(&pdev->dev);
544+
pm_runtime_put_noidle(&pdev->dev);
545+
529546
sdhci_remove_host(host, 0);
530547

531548
xenon_sdhc_unprepare(host);
@@ -542,40 +559,78 @@ static int xenon_suspend(struct device *dev)
542559
{
543560
struct sdhci_host *host = dev_get_drvdata(dev);
544561
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
562+
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
545563
int ret;
546564

547-
ret = sdhci_suspend_host(host);
548-
if (ret)
549-
return ret;
565+
ret = pm_runtime_force_suspend(dev);
550566

551-
clk_disable_unprepare(pltfm_host->clk);
567+
priv->restore_needed = true;
552568
return ret;
553569
}
570+
#endif
554571

555-
static int xenon_resume(struct device *dev)
572+
#ifdef CONFIG_PM
573+
static int xenon_runtime_suspend(struct device *dev)
556574
{
557575
struct sdhci_host *host = dev_get_drvdata(dev);
558576
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
577+
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
559578
int ret;
560579

561-
ret = clk_prepare_enable(pltfm_host->clk);
580+
ret = sdhci_runtime_suspend_host(host);
562581
if (ret)
563582
return ret;
564583

584+
if (host->tuning_mode != SDHCI_TUNING_MODE_3)
585+
mmc_retune_needed(host->mmc);
586+
587+
clk_disable_unprepare(pltfm_host->clk);
565588
/*
566-
* If SoCs power off the entire Xenon, registers setting will
567-
* be lost.
568-
* Re-configure Xenon specific register to enable current SDHC
589+
* Need to update the priv->clock here, or when runtime resume
590+
* back, phy don't aware the clock change and won't adjust phy
591+
* which will cause cmd err
569592
*/
570-
ret = xenon_sdhc_prepare(host);
571-
if (ret)
593+
priv->clock = 0;
594+
return 0;
595+
}
596+
597+
static int xenon_runtime_resume(struct device *dev)
598+
{
599+
struct sdhci_host *host = dev_get_drvdata(dev);
600+
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
601+
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
602+
int ret;
603+
604+
ret = clk_prepare_enable(pltfm_host->clk);
605+
if (ret) {
606+
dev_err(dev, "can't enable mainck\n");
572607
return ret;
608+
}
573609

574-
return sdhci_resume_host(host);
575-
}
576-
#endif
610+
if (priv->restore_needed) {
611+
ret = xenon_sdhc_prepare(host);
612+
if (ret)
613+
goto out;
614+
priv->restore_needed = false;
615+
}
577616

578-
static SIMPLE_DEV_PM_OPS(xenon_pmops, xenon_suspend, xenon_resume);
617+
ret = sdhci_runtime_resume_host(host);
618+
if (ret)
619+
goto out;
620+
return 0;
621+
out:
622+
clk_disable_unprepare(pltfm_host->clk);
623+
return ret;
624+
}
625+
#endif /* CONFIG_PM */
626+
627+
static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
628+
SET_SYSTEM_SLEEP_PM_OPS(xenon_suspend,
629+
pm_runtime_force_resume)
630+
SET_RUNTIME_PM_OPS(xenon_runtime_suspend,
631+
xenon_runtime_resume,
632+
NULL)
633+
};
579634

580635
static const struct of_device_id sdhci_xenon_dt_ids[] = {
581636
{ .compatible = "marvell,armada-ap806-sdhci",},
@@ -589,7 +644,7 @@ static struct platform_driver sdhci_xenon_driver = {
589644
.driver = {
590645
.name = "xenon-sdhci",
591646
.of_match_table = sdhci_xenon_dt_ids,
592-
.pm = &xenon_pmops,
647+
.pm = &sdhci_xenon_dev_pm_ops,
593648
},
594649
.probe = xenon_probe,
595650
.remove = xenon_remove,

drivers/mmc/host/sdhci-xenon.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ struct xenon_priv {
9191
*/
9292
void *phy_params;
9393
struct xenon_emmc_phy_regs *emmc_phy_regs;
94+
bool restore_needed;
9495
};
9596

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

0 commit comments

Comments
 (0)