From 3dbb379ecf54266177d16134427a9101ecc2be6c Mon Sep 17 00:00:00 2001 From: Zhe Wang Date: Mon, 25 Mar 2019 19:53:30 +0800 Subject: [PATCH] audio: add tdm and spdif clk fine tuning interface [1/1] PD#SWPL-5518 Problem: In DTV passthrough, the output clk drifts from input Solution: add clk fine tuning interface Verify: verify by X301 Change-Id: I969d3eb865fb1aba90f155965548454cc3040c99 Signed-off-by: Zhe Wang --- sound/soc/amlogic/auge/audio_utils.c | 5 +++- sound/soc/amlogic/auge/spdif.c | 51 +++++++++++++++++++++++++++++++++--- sound/soc/amlogic/auge/tdm.c | 42 ++++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/sound/soc/amlogic/auge/audio_utils.c b/sound/soc/amlogic/auge/audio_utils.c index c710d16..2301428 100644 --- a/sound/soc/amlogic/auge/audio_utils.c +++ b/sound/soc/amlogic/auge/audio_utils.c @@ -165,6 +165,7 @@ static int loopback_tdminlb_set_enum( return 0; } +#if 0 static int snd_int_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -279,6 +280,7 @@ static int snd_byte_set(struct snd_kcontrol *kcontrol, return 0; } +#endif #define SND_BYTE(xname, type, func, xshift, xmask) \ { \ @@ -742,7 +744,7 @@ static const struct snd_kcontrol_new snd_auge_controls[] = { loopback_tdminlb_enum, loopback_tdminlb_get_enum, loopback_tdminlb_set_enum), - +#if 0 /*TDMIN_A swap*/ SND_SWAP("TDMIN_A Ch0 Swap", TDMIN_A, in_swap_channel_enum, 0, 0x7), SND_SWAP("TDMIN_A Ch1 Swap", TDMIN_A, in_swap_channel_enum, 4, 0x7), @@ -983,6 +985,7 @@ static const struct snd_kcontrol_new snd_auge_controls[] = { TDMOUT_C, lane2_mixer_enum, 22, 0x1), SND_MIX("TDMOUT_C Lane3 Mixer Channel", TDMOUT_C, lane3_mixer_enum, 23, 0x1), +#endif /* SPDIFIN Channel Status */ SPDIFIN_CHSTATUS("SPDIFIN Channel Status", diff --git a/sound/soc/amlogic/auge/spdif.c b/sound/soc/amlogic/auge/spdif.c index 0205867..31757ef 100644 --- a/sound/soc/amlogic/auge/spdif.c +++ b/sound/soc/amlogic/auge/spdif.c @@ -53,6 +53,9 @@ /*#define __SPDIFIN_AUDIO_TYPE_HW__*/ +static int aml_dai_set_spdif_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir); + struct spdif_chipinfo { unsigned int id; @@ -345,16 +348,49 @@ int spdifin_source_set_enum( 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_spdifout); + 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); + + int sysclk = p_spdif->sysclk_freq; + 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; + } + sysclk += (value - 1000000); + + aml_dai_set_spdif_sysclk(cpu_dai, 0, sysclk, 0); + + return 0; +} + static const struct snd_kcontrol_new snd_spdif_controls[] = { - SOC_ENUM_EXT("SPDIFIN audio samplerate", spdifin_sample_rate_enum, + SOC_ENUM_EXT("SPDIFIN audio samplerate", + spdifin_sample_rate_enum, spdifin_samplerate_get_enum, NULL), SOC_ENUM_EXT("SPDIFIN Audio Type", - spdif_audio_type_enum, - spdifin_audio_type_get_enum, - NULL), + spdif_audio_type_enum, + spdifin_audio_type_get_enum, + NULL), SOC_ENUM_EXT("Audio spdif format", spdif_format_enum, @@ -364,15 +400,22 @@ static const struct snd_kcontrol_new snd_spdif_controls[] = { SOC_SINGLE_BOOL_EXT("Audio spdif mute", 0, aml_audio_get_spdif_mute, aml_audio_set_spdif_mute), + SOC_ENUM_EXT("Audio spdifin source", spdifin_src_enum, spdifin_source_get_enum, spdifin_source_set_enum), + #ifdef CONFIG_AMLOGIC_HDMITX SOC_SINGLE_BOOL_EXT("Audio hdmi-out mute", 0, aml_get_hdmi_out_audio, aml_set_hdmi_out_audio), #endif + + SOC_SINGLE_EXT("SPDIF CLK Fine Setting", + 0, 0, 2000000, 0, + spdif_clk_get, + spdif_clk_set), }; static bool spdifin_check_audiotype_by_sw(struct aml_spdif *p_spdif) diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index 4ed034b..1a27094 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -52,6 +52,9 @@ #define TDM_C 2 #define LANE_MAX 4 +static int aml_dai_set_tdm_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir); + static void dump_pcm_setting(struct pcm_setting *setting) { if (setting == NULL) @@ -152,6 +155,36 @@ static const struct snd_pcm_hardware aml_tdm_hardware = { .channels_max = 32, }; +static int tdm_clk_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai); + + ucontrol->value.enumerated.item[0] = clk_get_rate(p_tdm->mclk); + return 0; +} + +static int tdm_clk_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai); + + int mclk_rate = p_tdm->last_mclk_freq; + 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); + + aml_dai_set_tdm_sysclk(cpu_dai, 0, mclk_rate, 0); + + return 0; +} + static int tdmin_clk_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -182,8 +215,6 @@ static const char *const i2sin_clk[] = { "12000000" }; - - static const struct soc_enum i2sin_clk_enum[] = { SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(i2sin_clk), i2sin_clk), @@ -194,7 +225,12 @@ static const struct soc_enum i2sin_clk_enum[] = { static const struct snd_kcontrol_new snd_tdm_controls[] = { SOC_ENUM_EXT("I2SIn CLK", i2sin_clk_enum, tdmin_clk_get, - NULL) + NULL), + + SOC_SINGLE_EXT("TDM MCLK Fine Setting", + 0, 0, 2000000, 0, + tdm_clk_get, + tdm_clk_set), }; -- 2.7.4