mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
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:
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user