Commit c5ab93e2 authored by Trevor Wu's avatar Trevor Wu Committed by Mark Brown

ASoC: mediatek: mt8195: update control for RT5682 series

Playback pop is observed and the root cause is the reference clock
provided by MT8195 is diabled before RT5682 finishes the control flow.

To ensure the reference clock supplied to RT5682 is disabled after RT5682
finishes all register controls. We replace BCLK with MCLK for RT5682
reference clock, and makes use of set_bias_level_post to handle MCLK
which guarantees MCLK is off after all RT5682 register access.
Signed-off-by: default avatarTrevor Wu <trevor.wu@mediatek.com>
Reviewed-by: default avatarTzung-Bi Shih <tzungbi@google.com>
Link: https://lore.kernel.org/r/20211228064821.27865-1-trevor.wu@mediatek.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 3ecb4675
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "../../codecs/rt1011.h" #include "../../codecs/rt1011.h"
#include "../../codecs/rt5682.h" #include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h" #include "../common/mtk-afe-platform-driver.h"
#include "mt8195-afe-clk.h"
#include "mt8195-afe-common.h" #include "mt8195-afe-common.h"
#define RT1011_CODEC_DAI "rt1011-aif" #define RT1011_CODEC_DAI "rt1011-aif"
...@@ -34,6 +35,7 @@ struct mt8195_mt6359_rt1011_rt5682_priv { ...@@ -34,6 +35,7 @@ struct mt8195_mt6359_rt1011_rt5682_priv {
struct snd_soc_jack headset_jack; struct snd_soc_jack headset_jack;
struct snd_soc_jack dp_jack; struct snd_soc_jack dp_jack;
struct snd_soc_jack hdmi_jack; struct snd_soc_jack hdmi_jack;
struct clk *i2so1_mclk;
}; };
static const struct snd_soc_dapm_widget static const struct snd_soc_dapm_widget
...@@ -84,8 +86,8 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, ...@@ -84,8 +86,8 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
} }
ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, RT5682_PLL1_S_BCLK1, ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, RT5682_PLL1_S_MCLK,
rate * 64, rate * 512); rate * 256, rate * 512);
if (ret) { if (ret) {
dev_err(card->dev, "failed to set pll\n"); dev_err(card->dev, "failed to set pll\n");
return ret; return ret;
...@@ -98,7 +100,7 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, ...@@ -98,7 +100,7 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
} }
return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 128, return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 256,
SND_SOC_CLOCK_OUT); SND_SOC_CLOCK_OUT);
} }
...@@ -327,8 +329,14 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) ...@@ -327,8 +329,14 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd)
struct mt8195_mt6359_rt1011_rt5682_priv *priv = struct mt8195_mt6359_rt1011_rt5682_priv *priv =
snd_soc_card_get_drvdata(rtd->card); snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_jack *jack = &priv->headset_jack; struct snd_soc_jack *jack = &priv->headset_jack;
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int ret; int ret;
priv->i2so1_mclk = afe_priv->clk[MT8195_CLK_TOP_APLL12_DIV2];
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
...@@ -562,6 +570,47 @@ static const struct snd_soc_ops mt8195_capture_ops = { ...@@ -562,6 +570,47 @@ static const struct snd_soc_ops mt8195_capture_ops = {
.startup = mt8195_capture_startup, .startup = mt8195_capture_startup,
}; };
static int mt8195_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
{
struct snd_soc_component *component = dapm->component;
struct mt8195_mt6359_rt1011_rt5682_priv *priv =
snd_soc_card_get_drvdata(card);
int ret;
/*
* It's required to control mclk directly in the set_bias_level_post
* function for rt5682 and rt5682s codec, or the unexpected pop happens
* at the end of playback.
*/
if (!component ||
(strcmp(component->name, RT5682_DEV0_NAME) &&
strcmp(component->name, RT5682S_DEV0_NAME)))
return 0;
switch (level) {
case SND_SOC_BIAS_OFF:
if (!__clk_is_enabled(priv->i2so1_mclk))
return 0;
clk_disable_unprepare(priv->i2so1_mclk);
dev_dbg(card->dev, "Disable i2so1 mclk\n");
break;
case SND_SOC_BIAS_ON:
ret = clk_prepare_enable(priv->i2so1_mclk);
if (ret) {
dev_err(card->dev, "Can't enable i2so1 mclk: %d\n", ret);
return ret;
}
dev_dbg(card->dev, "Enable i2so1 mclk\n");
break;
default:
break;
}
return 0;
}
enum { enum {
DAI_LINK_DL2_FE, DAI_LINK_DL2_FE,
DAI_LINK_DL3_FE, DAI_LINK_DL3_FE,
...@@ -1037,6 +1086,7 @@ static struct snd_soc_card mt8195_mt6359_rt1011_rt5682_soc_card = { ...@@ -1037,6 +1086,7 @@ static struct snd_soc_card mt8195_mt6359_rt1011_rt5682_soc_card = {
.num_dapm_routes = ARRAY_SIZE(mt8195_mt6359_rt1011_rt5682_routes), .num_dapm_routes = ARRAY_SIZE(mt8195_mt6359_rt1011_rt5682_routes),
.codec_conf = rt1011_amp_conf, .codec_conf = rt1011_amp_conf,
.num_configs = ARRAY_SIZE(rt1011_amp_conf), .num_configs = ARRAY_SIZE(rt1011_amp_conf),
.set_bias_level_post = mt8195_set_bias_level_post,
}; };
static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev) static int mt8195_mt6359_rt1011_rt5682_dev_probe(struct platform_device *pdev)
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "../../codecs/mt6359.h" #include "../../codecs/mt6359.h"
#include "../../codecs/rt5682.h" #include "../../codecs/rt5682.h"
#include "../common/mtk-afe-platform-driver.h" #include "../common/mtk-afe-platform-driver.h"
#include "mt8195-afe-clk.h"
#include "mt8195-afe-common.h" #include "mt8195-afe-common.h"
#define RT1019_CODEC_DAI "HiFi" #define RT1019_CODEC_DAI "HiFi"
...@@ -46,6 +47,7 @@ struct mt8195_mt6359_rt1019_rt5682_priv { ...@@ -46,6 +47,7 @@ struct mt8195_mt6359_rt1019_rt5682_priv {
struct snd_soc_jack headset_jack; struct snd_soc_jack headset_jack;
struct snd_soc_jack dp_jack; struct snd_soc_jack dp_jack;
struct snd_soc_jack hdmi_jack; struct snd_soc_jack hdmi_jack;
struct clk *i2so1_mclk;
}; };
static const struct snd_soc_dapm_widget static const struct snd_soc_dapm_widget
...@@ -92,8 +94,6 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, ...@@ -92,8 +94,6 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
unsigned int rate = params_rate(params); unsigned int rate = params_rate(params);
unsigned int mclk_fs_ratio = 128;
unsigned int mclk_fs = rate * mclk_fs_ratio;
int bitwidth; int bitwidth;
int ret; int ret;
...@@ -109,25 +109,22 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream, ...@@ -109,25 +109,22 @@ static int mt8195_rt5682_etdm_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
} }
ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL1, RT5682_PLL1_S_MCLK,
RT5682_PLL1_S_BCLK1, rate * 256, rate * 512);
params_rate(params) * 64,
params_rate(params) * 512);
if (ret) { if (ret) {
dev_err(card->dev, "failed to set pll\n"); dev_err(card->dev, "failed to set pll\n");
return ret; return ret;
} }
ret = snd_soc_dai_set_sysclk(codec_dai, ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
RT5682_SCLK_S_PLL1, rate * 512, SND_SOC_CLOCK_IN);
params_rate(params) * 512,
SND_SOC_CLOCK_IN);
if (ret) { if (ret) {
dev_err(card->dev, "failed to set sysclk\n"); dev_err(card->dev, "failed to set sysclk\n");
return ret; return ret;
} }
return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_fs, SND_SOC_CLOCK_OUT); return snd_soc_dai_set_sysclk(cpu_dai, 0, rate * 256,
SND_SOC_CLOCK_OUT);
} }
static const struct snd_soc_ops mt8195_rt5682_etdm_ops = { static const struct snd_soc_ops mt8195_rt5682_etdm_ops = {
...@@ -322,8 +319,14 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd) ...@@ -322,8 +319,14 @@ static int mt8195_rt5682_init(struct snd_soc_pcm_runtime *rtd)
struct mt8195_mt6359_rt1019_rt5682_priv *priv = struct mt8195_mt6359_rt1019_rt5682_priv *priv =
snd_soc_card_get_drvdata(rtd->card); snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_jack *jack = &priv->headset_jack; struct snd_soc_jack *jack = &priv->headset_jack;
struct snd_soc_component *cmpnt_afe =
snd_soc_rtdcom_lookup(rtd, AFE_PCM_NAME);
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt_afe);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int ret; int ret;
priv->i2so1_mclk = afe_priv->clk[MT8195_CLK_TOP_APLL12_DIV2];
ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_1 | SND_JACK_BTN_2 |
...@@ -560,6 +563,48 @@ static const struct snd_soc_ops mt8195_capture_ops = { ...@@ -560,6 +563,48 @@ static const struct snd_soc_ops mt8195_capture_ops = {
.startup = mt8195_capture_startup, .startup = mt8195_capture_startup,
}; };
static int mt8195_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
{
struct snd_soc_component *component = dapm->component;
struct mt8195_mt6359_rt1019_rt5682_priv *priv =
snd_soc_card_get_drvdata(card);
int ret;
/*
* It's required to control mclk directly in the set_bias_level_post
* function for rt5682 and rt5682s codec, or the unexpected pop happens
* at the end of playback.
*/
if (!component ||
(strcmp(component->name, RT5682_DEV0_NAME) &&
strcmp(component->name, RT5682S_DEV0_NAME)))
return 0;
switch (level) {
case SND_SOC_BIAS_OFF:
if (!__clk_is_enabled(priv->i2so1_mclk))
return 0;
clk_disable_unprepare(priv->i2so1_mclk);
dev_dbg(card->dev, "Disable i2so1 mclk\n");
break;
case SND_SOC_BIAS_ON:
ret = clk_prepare_enable(priv->i2so1_mclk);
if (ret) {
dev_err(card->dev, "Can't enable i2so1 mclk: %d\n", ret);
return ret;
}
dev_dbg(card->dev, "Enable i2so1 mclk\n");
break;
default:
break;
}
return 0;
}
enum { enum {
DAI_LINK_DL2_FE, DAI_LINK_DL2_FE,
DAI_LINK_DL3_FE, DAI_LINK_DL3_FE,
...@@ -1199,6 +1244,7 @@ static struct snd_soc_card mt8195_mt6359_rt1019_rt5682_soc_card = { ...@@ -1199,6 +1244,7 @@ static struct snd_soc_card mt8195_mt6359_rt1019_rt5682_soc_card = {
.num_dapm_widgets = ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_widgets), .num_dapm_widgets = ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_widgets),
.dapm_routes = mt8195_mt6359_rt1019_rt5682_routes, .dapm_routes = mt8195_mt6359_rt1019_rt5682_routes,
.num_dapm_routes = ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_routes), .num_dapm_routes = ARRAY_SIZE(mt8195_mt6359_rt1019_rt5682_routes),
.set_bias_level_post = mt8195_set_bias_level_post,
}; };
static int mt8195_dailink_parse_of(struct snd_soc_card *card, struct device_node *np, static int mt8195_dailink_parse_of(struct snd_soc_card *card, struct device_node *np,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment