ASoC: mediatek: mt8195: Fix clock error handling

bui duc phuc <phucduc.bui@gmail.com> says:

This series improves error handling in the MT8195 ASoC driver,
mainly by checking and propagating errors from clock operations.

Compile-tested only.

Link: https://patch.msgid.link/20261014112752.683032-1-phucduc.bui@gmail.com
This commit is contained in:
Mark Brown 2026-10-15 23:20:10 +01:00
commit 8bb6227083
No known key found for this signature in database
GPG Key ID: 2FEF73B0B3D03889
4 changed files with 221 additions and 78 deletions

View File

@ -241,21 +241,35 @@ static int mt8195_afe_enable_tuner_clk(struct mtk_base_afe *afe,
unsigned int id)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int ret;
switch (id) {
case MT8195_AUD_PLL1:
mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL]);
mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL1_TUNER]);
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL]);
if (ret)
return ret;
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL1_TUNER]);
if (ret) {
mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL]);
return ret;
}
break;
case MT8195_AUD_PLL2:
mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL2]);
mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL2_TUNER]);
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL2]);
if (ret)
return ret;
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL2_TUNER]);
if (ret) {
mt8195_afe_disable_clk(afe, afe_priv->clk[MT8195_CLK_AUD_APLL2]);
return ret;
}
break;
default:
ret = 0;
break;
}
return 0;
return ret;
}
static int mt8195_afe_disable_tuner_clk(struct mtk_base_afe *afe,
@ -383,12 +397,9 @@ int mt8195_afe_init_clock(struct mtk_base_afe *afe)
for (i = 0; i < MT8195_CLK_NUM; i++) {
afe_priv->clk[i] = devm_clk_get(afe->dev, aud_clks[i]);
if (IS_ERR(afe_priv->clk[i])) {
dev_dbg(afe->dev, "%s(), devm_clk_get %s fail, ret %ld\n",
__func__, aud_clks[i],
PTR_ERR(afe_priv->clk[i]));
return PTR_ERR(afe_priv->clk[i]);
}
if (IS_ERR(afe_priv->clk[i]))
return dev_err_probe(afe->dev, PTR_ERR(afe_priv->clk[i]),
"failed to get clock %s\n", aud_clks[i]);
}
/* initial tuner */
@ -588,7 +599,7 @@ static int mt8195_afe_disable_top_cg(struct mtk_base_afe *afe, unsigned int cg_t
int mt8195_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int i;
int i, ret;
static const unsigned int clk_array[] = {
MT8195_CLK_SCP_ADSP_AUDIODSP, /* bus clock for infra */
MT8195_CLK_TOP_AUDIO_H_SEL, /* clock for ADSP bus */
@ -600,10 +611,19 @@ int mt8195_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
MT8195_CLK_AUD_A1SYS, /* AFE HW clock */
};
for (i = 0; i < ARRAY_SIZE(clk_array); i++)
mt8195_afe_enable_clk(afe, afe_priv->clk[clk_array[i]]);
for (i = 0; i < ARRAY_SIZE(clk_array); i++) {
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[clk_array[i]]);
if (ret)
goto err_disable_clk;
}
return 0;
err_disable_clk:
while (--i >= 0)
mt8195_afe_disable_clk(afe, afe_priv->clk[clk_array[i]]);
return ret;
}
int mt8195_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
@ -642,7 +662,7 @@ static int mt8195_afe_disable_afe_on(struct mtk_base_afe *afe)
static int mt8195_afe_enable_timing_sys(struct mtk_base_afe *afe)
{
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int i;
int i, ret;
static const unsigned int clk_array[] = {
MT8195_CLK_AUD_A1SYS,
MT8195_CLK_AUD_A2SYS,
@ -653,13 +673,22 @@ static int mt8195_afe_enable_timing_sys(struct mtk_base_afe *afe)
MT8195_TOP_CG_26M_TIMING,
};
for (i = 0; i < ARRAY_SIZE(clk_array); i++)
mt8195_afe_enable_clk(afe, afe_priv->clk[clk_array[i]]);
for (i = 0; i < ARRAY_SIZE(clk_array); i++) {
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[clk_array[i]]);
if (ret)
goto err_disable_clk;
}
for (i = 0; i < ARRAY_SIZE(cg_array); i++)
mt8195_afe_enable_top_cg(afe, cg_array[i]);
return 0;
err_disable_clk:
while (--i >= 0)
mt8195_afe_disable_clk(afe, afe_priv->clk[clk_array[i]]);
return ret;
}
static int mt8195_afe_disable_timing_sys(struct mtk_base_afe *afe)
@ -687,14 +716,31 @@ static int mt8195_afe_disable_timing_sys(struct mtk_base_afe *afe)
int mt8195_afe_enable_main_clock(struct mtk_base_afe *afe)
{
mt8195_afe_enable_timing_sys(afe);
int ret;
ret = mt8195_afe_enable_timing_sys(afe);
if (ret)
return ret;
mt8195_afe_enable_afe_on(afe);
mt8195_afe_enable_apll_tuner(afe, MT8195_AUD_PLL1);
mt8195_afe_enable_apll_tuner(afe, MT8195_AUD_PLL2);
ret = mt8195_afe_enable_apll_tuner(afe, MT8195_AUD_PLL1);
if (ret)
goto err_disable_afe_on;
ret = mt8195_afe_enable_apll_tuner(afe, MT8195_AUD_PLL2);
if (ret)
goto err_disable_apll1_tuner;
return 0;
err_disable_apll1_tuner:
mt8195_afe_disable_apll_tuner(afe, MT8195_AUD_PLL1);
err_disable_afe_on:
mt8195_afe_disable_afe_on(afe);
mt8195_afe_disable_timing_sys(afe);
return ret;
}
int mt8195_afe_disable_main_clock(struct mtk_base_afe *afe)

