audio: add i2s and spdif fine clk tuning interface [1/1]
authorZhe Wang <Zhe.Wang@amlogic.com>
Mon, 13 May 2019 06:56:25 +0000 (14:56 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Mon, 20 May 2019 09:40:33 +0000 (02:40 -0700)
PD#SWPL-8310

Problem:
DTV, a/v is out of sync

Solution:
add i2s and spdif fine clk tuning interface

Verify:
verify on R311.

Change-Id: I8219774bd5fe334fa21227d427ce4dbb06177dc8
Signed-off-by: Zhe Wang <Zhe.Wang@amlogic.com>
sound/soc/amlogic/meson/i2s_dai.c
sound/soc/amlogic/meson/i2s_dai.h
sound/soc/amlogic/meson/spdif_dai.c

index 79a54e9..381f389 100644 (file)
 #include "spdif_dai.h"
 #include "dmic.h"
 
+static int i2s_clk_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct aml_i2s *p_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+
+       ucontrol->value.enumerated.item[0] = clk_get_rate(p_i2s->clk_mclk);
+       return 0;
+}
+
+static int i2s_clk_set(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct aml_i2s *p_i2s = snd_soc_dai_get_drvdata(cpu_dai);
+       int ret = 0;
+
+       unsigned long mclk_rate = p_i2s->mclk;
+       int value = ucontrol->value.enumerated.item[0];
+
+       if (value > 2000000 || value < 0) {
+               pr_err("Fine tdm clk setting range (0~2000000), %d\n", value);
+               return 0;
+       }
+       mclk_rate += (value - 1000000);
+
+       ret = clk_set_rate(p_i2s->clk_mpll, mclk_rate * 10);
+       if (ret) {
+               pr_err("Cannot set i2s mpll\n");
+               return ret;
+       }
+
+       ret = clk_set_rate(p_i2s->clk_mclk, mclk_rate);
+       if (ret) {
+               pr_err("Cannot set i2s mclk %ld\n", mclk_rate);
+               return ret;
+       }
+
+       p_i2s->mclk = mclk_rate;
+       return 0;
+}
+
+static const struct snd_kcontrol_new snd_i2s_controls[] = {
+       SOC_SINGLE_EXT("TDM MCLK Fine Setting",
+                               0, 0, 2000000, 0,
+                               i2s_clk_get,
+                               i2s_clk_set),
+};
+
+static int aml_dai_i2s_probe(struct snd_soc_dai *dai)
+{
+       snd_soc_add_dai_controls(dai,
+               snd_i2s_controls, ARRAY_SIZE(snd_i2s_controls));
+       return 0;
+}
+
+
 /* extern int set_i2s_iec958_samesource(int enable);
  *
  * the I2S hw  and IEC958 PCM output initiation,958 initiation here,
@@ -140,6 +197,8 @@ static int aml_i2s_set_amclk(struct aml_i2s *i2s, unsigned long rate)
        if (ret) {
                pr_info("Cannot set i2s mclk %lu\n", rate);
                return ret;
+       } else {
+               i2s->mclk = rate;
        }
 
        audio_set_i2s_clk_div();
@@ -379,6 +438,7 @@ static struct snd_soc_dai_ops aml_dai_i2s_ops = {
 struct snd_soc_dai_driver aml_i2s_dai[] = {
        {
                .id = 0,
+               .probe = aml_dai_i2s_probe,
                .suspend  = aml_dai_i2s_suspend,
                .resume   = aml_dai_i2s_resume,
                .playback = {
index 9246fed..202b6f5 100644 (file)
@@ -26,5 +26,6 @@ struct aml_i2s {
        int audin_fifo_src;
        int i2s_pos_sync;
        int clk_data_pos;
+       unsigned long mclk;
 };
 #endif
index 58990a6..8965908 100644 (file)
@@ -62,6 +62,7 @@ struct aml_spdif {
         * !Check this with chip spec.
         */
        uint src;
+       unsigned long spdifout_clk;
 };
 struct aml_spdif *spdif_p;
 
@@ -548,6 +549,7 @@ int aml_set_spdif_clk(unsigned long rate, bool src_i2s)
                        pr_err("Can't set spdif clk parent: %d\n", ret);
                        return ret;
                }
+               spdif_p->spdifout_clk = rate;
        }
 
        return 0;
@@ -588,6 +590,51 @@ static int aml_dai_spdif_resume(struct snd_soc_dai *cpu_dai)
        return 0;
 }
 
+static int spdif_clk_get(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
+
+       ucontrol->value.enumerated.item[0] =
+                       clk_get_rate(p_spdif->clk_spdif);
+       return 0;
+}
+
+static int spdif_clk_set(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
+       unsigned long sysclk = p_spdif->spdifout_clk;
+       int value = ucontrol->value.enumerated.item[0];
+
+       if (value > 2000000 || value < 0) {
+               pr_err("Fine spdif sysclk setting range(0~2000000), %d\n",
+                               value);
+               return 0;
+       }
+       value = value - 1000000;
+       sysclk += value;
+
+       aml_set_spdif_clk(sysclk, 0);
+       return 0;
+}
+
+static const struct snd_kcontrol_new aml_spdif_dai_controls[] = {
+       SOC_SINGLE_EXT("SPDIF CLK Fine Setting",
+                               0, 0, 2000000, 0,
+                               spdif_clk_get,
+                               spdif_clk_set),
+};
+
+static int aml_spdif_probe(struct snd_soc_dai *dai)
+{
+       snd_soc_add_dai_controls(dai,
+               aml_spdif_dai_controls, ARRAY_SIZE(aml_spdif_dai_controls));
+       return 0;
+}
+
 static struct snd_soc_dai_ops spdif_dai_ops = {
        .set_sysclk = aml_dai_spdif_set_sysclk,
        .trigger = aml_dai_spdif_trigger,
@@ -628,6 +675,7 @@ static struct snd_soc_dai_driver aml_spdif_dai[] = {
                .ops = &spdif_dai_ops,
                .suspend = aml_dai_spdif_suspend,
                .resume = aml_dai_spdif_resume,
+               .probe = aml_spdif_probe,
        }
 };
 
@@ -692,6 +740,7 @@ static int aml_dai_spdif_probe(struct platform_device *pdev)
                ret = PTR_ERR(spdif_priv->clk_spdif);
                goto err;
        }
+
        ret = clk_set_parent(spdif_priv->clk_i958, spdif_priv->clk_mpl1);
        if (ret) {
                pr_err("Can't set i958 clk parent: %d\n", ret);
@@ -703,6 +752,7 @@ static int aml_dai_spdif_probe(struct platform_device *pdev)
                pr_err("Can't set spdif clk parent: %d\n", ret);
                return ret;
        }
+
        ret = clk_prepare_enable(spdif_priv->clk_spdif);
        if (ret) {
                pr_err("Can't enable spdif clock: %d\n", ret);