ASoC: mediatek: mt8186: Fix clock error handling
Subsystems (3)
cover ASoC: mediatek: mt8186: Fix clock error handling
From: bui duc phuc <[email protected]>
Hi all,
This series fixes error handling in the MT8186 AFE clock code.
The current code can return from clock operations without cleaning up clocks that were already enabled, and can ignore clock lookup errors while later using the affected clock pointers.
This series keeps devm_clk_get() and propagates clock lookup errors instead of silently continuing with a NULL clock.
The changes therefore assume that the clocks used by the driver are required. If these clocks are intended to be optional and devm_clk_get_optional() is preferred, the clock users would also need to check for missing clocks before calling clock APIs such as clk_prepare_enable(), clk_disable_unprepare(), and clk_set_parent().
If that is the preferred approach, I can rework the series accordingly.
The changes were found by manual code inspection and compile-tested only.
Best regards,
Phuc
bui duc phuc (5):
ASoC: mediatek: mt8186: fix APLL mux setting error handling
ASoC: mediatek: mt8186: Fix AFE clock error handling
ASoC: mediatek: mt8186: Fix APLL enable error handling
ASoC: mediatek: mt8186: Fix MCK error handling
ASoC: mediatek: mt8186: Propagate clock lookup errors
sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 112 ++++++++++++++------- 1 file changed, 74 insertions(+), 38 deletions(-)
Signature · 1 line
2.43.0
PATCH 1/5 ASoC: mediatek: mt8186: fix APLL mux setting error handling
From: bui duc phuc <[email protected]>
The APLL mux setup functions return immediately when a clock operation fails, without undoing the clock changes already made. This can leave clocks enabled or muxes configured to an unexpected parent.
Restore the affected muxes to CLK26M and disable previously enabled clocks on error before propagating the original error.
--- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 50 ++++++++++++++++------ 1 file changed, 38 insertions(+), 12 deletions(-)
sound/soc/mediatek/mt8186/mt8186-afe-clk.c +38 -12
@@ -98,7 +98,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)if (ret) {dev_err (afe->dev,"%s clk_prepare_enable %s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_1 ], ret); -return ret; + goto ERR_ENABLE_CLK_TOP_MUX_AUD_1; } ret =clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_1 ], afe_priv->clk[CLK_TOP_APLL1_CK ]);
@@ -106,7 +106,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_1 ], aud_clks[CLK_TOP_APLL1_CK ], ret); -return ret; + goto ERR_SELECT_CLK_TOP_MUX_AUD_1; }/* 180.6336 / 8 = 22.5792MHz */
@@ -114,7 +114,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)if (ret) {dev_err (afe->dev,"%s clk_prepare_enable %s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1 ], ret); -return ret; + goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1; } ret =clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_ENG1 ], afe_priv->clk[CLK_TOP_APLL1_D8 ]);
@@ -122,7 +122,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1 ], aud_clks[CLK_TOP_APLL1_D8 ], ret); -return ret; + goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG1; } }else { ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG1],
@@ -131,7 +131,7 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_ENG1 ], aud_clks[CLK_CLK26M ], ret); -return ret; + goto EXIT; }clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_ENG1 ]);
@@ -141,12 +141,25 @@ static int apll1_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_1 ], aud_clks[CLK_CLK26M ], ret); -return ret; + goto EXIT; }clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_1 ]); }return 0 ; + +ERR_SELECT_CLK_TOP_MUX_AUD_ENG1: +clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_ENG1 ], + afe_priv->clk[CLK_CLK26M ]); +clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_ENG1 ]); +ERR_ENABLE_CLK_TOP_MUX_AUD_ENG1: +ERR_SELECT_CLK_TOP_MUX_AUD_1: +clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_1 ], + afe_priv->clk[CLK_CLK26M ]); +clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_1 ]); +ERR_ENABLE_CLK_TOP_MUX_AUD_1: +EXIT: +return ret; }static int apll2_mux_setting (struct mtk_base_afe *afe,bool enable)
@@ -159,7 +172,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)if (ret) {dev_err (afe->dev,"%s clk_prepare_enable %s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_2 ], ret); -return ret; + goto ERR_ENABLE_CLK_TOP_MUX_AUD_2; } ret =clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_2 ], afe_priv->clk[CLK_TOP_APLL2_CK ]);
@@ -167,7 +180,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_2 ], aud_clks[CLK_TOP_APLL2_CK ], ret); -return ret; + goto ERR_SELECT_CLK_TOP_MUX_AUD_2; }/* 196.608 / 8 = 24.576MHz */
@@ -175,7 +188,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)if (ret) {dev_err (afe->dev,"%s clk_prepare_enable %s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2 ], ret); -return ret; + goto ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2; } ret =clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_ENG2 ], afe_priv->clk[CLK_TOP_APLL2_D8 ]);
@@ -183,7 +196,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2 ], aud_clks[CLK_TOP_APLL2_D8 ], ret); -return ret; + goto ERR_SELECT_CLK_TOP_MUX_AUD_ENG2; } }else { ret = clk_set_parent(afe_priv->clk[CLK_TOP_MUX_AUD_ENG2],
@@ -192,7 +205,7 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_ENG2 ], aud_clks[CLK_CLK26M ], ret); -return ret; + goto EXIT; }clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_ENG2 ]);
@@ -202,12 +215,25 @@ static int apll2_mux_setting(struct mtk_base_afe *afe, bool enable)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_TOP_MUX_AUD_2 ], aud_clks[CLK_CLK26M ], ret); -return ret; + goto EXIT; }clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_2 ]); }return 0 ; + +ERR_SELECT_CLK_TOP_MUX_AUD_ENG2: +clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_ENG2 ], + afe_priv->clk[CLK_CLK26M ]); +clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_ENG2 ]); +ERR_ENABLE_CLK_TOP_MUX_AUD_ENG2: +ERR_SELECT_CLK_TOP_MUX_AUD_2: +clk_set_parent (afe_priv->clk[CLK_TOP_MUX_AUD_2 ], + afe_priv->clk[CLK_CLK26M ]); +clk_disable_unprepare (afe_priv->clk[CLK_TOP_MUX_AUD_2 ]); +ERR_ENABLE_CLK_TOP_MUX_AUD_2: +EXIT: +return ret; }int mt8186_afe_enable_cgs (struct mtk_base_afe *afe)
Signature · 1 line
2.43.0
PATCH 2/5 ASoC: mediatek: mt8186: Fix AFE clock error handling
In reply to [email protected]From: bui duc phuc <[email protected]>
The error paths in mt8186_afe_enable_clock() do not consistently undo the clock operations performed before an error.
Fix the goto targets and cleanup order so that the audio internal bus parent is restored to CLK26M and all previously enabled clocks are disabled before returning the error.
--- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-)
sound/soc/mediatek/mt8186/mt8186-afe-clk.c +8 -10
@@ -294,7 +294,7 @@ int mt8186_afe_enable_clock(struct mtk_base_afe *afe)dev_err (afe->dev,"%s clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[CLK_MUX_AUDIO ], aud_clks[CLK_CLK26M ], ret); - goto clk_mux_audio_err; + goto clk_mux_audio_intbus_err; } ret =clk_prepare_enable (afe_priv->clk[CLK_MUX_AUDIOINTBUS ]);
@@ -321,24 +321,22 @@ int mt8186_afe_enable_clock(struct mtk_base_afe *afe)if (ret) {dev_err (afe->dev,"%s clk_prepare_enable %s fail %d\n" , __func__, aud_clks[CLK_AFE ], ret); - goto clk_afe_err; + goto clk_mux_audio_h_parent_err; }return 0 ; -clk_afe_err: -clk_disable_unprepare (afe_priv->clk[CLK_AFE ]); clk_mux_audio_h_parent_err: +mt8186_set_audio_int_bus_parent (afe,CLK_CLK26M ); clk_mux_audio_intbus_parent_err: -mt8186_set_audio_int_bus_parent (afe,CLK_CLK26M ); +clk_disable_unprepare (afe_priv->clk[CLK_MUX_AUDIOINTBUS ]); clk_mux_audio_intbus_err: -clk_disable_unprepare (afe_priv->clk[CLK_MUX_AUDIOINTBUS ]); +clk_disable_unprepare (afe_priv->clk[CLK_MUX_AUDIO ]); clk_mux_audio_err: -clk_disable_unprepare (afe_priv->clk[CLK_MUX_AUDIO ]); -clk_infra_sys_audio_err: -clk_disable_unprepare (afe_priv->clk[CLK_INFRA_SYS_AUDIO ]); +clk_disable_unprepare (afe_priv->clk[CLK_INFRA_AUDIO_26M ]); clk_infra_audio_26m_err: -clk_disable_unprepare (afe_priv->clk[CLK_INFRA_AUDIO_26M ]); +clk_disable_unprepare (afe_priv->clk[CLK_INFRA_SYS_AUDIO ]); +clk_infra_sys_audio_err:return ret; }
Signature · 1 line
2.43.0
PATCH 3/5 ASoC: mediatek: mt8186: Fix APLL enable error handling
In reply to [email protected]From: bui duc phuc <[email protected]>
Currently, the mt8186_apll*_enable() functions call mux_setting(afe, true) but do not check its return value to handle failures.
In addition, the cleanup paths of mt8186_apll*_enable() do not call mux_setting(afe, false) when the enable operation fails, while the mt8186_apll*_disable() functions do.
Add error handling for apll*_mux_setting() and call mux_setting(afe, false) in the cleanup paths when mt8186_apll*_enable() fails.
--- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
sound/soc/mediatek/mt8186/mt8186-afe-clk.c +12 -6
@@ -359,7 +359,9 @@ int mt8186_apll1_enable(struct mtk_base_afe *afe)int ret;/* setting for APLL */ -apll1_mux_setting (afe, true); + ret =apll1_mux_setting (afe, true); +if (ret) + goto err_apll1_mux_setting; ret =clk_prepare_enable (afe_priv->clk[CLK_APLL22M ]);if (ret) {
@@ -384,9 +386,10 @@ int mt8186_apll1_enable(struct mtk_base_afe *afe)return 0 ; err_clk_apll1_tuner: -clk_disable_unprepare (afe_priv->clk[CLK_APLL1_TUNER ]); +clk_disable_unprepare (afe_priv->clk[CLK_APLL22M ]); err_clk_apll22m: -clk_disable_unprepare (afe_priv->clk[CLK_APLL22M ]); +apll1_mux_setting (afe, false); +err_apll1_mux_setting:return ret; }
@@ -412,7 +415,9 @@ int mt8186_apll2_enable(struct mtk_base_afe *afe)int ret;/* setting for APLL */ -apll2_mux_setting (afe, true); + ret =apll2_mux_setting (afe, true); +if (ret) + goto err_apll2_mux_setting; ret =clk_prepare_enable (afe_priv->clk[CLK_APLL24M ]);if (ret) {
@@ -437,9 +442,10 @@ int mt8186_apll2_enable(struct mtk_base_afe *afe)return 0 ; err_clk_apll2_tuner: -clk_disable_unprepare (afe_priv->clk[CLK_APLL2_TUNER ]); +clk_disable_unprepare (afe_priv->clk[CLK_APLL24M ]); err_clk_apll24m: -clk_disable_unprepare (afe_priv->clk[CLK_APLL24M ]); +apll2_mux_setting (afe, false); +err_apll2_mux_setting:return ret; }
Signature · 1 line
2.43.0
PATCH 4/5 ASoC: mediatek: mt8186: Fix MCK error handling
In reply to [email protected]From: bui duc phuc <[email protected]>
The mt8186_mck_enable() function returns immediately when a clock operation fails, leaving previously enabled clocks active.
Add error paths to disable previously enabled clocks before returning the error.
--- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
sound/soc/mediatek/mt8186/mt8186-afe-clk.c +13 -4
@@ -528,7 +528,7 @@ int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)if (ret) {dev_err (afe->dev,"%s(), clk_prepare_enable %s fail %d\n" , __func__, aud_clks[m_sel_id], ret); -return ret; + goto ERR_ENABLE_MCLK; } ret =clk_set_parent (afe_priv->clk[m_sel_id], afe_priv->clk[apll_clk_id]);
@@ -536,7 +536,7 @@ int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)dev_err (afe->dev,"%s(), clk_set_parent %s-%s fail %d\n" , __func__, aud_clks[m_sel_id], aud_clks[apll_clk_id], ret); -return ret; + goto ERR_SELECT_MCLK; } }
@@ -545,16 +545,25 @@ int mt8186_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)if (ret) {dev_err (afe->dev,"%s(), clk_prepare_enable %s fail %d\n" , __func__, aud_clks[div_clk_id], ret); -return ret; + goto ERR_ENABLE_MCLK_DIV; } ret =clk_set_rate (afe_priv->clk[div_clk_id], rate);if (ret) {dev_err (afe->dev,"%s(), clk_set_rate %s, rate %d, fail %d\n" , __func__, aud_clks[div_clk_id], rate, ret); -return ret; + goto ERR_SET_MCLK_RATE; }return 0 ; + +ERR_SET_MCLK_RATE: +clk_disable_unprepare (afe_priv->clk[div_clk_id]); +ERR_ENABLE_MCLK_DIV: +ERR_SELECT_MCLK: +if (m_sel_id >=0 ) +clk_disable_unprepare (afe_priv->clk[m_sel_id]); +ERR_ENABLE_MCLK: +return ret; }void mt8186_mck_disable (struct mtk_base_afe *afe,int mck_id)
Signature · 1 line
2.43.0
PATCH 5/5 ASoC: mediatek: mt8186: Propagate clock lookup errors
In reply to [email protected]From: bui duc phuc <[email protected]>
The driver currently clears the clock pointer when devm_clk_get() fails and continues initialization. The clock operations later in the driver do not check for missing clocks before using them.
Return the error from devm_clk_get() instead of continuing with an invalid clock state. Use dev_err_probe() to report the error while preserving the original error code.
--- sound/soc/mediatek/mt8186/mt8186-afe-clk.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
sound/soc/mediatek/mt8186/mt8186-afe-clk.c +3 -6
@@ -592,12 +592,9 @@ int mt8186_init_clock(struct mtk_base_afe *afe)for (i =0 ; i <CLK_NUM ; i++) { afe_priv->clk[i] =devm_clk_get (afe->dev, aud_clks[i]); -if (IS_ERR (afe_priv->clk[i])) { -dev_err (afe->dev,"%s devm_clk_get %s fail, ret %ld\n" , - __func__, - aud_clks[i],PTR_ERR (afe_priv->clk[i])); - afe_priv->clk[i] =NULL ; - } +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]); } afe_priv->apmixedsys = syscon_regmap_lookup_by_phandle(of_node,
Signature · 1 line
2.43.0
Quoted 7 lines
The changes therefore assume that the clocks used by the driver are required. If these clocks are intended to be optional and
devm_clk_get_optional()is preferred, the clock users would also need to check for missing clocks before calling clock APIs such asclk_prepare_enable(),clk_disable_unprepare(), andclk_set_parent().If that is the preferred approach, I can rework the series accordingly.
I apologize for the confusion. clk_prepare_enable(), clk_disable_unprepare(), and clk_set_parent() already handle missing clocks and return 0 in that case.
So I only need to confirm whether an optional clock is intended to be used here, so that I can revise the patch series accordingly.
Best regards,
Phuc