Use the MCLK to solve audio quality issues found on some Cherryview-based platforms
Signed-off-by: Pietro Di Costanzo pxpert@gmail.com --- sound/soc/intel/boards/bytcr_rt5651.c | 84 +++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 9 deletions(-)
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 35f591e..e51ea5b 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -31,11 +31,76 @@ #include "../../codecs/rt5651.h" #include "../atom/sst-atom-controls.h"
+#define CHT_PLAT_CLK_3_HZ 19200000 +#define CHT_CODEC_DAI_5651 "rt5651-aif1" + +struct cht_acpi_card { + char *codec_id; + int codec_type; + struct snd_soc_card *soc_card; +}; + +struct cht_mc_private { + struct snd_soc_jack jack; + struct cht_acpi_card *acpi_card; +}; + + +static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI_5651, + strlen(CHT_CODEC_DAI_5651))) + return rtd->codec_dai; + } + return NULL; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = cht_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); + return -EIO; + } + + if (!SND_SOC_DAPM_EVENT_OFF(event)) + return 0; + + /* Set codec sysclk source to its internal clock because codec PLL will + * be off when idle and MCLK will also be off by ACPI when codec is + * runtime suspended. Codec needs clock for jack detection and button + * press. + */ + ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_RCCLK, + 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "can't set codec sysclk: %d\n", ret); + return ret; + } + + return 0; +} + + + + static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Internal Mic", NULL), SND_SOC_DAPM_SPK("Speaker", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_POST_PMD), + };
static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { @@ -52,6 +117,9 @@ static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { {"Headphone", NULL, "HPOR"}, {"Speaker", NULL, "LOUTL"}, {"Speaker", NULL, "LOUTR"}, + {"Headphone", NULL, "Platform Clock"}, + {"Speaker", NULL, "Platform Clock"}, + };
static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = { @@ -93,7 +161,13 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; int ret;
- snd_soc_dai_set_bclk_ratio(codec_dai, 50); + /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_MCLK, + CHT_PLAT_CLK_3_HZ, params_rate(params) * 512); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + }
ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1, params_rate(params) * 512, @@ -103,14 +177,6 @@ static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, return ret; }
- ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1, - params_rate(params) * 50, - params_rate(params) * 512); - if (ret < 0) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); - return ret; - } - return 0; }