]> git.baikalelectronics.ru Git - kernel.git/commitdiff
ASoC: fsl_spdif: Add support for PLL switch at runtime.
authorShengjiu Wang <shengjiu.wang@nxp.com>
Fri, 1 Jul 2022 09:32:37 +0000 (17:32 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 5 Jul 2022 12:00:38 +0000 (13:00 +0100)
i.MX8MQ/MN/MM/MP platforms typically have 2 AUDIO PLLs being
configured to handle 8kHz and 11kHz series audio rates.

The patch implements the functionality to select at runtime
the appropriate AUDIO PLL as function of audio file rate.
As the clock parent may be changed, need to probe txclk
according to sample rate again.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Link: https://lore.kernel.org/r/1656667961-1799-3-git-send-email-shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_spdif.c

index 10fa3875345338a39a5911011f24fe42146a4d52..910b8747b6bdfd934498a6fe8e00ffcec7503594 100644 (file)
@@ -59,6 +59,7 @@ config SND_SOC_FSL_SPDIF
        select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n
        select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC)
        select BITREVERSE
+       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add Sony/Philips Digital Interface (SPDIF)
          support for the Freescale CPUs.
index 0504431792cf93e34e1fe6ecc720bfa43f87e5f0..7fc1c96929bb841a282b3b728254d06adf8b3e90 100644 (file)
@@ -23,6 +23,7 @@
 #include <sound/soc.h>
 
 #include "fsl_spdif.h"
+#include "fsl_utils.h"
 #include "imx-pcm.h"
 
 #define FSL_SPDIF_TXFIFO_WML   0x8
@@ -114,6 +115,8 @@ struct spdif_mixer_control {
  * @dma_params_rx: DMA parameters for receive channel
  * @regcache_srpc: regcache for SRPC
  * @bypass: status of bypass input to output
+ * @pll8k_clk: PLL clock for the rate of multiply of 8kHz
+ * @pll11k_clk: PLL clock for the rate of multiply of 11kHz
  */
 struct fsl_spdif_priv {
        const struct fsl_spdif_soc_data *soc;
@@ -137,6 +140,8 @@ struct fsl_spdif_priv {
        /* regcache for SRPC */
        u32 regcache_srpc;
        bool bypass;
+       struct clk *pll8k_clk;
+       struct clk *pll11k_clk;
 };
 
 static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
@@ -480,6 +485,8 @@ static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
        return 0;
 }
 
+static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index);
+
 static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
                                int sample_rate)
 {
@@ -528,6 +535,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       ret = fsl_spdif_probe_txclk(spdif_priv, rate);
+       if (ret)
+               return ret;
+
        clk = spdif_priv->txclk_src[rate];
        if (clk >= STC_TXCLK_SRC_MAX) {
                dev_err(&pdev->dev, "tx clock source is out of range\n");
@@ -647,6 +658,29 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
        }
 }
 
+static int spdif_reparent_rootclk(struct fsl_spdif_priv *spdif_priv, unsigned int sample_rate)
+{
+       struct platform_device *pdev = spdif_priv->pdev;
+       struct clk *clk;
+       int ret;
+
+       /* Reparent clock if required condition is true */
+       if (!fsl_spdif_can_set_clk_rate(spdif_priv, STC_TXCLK_SPDIF_ROOT))
+               return 0;
+
+       /* Get root clock */
+       clk = spdif_priv->txclk[STC_TXCLK_SPDIF_ROOT];
+
+       /* Disable clock first, for it was enabled by pm_runtime */
+       clk_disable_unprepare(clk);
+       fsl_asoc_reparent_pll_clocks(&pdev->dev, clk, spdif_priv->pll8k_clk,
+                                    spdif_priv->pll11k_clk, sample_rate);
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               return ret;
+
+       return 0;
+}
 static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
@@ -659,6 +693,13 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
        int ret = 0;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               ret = spdif_reparent_rootclk(spdif_priv, sample_rate);
+               if (ret) {
+                       dev_err(&pdev->dev, "%s: reparent root clk failed: %d\n",
+                               __func__, sample_rate);
+                       return ret;
+               }
+
                ret  = spdif_set_sample_rate(substream, sample_rate);
                if (ret) {
                        dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
@@ -1548,11 +1589,8 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        }
        spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC;
 
-       for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
-               ret = fsl_spdif_probe_txclk(spdif_priv, i);
-               if (ret)
-                       return ret;
-       }
+       fsl_asoc_get_pll_clocks(&pdev->dev, &spdif_priv->pll8k_clk,
+                               &spdif_priv->pll11k_clk);
 
        /* Initial spinlock for control data */
        ctrl = &spdif_priv->fsl_spdif_control;