View File

@ -286,15 +286,23 @@ mt8195_afe_paired_memif_clk_prepare(struct snd_pcm_substream *substream,
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int clk_id;
int ret;
if (id != MT8195_AFE_MEMIF_DL8 && id != MT8195_AFE_MEMIF_DL10)
return 0;
if (enable) {
clk_id = MT8195_CLK_AUD_MEMIF_DL10;
mt8195_afe_prepare_clk(afe, afe_priv->clk[clk_id]);
ret = mt8195_afe_prepare_clk(afe, afe_priv->clk[clk_id]);
if (ret)
return ret;
clk_id = MT8195_CLK_AUD_MEMIF_DL8;
mt8195_afe_prepare_clk(afe, afe_priv->clk[clk_id]);
ret = mt8195_afe_prepare_clk(afe, afe_priv->clk[clk_id]);
if (ret) {
clk_id = MT8195_CLK_AUD_MEMIF_DL10;
mt8195_afe_unprepare_clk(afe, afe_priv->clk[clk_id]);
return ret;
}
} else {
clk_id = MT8195_CLK_AUD_MEMIF_DL8;
mt8195_afe_unprepare_clk(afe, afe_priv->clk[clk_id]);
@ -315,6 +323,7 @@ mt8195_afe_paired_memif_clk_enable(struct snd_pcm_substream *substream,
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int clk_id;
int ret;
if (id != MT8195_AFE_MEMIF_DL8 && id != MT8195_AFE_MEMIF_DL10)
return 0;
@ -322,11 +331,18 @@ mt8195_afe_paired_memif_clk_enable(struct snd_pcm_substream *substream,
if (enable) {
/* DL8_DL10_MEM */
clk_id = MT8195_CLK_AUD_MEMIF_DL10;
mt8195_afe_enable_clk_atomic(afe, afe_priv->clk[clk_id]);
ret = mt8195_afe_enable_clk_atomic(afe, afe_priv->clk[clk_id]);
if (ret)
return ret;
udelay(1);
/* DL8_DL10_AGENT */
clk_id = MT8195_CLK_AUD_MEMIF_DL8;
mt8195_afe_enable_clk_atomic(afe, afe_priv->clk[clk_id]);
ret = mt8195_afe_enable_clk_atomic(afe, afe_priv->clk[clk_id]);
if (ret) {
clk_id = MT8195_CLK_AUD_MEMIF_DL10;
mt8195_afe_disable_clk_atomic(afe, afe_priv->clk[clk_id]);
return ret;
}
} else {
/* DL8_DL10_AGENT */
clk_id = MT8195_CLK_AUD_MEMIF_DL8;
@ -348,24 +364,38 @@ static int mt8195_afe_fe_startup(struct snd_pcm_substream *substream,
int id = snd_soc_rtd_to_cpu(rtd, 0)->id;
int ret = 0;
mt8195_afe_paired_memif_clk_prepare(substream, dai, 1);
ret = mt8195_afe_paired_memif_clk_prepare(substream, dai, 1);
if (ret)
return ret;
ret = mtk_afe_fe_startup(substream, dai);
snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
MT8195_MEMIF_BUFFER_BYTES_ALIGN);
if (id != MT8195_AFE_MEMIF_DL7)
goto out;
ret = snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1,
MT8195_MEMIF_DL7_MAX_PERIOD_SIZE);
if (ret < 0)
dev_dbg(afe->dev, "hw_constraint_minmax failed\n");
out:
goto err_clk_unprepare;
ret = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
MT8195_MEMIF_BUFFER_BYTES_ALIGN);
if (ret)
goto err_fe_shutdow;
if (id == MT8195_AFE_MEMIF_DL7) {
ret = snd_pcm_hw_constraint_minmax(runtime,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
1,
MT8195_MEMIF_DL7_MAX_PERIOD_SIZE);
if (ret < 0) {
dev_dbg(afe->dev, "hw_constraint_minmax failed\n");
goto err_fe_shutdow;
}
}
return 0;
err_fe_shutdow:
mtk_afe_fe_shutdown(substream, dai);
err_clk_unprepare:
mt8195_afe_paired_memif_clk_prepare(substream, dai, 0);
return ret;
}
@ -436,7 +466,14 @@ static int mt8195_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
mt8195_afe_paired_memif_clk_enable(substream, dai, 1);
if (ret)
break;
ret = mt8195_afe_paired_memif_clk_enable(substream, dai, 1);
if (ret) {
mtk_afe_fe_trigger(substream, SNDRV_PCM_TRIGGER_STOP, dai);
mt8195_afe_enable_cm(afe, cm, false);
}
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
@ -2928,18 +2965,31 @@ static int mt8195_afe_runtime_resume(struct device *dev)
{
struct mtk_base_afe *afe = dev_get_drvdata(dev);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int ret;
mt8195_afe_enable_reg_rw_clk(afe);
ret = mt8195_afe_enable_reg_rw_clk(afe);
if (ret)
return ret;
if (!afe->regmap || afe_priv->pm_runtime_bypass_reg_ctl)
goto skip_regmap;
return 0;
regcache_cache_only(afe->regmap, false);
regcache_sync(afe->regmap);
ret = regcache_sync(afe->regmap);
if (ret)
goto err_restore_cache;
ret = mt8195_afe_enable_main_clock(afe);
if (ret)
goto err_restore_cache;
mt8195_afe_enable_main_clock(afe);
skip_regmap:
return 0;
err_restore_cache:
regcache_cache_only(afe->regmap, true);
mt8195_afe_disable_reg_rw_clk(afe);
return ret;
}
static int init_memif_priv_data(struct mtk_base_afe *afe)
@ -3040,7 +3090,7 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
/* initial audio related clock */
ret = mt8195_afe_init_clock(afe);
if (ret)
return dev_err_probe(dev, ret, "init clock error\n");
return ret;
/* reset controller to reset audio regs before regmap cache */
rstc = devm_reset_control_get_exclusive(dev, "audiosys");
@ -3082,12 +3132,12 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
/* request irq */
irq_id = platform_get_irq(pdev, 0);
if (irq_id < 0)
return -ENXIO;
return irq_id;
ret = devm_request_irq(dev, irq_id, mt8195_afe_irq_handler,
IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
if (ret)
return dev_err_probe(dev, ret, "could not request_irq for asys-isr\n");
return ret;
/* init sub_dais */
INIT_LIST_HEAD(&afe->sub_dais);
@ -3145,10 +3195,9 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
/* register component */
ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
afe->dai_drivers, afe->num_dai_drivers);
if (ret) {
dev_warn(dev, "err_platform\n");
if (ret)
goto err_pm_put;
}
ret = regmap_multi_reg_write(afe->regmap, mt8195_afe_reg_defaults,
ARRAY_SIZE(mt8195_afe_reg_defaults));

View File

@ -262,9 +262,8 @@ static int mtk_audio_hires_event(struct snd_soc_dapm_widget *w,
default:
return 0;
}
mt8195_afe_set_clk_parent(afe, clk, clk_parent);
return 0;
return mt8195_afe_set_clk_parent(afe, clk, clk_parent);
}
static struct mtk_dai_adda_priv *get_adda_priv_by_name(struct mtk_base_afe *afe,

View File

@ -1549,9 +1549,7 @@ static int mtk_dai_etdm_enable_mclk(struct mtk_base_afe *afe, int dai_id)
if (clkdiv_id < 0)
return -EINVAL;
mt8195_afe_enable_clk(afe, afe_priv->clk[clkdiv_id]);
return 0;
return mt8195_afe_enable_clk(afe, afe_priv->clk[clkdiv_id]);
}
static int mtk_dai_etdm_disable_mclk(struct mtk_base_afe *afe, int dai_id)
@ -1577,36 +1575,66 @@ static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream,
int cg_id;
int mst_dai_id;
int slv_dai_id;
int i;
int i, ret;
if (is_cowork_mode(dai)) {
mst_dai_id = get_etdm_cowork_master_id(dai);
if (!mt8195_afe_etdm_is_valid(mst_dai_id))
return -EINVAL;
mtk_dai_etdm_enable_mclk(afe, mst_dai_id);
ret = mtk_dai_etdm_enable_mclk(afe, mst_dai_id);
if (ret)
return ret;
cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id);
if (cg_id >= 0)
mt8195_afe_enable_clk(afe, afe_priv->clk[cg_id]);
if (cg_id >= 0) {
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[cg_id]);
if (ret)
goto err_disable_mclk;
}
mst_etdm_data = afe_priv->dai_priv[mst_dai_id];
for (i = 0; i < mst_etdm_data->cowork_slv_count; i++) {
slv_dai_id = mst_etdm_data->cowork_slv_id[i];
cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id);
if (cg_id >= 0)
mt8195_afe_enable_clk(afe,
afe_priv->clk[cg_id]);
if (cg_id >= 0) {
ret = mt8195_afe_enable_clk(afe,
afe_priv->clk[cg_id]);
if (ret)
goto err_disable_slv_clk;
}
}
} else {
mtk_dai_etdm_enable_mclk(afe, dai->id);
ret = mtk_dai_etdm_enable_mclk(afe, dai->id);
if (ret)
return ret;
cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
if (cg_id >= 0)
mt8195_afe_enable_clk(afe, afe_priv->clk[cg_id]);
if (cg_id >= 0) {
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[cg_id]);
if (ret)
goto err_disable_mclk;
}
}
return 0;
err_disable_slv_clk:
while (--i >= 0) {
slv_dai_id = mst_etdm_data->cowork_slv_id[i];
cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(slv_dai_id);
if (cg_id >= 0)
mt8195_afe_disable_clk(afe, afe_priv->clk[cg_id]);
}
cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(mst_dai_id);
if (cg_id >= 0)
mt8195_afe_disable_clk(afe, afe_priv->clk[cg_id]);
err_disable_mclk:
mtk_dai_etdm_disable_mclk(afe, is_cowork_mode(dai) ? mst_dai_id : dai->id);
return ret;
}
static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream,
@ -2293,13 +2321,25 @@ static int mtk_dai_hdmitx_dptx_startup(struct snd_pcm_substream *substream,
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
int cg_id = mtk_dai_etdm_get_cg_id_by_dai_id(dai->id);
int ret;
if (cg_id >= 0)
mt8195_afe_enable_clk(afe, afe_priv->clk[cg_id]);
if (cg_id >= 0) {
ret = mt8195_afe_enable_clk(afe, afe_priv->clk[cg_id]);
if (ret)
return ret;
}
mtk_dai_etdm_enable_mclk(afe, dai->id);
ret = mtk_dai_etdm_enable_mclk(afe, dai->id);
if (ret)
goto err_disable_cg_clk;
return 0;
err_disable_cg_clk:
if (cg_id >= 0)
mt8195_afe_disable_clk(afe, afe_priv->clk[cg_id]);
return ret;
}
static void mtk_dai_hdmitx_dptx_shutdown(struct snd_pcm_substream *substream,
@ -2463,6 +2503,7 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai)
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
struct mt8195_afe_private *afe_priv = afe->platform_priv;
struct mtk_dai_etdm_priv *etdm_data;
int ret;
dev_dbg(dai->dev, "%s id %d\n", __func__, dai->id);
@ -2470,15 +2511,23 @@ static int mtk_dai_etdm_probe(struct snd_soc_dai *dai)
return -EINVAL;
etdm_data = afe_priv->dai_priv[dai->id];
if (etdm_data->mclk_freq) {
dev_dbg(afe->dev, "MCLK always on, rate %d\n",
etdm_data->mclk_freq);
pm_runtime_get_sync(afe->dev);
mtk_dai_etdm_mclk_configure(afe, dai->id);
mtk_dai_etdm_enable_mclk(afe, dai->id);
pm_runtime_put_sync(afe->dev);
}
return 0;
if (!etdm_data->mclk_freq)
return 0;
dev_dbg(afe->dev, "MCLK always on, rate %d\n",
etdm_data->mclk_freq);
ret = pm_runtime_resume_and_get(afe->dev);
if (ret)
return ret;
ret = mtk_dai_etdm_mclk_configure(afe, dai->id);
if (ret)
goto err_put_pm;
ret = mtk_dai_etdm_enable_mclk(afe, dai->id);
err_put_pm:
pm_runtime_put_sync(afe->dev);
return ret;
}
static const struct snd_soc_dai_ops mtk_dai_hdmitx_dptx_ops = {