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
515526remove_sdhc :
527+ pm_runtime_disable (& pdev -> dev );
528+ pm_runtime_put_noidle (& pdev -> dev );
516529 xenon_sdhc_unprepare (host );
517530err_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
580635static 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 ,
0 commit comments