ASoC: fsl_sai: Move clock operation to PM runtime
authorShengjiu Wang <shengjiu.wang@nxp.com>
Tue, 7 May 2019 14:06:52 +0000 (14:06 +0000)
committerMark Brown <broonie@kernel.org>
Wed, 8 May 2019 08:17:26 +0000 (17:17 +0900)
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.wang@nxp.com>
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
Acked-by: Nicolin Chen <nicoleotsuka@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/fsl/fsl_sai.c

index 8593269..d58cc3a 100644 (file)
@@ -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 */