ASoC: tegra30: i2s: Restore hardware state on runtime PM resume
authorDmitry Osipenko <digetx@gmail.com>
Sun, 14 Mar 2021 15:44:45 +0000 (18:44 +0300)
committerMark Brown <broonie@kernel.org>
Thu, 18 Mar 2021 13:49:32 +0000 (13:49 +0000)
Tegra30 I2S driver syncs regmap cache only on resume from system suspend,
but hardware is reset across the runtime suspend because RPM of the parent
AHUB driver resets the I2S hardware, hence h/w state is lost after each
RPM resume. The problem isn't visible because hardware happens to be fully
reprogrammed after each RPM resume. Move hardware syncing to RPM resume in
order to restore h/w state properly.

Fixes: ed9ce1ed2239 ("ASoC: tegra: ahub: Reset hardware properly")
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Link: https://lore.kernel.org/r/20210314154459.15375-4-digetx@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/tegra/tegra30_i2s.c

index 6740df5..3d22c1b 100644 (file)
@@ -58,8 +58,18 @@ static int tegra30_i2s_runtime_resume(struct device *dev)
        }
 
        regcache_cache_only(i2s->regmap, false);
+       regcache_mark_dirty(i2s->regmap);
+
+       ret = regcache_sync(i2s->regmap);
+       if (ret)
+               goto disable_clocks;
 
        return 0;
+
+disable_clocks:
+       clk_disable_unprepare(i2s->clk_i2s);
+
+       return ret;
 }
 
 static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
@@ -551,37 +561,11 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int tegra30_i2s_suspend(struct device *dev)
-{
-       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
-
-       regcache_mark_dirty(i2s->regmap);
-
-       return 0;
-}
-
-static int tegra30_i2s_resume(struct device *dev)
-{
-       struct tegra30_i2s *i2s = dev_get_drvdata(dev);
-       int ret;
-
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0) {
-               pm_runtime_put(dev);
-               return ret;
-       }
-       ret = regcache_sync(i2s->regmap);
-       pm_runtime_put(dev);
-
-       return ret;
-}
-#endif
-
 static const struct dev_pm_ops tegra30_i2s_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
                           tegra30_i2s_runtime_resume, NULL)
-       SET_SYSTEM_SLEEP_PM_OPS(tegra30_i2s_suspend, tegra30_i2s_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra30_i2s_driver = {