Add pm runtime support and move clock handling there.
Close the clocks at suspend to reduce the power consumption.

fsl_spdif_suspend is replaced by pm_runtime_force_suspend.
fsl_spdif_resume is replaced by pm_runtime_force_resume.

Signed-off-by: Shengjiu Wang <shengjiu.w...@nxp.com>
Acked-by: Nicolin Chen <nicoleots...@gmail.com>
---
changes in v2
- remove goto in startup()
- remove goto disable_spba_clk
- Add Acked-by: Nicolin Chen

 sound/soc/fsl/fsl_spdif.c | 117 ++++++++++++++++++++++----------------
 1 file changed, 67 insertions(+), 50 deletions(-)

diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
index 5bc0e4729341..5b2689ae63d4 100644
--- a/sound/soc/fsl/fsl_spdif.c
+++ b/sound/soc/fsl/fsl_spdif.c
@@ -16,6 +16,7 @@
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/regmap.h>
+#include <linux/pm_runtime.h>
 
 #include <sound/asoundef.h>
 #include <sound/dmaengine_pcm.h>
@@ -495,29 +496,14 @@ static int fsl_spdif_startup(struct snd_pcm_substream 
*substream,
        struct platform_device *pdev = spdif_priv->pdev;
        struct regmap *regmap = spdif_priv->regmap;
        u32 scr, mask;
-       int i;
        int ret;
 
        /* Reset module and interrupts only for first initialization */
        if (!snd_soc_dai_active(cpu_dai)) {
-               ret = clk_prepare_enable(spdif_priv->coreclk);
-               if (ret) {
-                       dev_err(&pdev->dev, "failed to enable core clock\n");
-                       return ret;
-               }
-
-               if (!IS_ERR(spdif_priv->spbaclk)) {
-                       ret = clk_prepare_enable(spdif_priv->spbaclk);
-                       if (ret) {
-                               dev_err(&pdev->dev, "failed to enable spba 
clock\n");
-                               goto err_spbaclk;
-                       }
-               }
-
                ret = spdif_softreset(spdif_priv);
                if (ret) {
                        dev_err(&pdev->dev, "failed to soft reset\n");
-                       goto err;
+                       return ret;
                }
 
                /* Disable all the interrupts */
@@ -531,18 +517,10 @@ static int fsl_spdif_startup(struct snd_pcm_substream 
*substream,
                mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
                        SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
                        SCR_TXFIFO_FSEL_MASK;
-               for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
-                       ret = clk_prepare_enable(spdif_priv->txclk[i]);
-                       if (ret)
-                               goto disable_txclk;
-               }
        } else {
                scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
                mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
                        SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
-               ret = clk_prepare_enable(spdif_priv->rxclk);
-               if (ret)
-                       goto err;
        }
        regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
 
@@ -550,17 +528,6 @@ static int fsl_spdif_startup(struct snd_pcm_substream 
*substream,
        regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
 
        return 0;
-
-disable_txclk:
-       for (i--; i >= 0; i--)
-               clk_disable_unprepare(spdif_priv->txclk[i]);
-err:
-       if (!IS_ERR(spdif_priv->spbaclk))
-               clk_disable_unprepare(spdif_priv->spbaclk);
-err_spbaclk:
-       clk_disable_unprepare(spdif_priv->coreclk);
-
-       return ret;
 }
 
 static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
@@ -569,20 +536,17 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream 
*substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct fsl_spdif_priv *spdif_priv = 
snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
        struct regmap *regmap = spdif_priv->regmap;
-       u32 scr, mask, i;
+       u32 scr, mask;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                scr = 0;
                mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
                        SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
                        SCR_TXFIFO_FSEL_MASK;
-               for (i = 0; i < SPDIF_TXRATE_MAX; i++)
-                       clk_disable_unprepare(spdif_priv->txclk[i]);
        } else {
                scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO;
                mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
                        SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
-               clk_disable_unprepare(spdif_priv->rxclk);
        }
        regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
 
@@ -591,9 +555,6 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream 
*substream,
                spdif_intr_status_clear(spdif_priv);
                regmap_update_bits(regmap, REG_SPDIF_SCR,
                                SCR_LOW_POWER, SCR_LOW_POWER);
-               if (!IS_ERR(spdif_priv->spbaclk))
-                       clk_disable_unprepare(spdif_priv->spbaclk);
-               clk_disable_unprepare(spdif_priv->coreclk);
        }
 }
 
@@ -1350,6 +1311,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 
        /* Register with ASoC */
        dev_set_drvdata(&pdev->dev, spdif_priv);
+       pm_runtime_enable(&pdev->dev);
+       regcache_cache_only(spdif_priv->regmap, true);
 
        ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
                                              &spdif_priv->cpu_dai_drv, 1);
@@ -1365,36 +1328,90 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        return ret;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int fsl_spdif_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int fsl_spdif_runtime_suspend(struct device *dev)
 {
        struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
+       int i;
 
        regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC,
                        &spdif_priv->regcache_srpc);
-
        regcache_cache_only(spdif_priv->regmap, true);
-       regcache_mark_dirty(spdif_priv->regmap);
+
+       clk_disable_unprepare(spdif_priv->rxclk);
+
+       for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+               clk_disable_unprepare(spdif_priv->txclk[i]);
+
+       if (!IS_ERR(spdif_priv->spbaclk))
+               clk_disable_unprepare(spdif_priv->spbaclk);
+       clk_disable_unprepare(spdif_priv->coreclk);
 
        return 0;
 }
 
-static int fsl_spdif_resume(struct device *dev)
+static int fsl_spdif_runtime_resume(struct device *dev)
 {
        struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
+       int ret;
+       int i;
+
+       ret = clk_prepare_enable(spdif_priv->coreclk);
+       if (ret) {
+               dev_err(dev, "failed to enable core clock\n");
+               return ret;
+       }
+
+       if (!IS_ERR(spdif_priv->spbaclk)) {
+               ret = clk_prepare_enable(spdif_priv->spbaclk);
+               if (ret) {
+                       dev_err(dev, "failed to enable spba clock\n");
+                       goto disable_core_clk;
+               }
+       }
+
+       for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
+               ret = clk_prepare_enable(spdif_priv->txclk[i]);
+               if (ret)
+                       goto disable_tx_clk;
+       }
+
+       ret = clk_prepare_enable(spdif_priv->rxclk);
+       if (ret)
+               goto disable_tx_clk;
 
        regcache_cache_only(spdif_priv->regmap, false);
+       regcache_mark_dirty(spdif_priv->regmap);
 
        regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC,
                        SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
                        spdif_priv->regcache_srpc);
 
-       return regcache_sync(spdif_priv->regmap);
+       ret = regcache_sync(spdif_priv->regmap);
+       if (ret)
+               goto disable_rx_clk;
+
+       return 0;
+
+disable_rx_clk:
+       clk_disable_unprepare(spdif_priv->rxclk);
+disable_tx_clk:
+       for (i--; i >= 0; i--)
+               clk_disable_unprepare(spdif_priv->txclk[i]);
+       if (!IS_ERR(spdif_priv->spbaclk))
+               clk_disable_unprepare(spdif_priv->spbaclk);
+disable_core_clk:
+       clk_disable_unprepare(spdif_priv->coreclk);
+
+       return ret;
 }
-#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
 
 static const struct dev_pm_ops fsl_spdif_pm = {
-       SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
+       SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume,
+                          NULL)
 };
 
 static const struct of_device_id fsl_spdif_dt_ids[] = {
-- 
2.21.0

Reply via email to