summaryrefslogtreecommitdiff
authorZhe Wang <Zhe.Wang@amlogic.com>2019-05-13 06:56:25 (GMT)
committer Xiaoliang Wang <xiaoliang.wang@amlogic.com>2019-05-28 05:35:19 (GMT)
commit52ac3ad3ad1a80bf28ad6300426b8314a3389958 (patch)
tree12594cd05014187e3aa1f5f1ecf068f02c45c226
parentc777ea7347c3b6226537aa168ff580a475a3118b (diff)
downloadcommon-52ac3ad3ad1a80bf28ad6300426b8314a3389958.zip
common-52ac3ad3ad1a80bf28ad6300426b8314a3389958.tar.gz
common-52ac3ad3ad1a80bf28ad6300426b8314a3389958.tar.bz2
audio: add i2s and spdif fine clk tuning interface [1/1]
PD#SWPL-8310 BUG=127586435 Problem: DTV, a/v is out of sync Solution: add i2s and spdif fine clk tuning interface Verify: verify on R311. Change-Id: If16a280cfb2c6b01e8b4bc98378ebbfd3a724813 Signed-off-by: Zhe Wang <Zhe.Wang@amlogic.com>
Diffstat
-rw-r--r--sound/soc/amlogic/meson/i2s_dai.c60
-rw-r--r--sound/soc/amlogic/meson/i2s_dai.h1
-rw-r--r--sound/soc/amlogic/meson/spdif_dai.c50
3 files changed, 111 insertions, 0 deletions
diff --git a/sound/soc/amlogic/meson/i2s_dai.c b/sound/soc/amlogic/meson/i2s_dai.c
index 79a54e9..381f389 100644
--- a/sound/soc/amlogic/meson/i2s_dai.c
+++ b/sound/soc/amlogic/meson/i2s_dai.c
@@ -49,6 +49,63 @@
#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 = {
diff --git a/sound/soc/amlogic/meson/i2s_dai.h b/sound/soc/amlogic/meson/i2s_dai.h
index 9246fed..202b6f5 100644
--- a/sound/soc/amlogic/meson/i2s_dai.h
+++ b/sound/soc/amlogic/meson/i2s_dai.h
@@ -26,5 +26,6 @@ struct aml_i2s {
int audin_fifo_src;
int i2s_pos_sync;
int clk_data_pos;
+ unsigned long mclk;
};
#endif
diff --git a/sound/soc/amlogic/meson/spdif_dai.c b/sound/soc/amlogic/meson/spdif_dai.c
index 4fe7f6a..27cc6a4 100644
--- a/sound/soc/amlogic/meson/spdif_dai.c
+++ b/sound/soc/amlogic/meson/spdif_dai.c
@@ -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);