mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
audio: add i2s and spdif fine clk tuning interface [1/1]
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>
This commit is contained in:
@@ -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 = {
|
||||
|
||||
@@ -26,5 +26,6 @@ struct aml_i2s {
|
||||
int audin_fifo_src;
|
||||
int i2s_pos_sync;
|
||||
int clk_data_pos;
|
||||
unsigned long mclk;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user