ASoC: tlv320aic31xx: Fix master mode clock I2S bus clocks
In the reset state of the codec we do not have complete playback or capture routes. The audio playback/capture will not work due to missing clock signals on the I2S bus if PLL, MDAC/NDAC/DAC MADC/NADC/ADC is powered down. To make sure that even if all output/input is disconnected the codec is generating clocks, we need to have valid DAPM route in every case to power up the must needed parts of the codec. I have verified that switching DAC (during playback) or ADC (during capture) will stop the I2S clocks, so the only solution is to connect the 'Off' routes as well to output/input. The routes will be only added if the codec is clock master. In case the role changes runtime, the applied routes are removed. Tested on am43x-epos-evm with aic3111 codec in master mode. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Reviewed-by: Jyri Sarha <jsarha@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Родитель
f2e6f95b4b
Коммит
d460b3f861
|
@ -166,6 +166,7 @@ struct aic31xx_priv {
|
|||
unsigned int sysclk;
|
||||
u8 p_div;
|
||||
int rate_div_line;
|
||||
bool master_dapm_route_applied;
|
||||
};
|
||||
|
||||
struct aic31xx_rate_divs {
|
||||
|
@ -670,6 +671,29 @@ aic310x_audio_map[] = {
|
|||
{"SPK", NULL, "SPK ClassD"},
|
||||
};
|
||||
|
||||
/*
|
||||
* Always connected DAPM routes for codec clock master modes.
|
||||
* If the codec is the master on the I2S bus, we need to power on components
|
||||
* to have valid DAC_CLK and also the DACs and ADC for playback/capture.
|
||||
* Otherwise the codec will not generate clocks on the bus.
|
||||
*/
|
||||
static const struct snd_soc_dapm_route
|
||||
common31xx_cm_audio_map[] = {
|
||||
{"DAC Left Input", "Off", "DAC IN"},
|
||||
{"DAC Right Input", "Off", "DAC IN"},
|
||||
|
||||
{"HPL", NULL, "DAC Left"},
|
||||
{"HPR", NULL, "DAC Right"},
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route
|
||||
aic31xx_cm_audio_map[] = {
|
||||
{"MIC1LP P-Terminal", "Off", "MIC1LP"},
|
||||
{"MIC1RP P-Terminal", "Off", "MIC1RP"},
|
||||
{"MIC1LM P-Terminal", "Off", "MIC1LM"},
|
||||
{"MIC1LM M-Terminal", "Off", "MIC1LM"},
|
||||
};
|
||||
|
||||
static int aic31xx_add_controls(struct snd_soc_component *component)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -912,6 +936,53 @@ static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int aic31xx_clock_master_routes(struct snd_soc_component *component,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
|
||||
struct aic31xx_priv *aic31xx = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
fmt &= SND_SOC_DAIFMT_MASTER_MASK;
|
||||
if (fmt == SND_SOC_DAIFMT_CBS_CFS &&
|
||||
aic31xx->master_dapm_route_applied) {
|
||||
/*
|
||||
* Remove the DAPM route(s) for codec clock master modes,
|
||||
* if applied
|
||||
*/
|
||||
ret = snd_soc_dapm_del_routes(dapm, common31xx_cm_audio_map,
|
||||
ARRAY_SIZE(common31xx_cm_audio_map));
|
||||
if (!ret && !(aic31xx->codec_type & DAC31XX_BIT))
|
||||
ret = snd_soc_dapm_del_routes(dapm,
|
||||
aic31xx_cm_audio_map,
|
||||
ARRAY_SIZE(aic31xx_cm_audio_map));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
aic31xx->master_dapm_route_applied = false;
|
||||
} else if (fmt != SND_SOC_DAIFMT_CBS_CFS &&
|
||||
!aic31xx->master_dapm_route_applied) {
|
||||
/*
|
||||
* Add the needed DAPM route(s) for codec clock master modes,
|
||||
* if it is not done already
|
||||
*/
|
||||
ret = snd_soc_dapm_add_routes(dapm, common31xx_cm_audio_map,
|
||||
ARRAY_SIZE(common31xx_cm_audio_map));
|
||||
if (!ret && !(aic31xx->codec_type & DAC31XX_BIT))
|
||||
ret = snd_soc_dapm_add_routes(dapm,
|
||||
aic31xx_cm_audio_map,
|
||||
ARRAY_SIZE(aic31xx_cm_audio_map));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
aic31xx->master_dapm_route_applied = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
|
@ -992,7 +1063,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
AIC31XX_BCLKINV_MASK,
|
||||
iface_reg2);
|
||||
|
||||
return 0;
|
||||
return aic31xx_clock_master_routes(component, fmt);
|
||||
}
|
||||
|
||||
static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
|
|
Загрузка…
Ссылка в новой задаче