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 <Zhe.Wang@amlogic.com>

Conflicts:
	sound/soc/amlogic/auge/tdm.c
This commit is contained in:
Zhe Wang
2019-03-25 19:53:30 +08:00
committed by Dongjin Kim
parent 8aa35da1e3
commit b93b3cdfb8
3 changed files with 132 additions and 5 deletions

View File

@@ -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",

View File

@@ -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)

View File

@@ -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;