From 610f30df70a790733ed25a1be250e08cce19f368 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 23 May 2017 16:44:28 +0100 Subject: [PATCH] ASoC: tegra-alt: Fix system suspend handling There are a couple issues with system suspend handling in the Tegra ASoC codec drivers which are: 1. Most drivers the system suspend callback does nothing and this means that if the codec device is active when suspend occurs then the codec will not be suspended correctly. This has been seen to cause system crashes in the I2S driver when the system is suspended and resuming while audio playback is active. 2. The codec suspend handlers may be called twice when entering suspend. Suspend handlers should only be called once, but currently they are called twice; once by the PM core and once when the APE power-domain is turned off (if it is on when suspend occurs). Fix the above two problems by: a). Adding proper system suspend and resume handlers for all codec drivers, to suspend and resume the device if not runtime PM suspended on entering suspend. b). Remove the code to call the PM callbacks from the APE power-domain code. Finally, make the system suspend callbacks for these codec drivers late suspend callbacks to ensure that the sound core has suspended any on-going activity, before we attempt to suspend these codec devices. Bug 200275736 Change-Id: I09d7e570be4e1866683873591ff76be63fdaf3fb Signed-off-by: Jon Hunter Reviewed-on: http://git-master/r/1488953 GVS: Gerrit_Virtual_Submit Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bibek Basu Tested-by: Bibek Basu --- drivers/platform/tegra/pm_domains.c | 7 ------- sound/soc/tegra-alt/tegra210_admaif_alt.c | 16 ++++++++++++++-- sound/soc/tegra-alt/tegra210_adx_alt.c | 15 +++++++++++++-- sound/soc/tegra-alt/tegra210_afc_alt.c | 15 +++++++++++++-- sound/soc/tegra-alt/tegra210_amx_alt.c | 15 +++++++++++++-- sound/soc/tegra-alt/tegra210_dmic_alt.c | 16 ++++++++++++++-- sound/soc/tegra-alt/tegra210_i2s_alt.c | 15 +++++++++++++-- sound/soc/tegra-alt/tegra210_iqc_alt.c | 15 +++++++++++++-- sound/soc/tegra-alt/tegra210_mixer_alt.c | 16 ++++++++++++++-- sound/soc/tegra-alt/tegra210_mvc_alt.c | 17 ++++++++++++----- sound/soc/tegra-alt/tegra210_ope_alt.c | 15 +++++++++++++-- sound/soc/tegra-alt/tegra210_sfc_alt.c | 15 +++++++++++++-- sound/soc/tegra-alt/tegra210_spdif_alt.c | 16 ++++++++++++++-- sound/soc/tegra-alt/tegra210_xbar_alt.c | 23 +++++++++-------------- 14 files changed, 168 insertions(+), 48 deletions(-) diff --git a/drivers/platform/tegra/pm_domains.c b/drivers/platform/tegra/pm_domains.c index 52e4a724e926..45406b295ccf 100644 --- a/drivers/platform/tegra/pm_domains.c +++ b/drivers/platform/tegra/pm_domains.c @@ -225,7 +225,6 @@ static int tegra_ape_pd_disable_clks(struct tegra_pm_domain *ape_pd) static int tegra_ape_power_on(struct generic_pm_domain *genpd) { struct tegra_pm_domain *ape_pd; - struct pm_domain_data *pdd; int ret = 0; int partition_id; struct device_node *dn; @@ -266,8 +265,6 @@ static int tegra_ape_power_on(struct generic_pm_domain *genpd) #ifdef CONFIG_TEGRA_APE_AGIC tegra_agic_restore_registers(); #endif - list_for_each_entry(pdd, &genpd->dev_list, list_node) - TEGRA_PD_DEV_CALLBACK(resume, pdd->dev); } else { /* * The adsp clock shall be enabled only when ADSP cpu is @@ -283,7 +280,6 @@ static int tegra_ape_power_on(struct generic_pm_domain *genpd) static int tegra_ape_power_off(struct generic_pm_domain *genpd) { struct tegra_pm_domain *ape_pd; - struct pm_domain_data *pdd; int ret = 0; int partition_id; struct device_node *dn; @@ -293,9 +289,6 @@ static int tegra_ape_power_off(struct generic_pm_domain *genpd) if (ret) return -EINVAL; - list_for_each_entry(pdd, &genpd->dev_list, list_node) - TEGRA_PD_DEV_CALLBACK(suspend, pdd->dev); - #ifdef CONFIG_TEGRA_APE_AGIC tegra_agic_save_registers(); #endif diff --git a/sound/soc/tegra-alt/tegra210_admaif_alt.c b/sound/soc/tegra-alt/tegra210_admaif_alt.c index 6205d3ad31dc..ea76cfa107a4 100644 --- a/sound/soc/tegra-alt/tegra210_admaif_alt.c +++ b/sound/soc/tegra-alt/tegra210_admaif_alt.c @@ -246,7 +246,18 @@ static int tegra210_admaif_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_admaif_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_admaif_runtime_suspend(dev); +} + +static int tegra210_admaif_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_admaif_runtime_resume(dev); } #endif @@ -1210,7 +1221,8 @@ static int tegra210_admaif_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_admaif_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_admaif_runtime_suspend, tegra210_admaif_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_admaif_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_admaif_suspend, + tegra210_admaif_resume) }; static struct platform_driver tegra210_admaif_driver = { diff --git a/sound/soc/tegra-alt/tegra210_adx_alt.c b/sound/soc/tegra-alt/tegra210_adx_alt.c index d982003a770c..3182c33c3506 100644 --- a/sound/soc/tegra-alt/tegra210_adx_alt.c +++ b/sound/soc/tegra-alt/tegra210_adx_alt.c @@ -272,7 +272,18 @@ static int tegra210_adx_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_adx_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_adx_runtime_suspend(dev); +} + +static int tegra210_adx_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_adx_runtime_resume(dev); } #endif @@ -730,7 +741,7 @@ static int tegra210_adx_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_adx_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend, tegra210_adx_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_adx_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_adx_suspend, tegra210_adx_resume) }; static struct platform_driver tegra210_adx_driver = { diff --git a/sound/soc/tegra-alt/tegra210_afc_alt.c b/sound/soc/tegra-alt/tegra210_afc_alt.c index 56c6af1e8286..e5c3d6739834 100644 --- a/sound/soc/tegra-alt/tegra210_afc_alt.c +++ b/sound/soc/tegra-alt/tegra210_afc_alt.c @@ -85,7 +85,18 @@ static int tegra210_afc_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_afc_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_afc_runtime_suspend(dev); +} + +static int tegra210_afc_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_afc_runtime_resume(dev); } #endif @@ -483,7 +494,7 @@ static int tegra210_afc_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_afc_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_afc_runtime_suspend, tegra210_afc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_afc_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_afc_suspend, tegra210_afc_resume) }; static struct platform_driver tegra210_afc_driver = { diff --git a/sound/soc/tegra-alt/tegra210_amx_alt.c b/sound/soc/tegra-alt/tegra210_amx_alt.c index d30043d1bd22..c442a44af07b 100644 --- a/sound/soc/tegra-alt/tegra210_amx_alt.c +++ b/sound/soc/tegra-alt/tegra210_amx_alt.c @@ -299,7 +299,18 @@ static int tegra210_amx_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_amx_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_amx_runtime_suspend(dev); +} + +static int tegra210_amx_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_amx_runtime_resume(dev); } #endif @@ -959,7 +970,7 @@ static int tegra210_amx_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_amx_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend, tegra210_amx_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_amx_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_amx_suspend, tegra210_amx_resume) }; static struct platform_driver tegra210_amx_driver = { diff --git a/sound/soc/tegra-alt/tegra210_dmic_alt.c b/sound/soc/tegra-alt/tegra210_dmic_alt.c index 08a520795455..393f86d8b7a7 100644 --- a/sound/soc/tegra-alt/tegra210_dmic_alt.c +++ b/sound/soc/tegra-alt/tegra210_dmic_alt.c @@ -125,7 +125,18 @@ static int tegra210_dmic_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_dmic_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_dmic_runtime_suspend(dev); +} + +static int tegra210_dmic_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_dmic_runtime_resume(dev); } #endif @@ -675,7 +686,8 @@ static int tegra210_dmic_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_dmic_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend, tegra210_dmic_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_dmic_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_dmic_suspend, + tegra210_dmic_resume) }; static struct platform_driver tegra210_dmic_driver = { diff --git a/sound/soc/tegra-alt/tegra210_i2s_alt.c b/sound/soc/tegra-alt/tegra210_i2s_alt.c index 699c28a161e1..49ae35cadd50 100644 --- a/sound/soc/tegra-alt/tegra210_i2s_alt.c +++ b/sound/soc/tegra-alt/tegra210_i2s_alt.c @@ -294,7 +294,18 @@ static int tegra210_i2s_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_i2s_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_i2s_runtime_suspend(dev); +} + +static int tegra210_i2s_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_i2s_runtime_resume(dev); } #endif @@ -1227,7 +1238,7 @@ static int tegra210_i2s_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_i2s_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend, tegra210_i2s_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_i2s_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_i2s_suspend, tegra210_i2s_resume) }; static struct platform_driver tegra210_i2s_driver = { diff --git a/sound/soc/tegra-alt/tegra210_iqc_alt.c b/sound/soc/tegra-alt/tegra210_iqc_alt.c index 61d929833fcd..514e045935aa 100644 --- a/sound/soc/tegra-alt/tegra210_iqc_alt.c +++ b/sound/soc/tegra-alt/tegra210_iqc_alt.c @@ -80,7 +80,18 @@ static int tegra210_iqc_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_iqc_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_iqc_runtime_suspend(dev); +} + +static int tegra210_iqc_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_iqc_runtime_resume(dev); } #endif @@ -447,7 +458,7 @@ static int tegra210_iqc_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_iqc_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_iqc_runtime_suspend, tegra210_iqc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_iqc_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_iqc_suspend, tegra210_iqc_resume) }; static struct platform_driver tegra210_iqc_driver = { diff --git a/sound/soc/tegra-alt/tegra210_mixer_alt.c b/sound/soc/tegra-alt/tegra210_mixer_alt.c index 73516b235de8..b265273c41e8 100644 --- a/sound/soc/tegra-alt/tegra210_mixer_alt.c +++ b/sound/soc/tegra-alt/tegra210_mixer_alt.c @@ -100,7 +100,18 @@ static int tegra210_mixer_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_mixer_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_mixer_runtime_suspend(dev); +} + +static int tegra210_mixer_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_mixer_runtime_resume(dev); } #endif @@ -819,7 +830,8 @@ static int tegra210_mixer_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_mixer_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend, tegra210_mixer_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_mixer_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_mixer_suspend, + tegra210_mixer_resume) }; static struct platform_driver tegra210_mixer_driver = { diff --git a/sound/soc/tegra-alt/tegra210_mvc_alt.c b/sound/soc/tegra-alt/tegra210_mvc_alt.c index e2f1d708b549..a8865f66ef60 100644 --- a/sound/soc/tegra-alt/tegra210_mvc_alt.c +++ b/sound/soc/tegra-alt/tegra210_mvc_alt.c @@ -59,6 +59,7 @@ static int tegra210_mvc_runtime_suspend(struct device *dev) struct tegra210_mvc *mvc = dev_get_drvdata(dev); regcache_cache_only(mvc->regmap, true); + regcache_mark_dirty(mvc->regmap); return 0; } @@ -83,12 +84,18 @@ static int tegra210_mvc_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_mvc_suspend(struct device *dev) { - struct tegra210_mvc *mvc = dev_get_drvdata(dev); + if (pm_runtime_status_suspended(dev)) + return 0; - if (mvc) - regcache_mark_dirty(mvc->regmap); + return tegra210_mvc_runtime_suspend(dev); +} - return 0; +static int tegra210_mvc_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_mvc_runtime_resume(dev); } #endif @@ -740,7 +747,7 @@ static int tegra210_mvc_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_mvc_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend, tegra210_mvc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_mvc_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_mvc_suspend, tegra210_mvc_resume) }; static struct platform_driver tegra210_mvc_driver = { diff --git a/sound/soc/tegra-alt/tegra210_ope_alt.c b/sound/soc/tegra-alt/tegra210_ope_alt.c index 2d35e6d40ac2..fb166b0fe45e 100644 --- a/sound/soc/tegra-alt/tegra210_ope_alt.c +++ b/sound/soc/tegra-alt/tegra210_ope_alt.c @@ -79,7 +79,18 @@ static int tegra210_ope_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_ope_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_ope_runtime_suspend(dev); +} + +static int tegra210_ope_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_ope_runtime_resume(dev); } #endif @@ -464,7 +475,7 @@ static int tegra210_ope_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_ope_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend, tegra210_ope_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_ope_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_ope_suspend, tegra210_ope_resume) }; static struct platform_driver tegra210_ope_driver = { diff --git a/sound/soc/tegra-alt/tegra210_sfc_alt.c b/sound/soc/tegra-alt/tegra210_sfc_alt.c index b67046f5ae8b..843a86557f27 100644 --- a/sound/soc/tegra-alt/tegra210_sfc_alt.c +++ b/sound/soc/tegra-alt/tegra210_sfc_alt.c @@ -87,7 +87,18 @@ static int tegra210_sfc_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_sfc_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_sfc_runtime_suspend(dev); +} + +static int tegra210_sfc_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_sfc_runtime_resume(dev); } #endif @@ -975,7 +986,7 @@ static int tegra210_sfc_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_sfc_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend, tegra210_sfc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_sfc_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_sfc_suspend, tegra210_sfc_resume) }; static struct platform_driver tegra210_sfc_driver = { diff --git a/sound/soc/tegra-alt/tegra210_spdif_alt.c b/sound/soc/tegra-alt/tegra210_spdif_alt.c index f40a2e4e4422..64a1fb2cb609 100644 --- a/sound/soc/tegra-alt/tegra210_spdif_alt.c +++ b/sound/soc/tegra-alt/tegra210_spdif_alt.c @@ -118,7 +118,18 @@ static int tegra210_spdif_runtime_resume(struct device *dev) #ifdef CONFIG_PM_SLEEP static int tegra210_spdif_suspend(struct device *dev) { - return 0; + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_spdif_runtime_suspend(dev); +} + +static int tegra210_spdif_resume(struct device *dev) +{ + if (pm_runtime_status_suspended(dev)) + return 0; + + return tegra210_spdif_runtime_resume(dev); } #endif @@ -649,7 +660,8 @@ static int tegra210_spdif_platform_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_spdif_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_spdif_runtime_suspend, tegra210_spdif_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_spdif_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_spdif_suspend, + tegra210_spdif_resume) }; static struct platform_driver tegra210_spdif_driver = { diff --git a/sound/soc/tegra-alt/tegra210_xbar_alt.c b/sound/soc/tegra-alt/tegra210_xbar_alt.c index e3269e958eda..a2f2a1350d9f 100644 --- a/sound/soc/tegra-alt/tegra210_xbar_alt.c +++ b/sound/soc/tegra-alt/tegra210_xbar_alt.c @@ -102,26 +102,20 @@ static int tegra210_xbar_runtime_resume(struct device *dev) } #ifdef CONFIG_PM_SLEEP -static int tegra210_xbar_child_suspend(struct device *dev, void *data) +static int tegra210_xbar_suspend(struct device *dev) { - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) + if (pm_runtime_status_suspended(dev)) return 0; - if (drv->pm) - if (drv->pm->suspend) - ret = drv->pm->suspend(dev); - - return ret; + return tegra210_xbar_runtime_suspend(dev); } -static int tegra210_xbar_suspend(struct device *dev) +static int tegra210_xbar_resume(struct device *dev) { - device_for_each_child(dev, NULL, tegra210_xbar_child_suspend); + if (pm_runtime_status_suspended(dev)) + return 0; - return 0; + return tegra210_xbar_runtime_resume(dev); } #endif @@ -1019,7 +1013,8 @@ static int tegra210_xbar_remove(struct platform_device *pdev) static const struct dev_pm_ops tegra210_xbar_pm_ops = { SET_RUNTIME_PM_OPS(tegra210_xbar_runtime_suspend, tegra210_xbar_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra210_xbar_suspend, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(tegra210_xbar_suspend, + tegra210_xbar_resume) }; static struct platform_driver tegra210_xbar_driver = { -- 2.39.2