From: Shengjiu Wang <shengjiu.w...@nxp.com>

Turn off/on clocks when device enters suspend/resume. This
can help saving power.

As a further optimization, we turn off/on mclk only when SAI
is in master mode because otherwise mclk is externally provided.

Signed-off-by: Shengjiu Wang <shengjiu.w...@nxp.com>
Signed-off-by: Daniel Baluta <daniel.bal...@nxp.com>
Reviewed-by: Viorel Suman <viorel.su...@nxp.com>
---
- initially part of this 3 patch series 
https://patchwork.kernel.org/cover/10911519/
- first 2 patches were merged

 sound/soc/fsl/fsl_sai.c | 54 +++++++++++++++++++++++++++++++++--------
 1 file changed, 44 insertions(+), 10 deletions(-)

diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index 8593269156bd..d58cc3ae90d8 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -596,15 +596,8 @@ static int fsl_sai_startup(struct snd_pcm_substream 
*substream,
 {
        struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
-       struct device *dev = &sai->pdev->dev;
        int ret;
 
-       ret = clk_prepare_enable(sai->bus_clk);
-       if (ret) {
-               dev_err(dev, "failed to enable bus clock: %d\n", ret);
-               return ret;
-       }
-
        regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE,
                           FSL_SAI_CR3_TRCE);
 
@@ -621,8 +614,6 @@ static void fsl_sai_shutdown(struct snd_pcm_substream 
*substream,
        bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
 
        regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx), FSL_SAI_CR3_TRCE, 0);
-
-       clk_disable_unprepare(sai->bus_clk);
 }
 
 static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
@@ -935,6 +926,14 @@ static int fsl_sai_runtime_suspend(struct device *dev)
 {
        struct fsl_sai *sai = dev_get_drvdata(dev);
 
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
+
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]);
+
+       clk_disable_unprepare(sai->bus_clk);
+
        regcache_cache_only(sai->regmap, true);
        regcache_mark_dirty(sai->regmap);
 
@@ -944,6 +943,25 @@ static int fsl_sai_runtime_suspend(struct device *dev)
 static int fsl_sai_runtime_resume(struct device *dev)
 {
        struct fsl_sai *sai = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(sai->bus_clk);
+       if (ret) {
+               dev_err(dev, "failed to enable bus clock: %d\n", ret);
+               return ret;
+       }
+
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK)) {
+               ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[1]]);
+               if (ret)
+                       goto disable_bus_clk;
+       }
+
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE)) {
+               ret = clk_prepare_enable(sai->mclk_clk[sai->mclk_id[0]]);
+               if (ret)
+                       goto disable_tx_clk;
+       }
 
        regcache_cache_only(sai->regmap, false);
        regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
@@ -951,7 +969,23 @@ static int fsl_sai_runtime_resume(struct device *dev)
        usleep_range(1000, 2000);
        regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
        regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
-       return regcache_sync(sai->regmap);
+
+       ret = regcache_sync(sai->regmap);
+       if (ret)
+               goto disable_rx_clk;
+
+       return 0;
+
+disable_rx_clk:
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_CAPTURE))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[0]]);
+disable_tx_clk:
+       if (sai->mclk_streams & BIT(SNDRV_PCM_STREAM_PLAYBACK))
+               clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[1]]);
+disable_bus_clk:
+       clk_disable_unprepare(sai->bus_clk);
+
+       return ret;
 }
 #endif /* CONFIG_PM */
 
-- 
2.17.1

Reply via email to