From b93b3cdfb8d8b19d5dc1a8d74e1b3ef3085df059 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 Conflicts: sound/soc/amlogic/auge/tdm.c --- sound/soc/amlogic/auge/audio_utils.c | 5 +- sound/soc/amlogic/auge/spdif.c | 51 ++++++++++++++++-- sound/soc/amlogic/auge/tdm.c | 81 ++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 5 deletions(-) diff --git a/sound/soc/amlogic/auge/audio_utils.c b/sound/soc/amlogic/auge/audio_utils.c index 16943bc3b841..ac18fb09f4c3 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 708d068b366f..b2f646f6dc27 100644 --- a/sound/soc/amlogic/auge/spdif.c +++ b/sound/soc/amlogic/auge/spdif.c @@ -51,6 +51,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 { enum SPDIF_ID id; @@ -357,16 +360,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, @@ -376,15 +412,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 3b368737368b..2b21e3bf03bf 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -53,6 +53,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) @@ -153,6 +156,84 @@ 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) +{ + int clk; + int value; + + clk = meson_clk_measure(70); + if (clk >= 11000000) + value = 3; + else if (clk >= 6000000) + value = 2; + else if (clk >= 2000000) + value = 1; + else + value = 0; + + + ucontrol->value.integer.value[0] = value; + + return 0; +} + +/* current sample mode and its sample rate */ +static const char *const i2sin_clk[] = { + "0", + "3000000", + "6000000", + "12000000" +}; + +static const struct soc_enum i2sin_clk_enum[] = { + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(i2sin_clk), + i2sin_clk), +}; + + + +static const struct snd_kcontrol_new snd_tdm_controls[] = { + SOC_ENUM_EXT("I2SIn CLK", i2sin_clk_enum, + tdmin_clk_get, + NULL), + + SOC_SINGLE_EXT("TDM MCLK Fine Setting", + 0, 0, 2000000, 0, + tdm_clk_get, + tdm_clk_set), +}; + static irqreturn_t aml_tdm_ddr_isr(int irq, void *devid) { struct snd_pcm_substream *substream = (struct snd_pcm_substream *)devid;