[PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control
AngeloGioacchino Del Regno
angelogioacchino.delregno at collabora.com
Thu May 15 01:30:26 PDT 2025
Il 14/05/25 10:11, Darren.Ye ha scritto:
> From: Darren Ye <darren.ye at mediatek.com>
>
> Add audio clock wrapper and audio tuner control.
>
> Signed-off-by: Darren Ye <darren.ye at mediatek.com>
> ---
> sound/soc/mediatek/mt8196/mt8196-afe-clk.c | 723 ++++++++++++++++++
> sound/soc/mediatek/mt8196/mt8196-afe-clk.h | 142 ++++
> sound/soc/mediatek/mt8196/mt8196-audsys-clk.c | 252 ++++++
> sound/soc/mediatek/mt8196/mt8196-audsys-clk.h | 14 +
> .../soc/mediatek/mt8196/mt8196-audsys-clkid.h | 78 ++
> 5 files changed, 1209 insertions(+)
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clk.h
> create mode 100644 sound/soc/mediatek/mt8196/mt8196-audsys-clkid.h
>
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.c b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> new file mode 100644
> index 000000000000..83b5ee9d30ef
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.c
> @@ -0,0 +1,723 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * mt8196-afe-clk.c -- Mediatek 8196 afe clock ctrl
mt8196-afe-clk.c - MediaTek MT8196 AFE Clock Control
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye at mediatek.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include "mt8196-afe-common.h"
> +#include "mt8196-audsys-clk.h"
> +#include "mt8196-afe-clk.h"
> +
..snip..
> +
> +static int mt8196_afe_disable_apll(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret = 0;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + if (ret)
> + return ret;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> + if (ret)
> + goto clk_ck_mux_aud1_err;
> +
> + ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
> + afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
> + if (ret)
> + goto clk_ck_mux_aud1_parent_err;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> + if (ret)
> + goto clk_ck_mux_aud2_err;
> +
> + ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2],
> + afe_priv->clk[MT8196_CLK_TOP_CLK26M]);
> + if (ret)
> + goto clk_ck_mux_aud2_parent_err;
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + return 0;
> +
> +clk_ck_mux_aud2_parent_err:
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_2]);
> +clk_ck_mux_aud2_err:
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1],
> + afe_priv->clk[MT8196_CLK_TOP_APLL1_CK]);
> +clk_ck_mux_aud1_parent_err:
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_MUX_AUD_1]);
> +clk_ck_mux_aud1_err:
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> +
> + return ret;
> +}
> +
> +static void mt8196_afe_apll_init(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
if (!afe_priv->vlp_clk) {
dev_warn...
return;
}
regmap_write......
> + if (afe_priv->vlp_ck) {
> + regmap_write(afe_priv->vlp_ck, VLP_APLL1_TUNER_CON0, VLP_APLL1_TUNER_CON0_VALUE);
> + regmap_write(afe_priv->vlp_ck, VLP_APLL2_TUNER_CON0, VLP_APLL2_TUNER_CON0_VALUE);
> + } else {
> + dev_warn(afe->dev, "vlp_ck regmap is null ptr\n");
> + }
> +}
> +
> +int mt8196_apll1_enable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret;
> +
> + /* setting for APLL */
> + apll1_mux_setting(afe, true);
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> + if (ret)
> + goto ERR_CLK_APLL1;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> + if (ret)
> + goto ERR_CLK_APLL1_TUNER;
> +
> + /* sel 44.1kHz:1, apll_div:7, upper bound:3 */
> + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
> + XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT,
> + (0x1 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
> + (3 << UPPER_BOUND_SFT));
> +
> + /* apll1 freq tuner enable */
> + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
> + FREQ_TUNER_EN_MASK_SFT,
> + 0x1 << FREQ_TUNER_EN_SFT);
> +
> + /* audio apll1 on */
> + mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
> +
> + return 0;
> +
> +ERR_CLK_APLL1_TUNER:
lower case for labels please
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> +ERR_CLK_APLL1:
^^^^^^^^^
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> + return ret;
> +}
> +
> +void mt8196_apll1_disable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* audio apll1 off */
> + mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL1_EN_ON);
> +
> + /* apll1 freq tuner disable */
> + regmap_update_bits(afe->regmap, AFE_APLL1_TUNER_CFG,
> + FREQ_TUNER_EN_MASK_SFT,
> + 0x0);
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER1]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL1]);
> + apll1_mux_setting(afe, false);
> +}
> +
> +int mt8196_apll2_enable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret;
> +
> + /* setting for APLL */
> + apll2_mux_setting(afe, true);
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> + if (ret)
> + goto ERR_CLK_APLL2;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> + if (ret)
> + goto ERR_CLK_APLL2_TUNER;
> +
> + /* sel 48kHz: 2, apll_div: 7, upper bound: 3*/
> + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
> + XTAL_EN_128FS_SEL_MASK_SFT | APLL_DIV_MASK_SFT | UPPER_BOUND_MASK_SFT,
> + (0x2 << XTAL_EN_128FS_SEL_SFT) | (7 << APLL_DIV_SFT) |
> + (3 << UPPER_BOUND_SFT));
> +
> + /* apll2 freq tuner enable */
> + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
> + FREQ_TUNER_EN_MASK_SFT,
> + 0x1 << FREQ_TUNER_EN_SFT);
> +
> + /* audio apll2 on */
> + mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
> + return 0;
> +
> +ERR_CLK_APLL2_TUNER:
lower case for labels please
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> +ERR_CLK_APLL2:
ditto
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> + return ret;
> +
> + return 0;
> +}
> +
> +void mt8196_apll2_disable(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* audio apll2 off */
> + mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_APLL2_EN_ON);
> +
> + /* apll2 freq tuner disable */
> + regmap_update_bits(afe->regmap, AFE_APLL2_TUNER_CFG,
> + FREQ_TUNER_EN_MASK_SFT,
> + 0x0);
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL_TUNER2]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_APLL2]);
> + apll2_mux_setting(afe, false);
> +}
> +
> +int mt8196_get_apll_rate(struct mtk_base_afe *afe, int apll)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int clk_id = 0;
> +
> + if (apll < MT8196_APLL1 || apll > MT8196_APLL2) {
> + dev_warn(afe->dev, "invalid clk id\n");
("invalid clk id %d\n", clk_id)
...otherwise it makes no sense, as it gives no useful information.
Alternatively, just drop the print.
> + return 0;
> + }
> +
> + if (apll == MT8196_APLL1)
> + clk_id = MT8196_CLK_TOP_APLL1_CK;
> + else
> + clk_id = MT8196_CLK_TOP_APLL2_CK;
> +
> + return clk_get_rate(afe_priv->clk[clk_id]);
> +}
> +
> +int mt8196_get_apll_by_rate(struct mtk_base_afe *afe, int rate)
> +{
> + return ((rate % 8000) == 0) ? MT8196_APLL2 : MT8196_APLL1;
return (rate % 8000) ? MT8196_APLL1 : MT8196_APLL2;
> +}
> +
> +int mt8196_get_apll_by_name(struct mtk_base_afe *afe, const char *name)
> +{
> + if (strcmp(name, APLL1_W_NAME) == 0)
> + return MT8196_APLL1;
> + else
> + return MT8196_APLL2;
if (strcmp ....)
return MT8196_APLL1;
return MT8196_APLL2;
> +}
> +
> +/* mck */
> +struct mt8196_mck_div {
> + int m_sel_id;
> + int div_clk_id;
> +};
> +
> +static const struct mt8196_mck_div mck_div[MT8196_MCK_NUM] = {
> + [MT8196_I2SIN0_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_I2SIN0_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN0,
> + },
> + [MT8196_I2SIN1_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_I2SIN1_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_I2SIN1,
> + },
> + [MT8196_FMI2S_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_FMI2S_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_FMI2S,
> + },
> + [MT8196_TDMOUT_MCK] = {
> + .m_sel_id = MT8196_CLK_TOP_TDMOUT_M_SEL,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_M,
> + },
> + [MT8196_TDMOUT_BCK] = {
> + .m_sel_id = -1,
> + .div_clk_id = MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B,
> + },
> +};
> +
> +int mt8196_mck_enable(struct mtk_base_afe *afe, int mck_id, int rate)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int apll = mt8196_get_apll_by_rate(afe, rate);
> + int apll_clk_id = apll == MT8196_APLL1 ?
> + MT8196_CLK_TOP_MUX_AUD_1 : MT8196_CLK_TOP_MUX_AUD_2;
> + int m_sel_id = 0;
> + int div_clk_id = 0;
> + int ret = 0;
this gives double initialzation of all m_sel_id, div_clk_id and ret as you are
initializing the first two immediately after the mck_id check, and ret later;
just go for
int m_sel_id, div_clk_id, ret;
or just
int ret;
> +
> + dev_dbg(afe->dev, "mck_id: %d, rate: %d\n", mck_id, rate);
> +
> + if (mck_id >= MT8196_MCK_NUM || mck_id < 0)
> + return -EINVAL;
> +
> + m_sel_id = mck_div[mck_id].m_sel_id;
> + div_clk_id = mck_div[mck_id].div_clk_id;
> +
> + /* select apll */
> + if (m_sel_id >= 0) {
...because then I don't understand why don't you just use mck_div[mck_id] directly.
if (mck_div[mck_id].m_sel_id >= 0) {
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[m_sel_id]);
> + if (ret)
> + return ret;
> +
> + ret = mt8196_afe_set_clk_parent(afe, afe_priv->clk[m_sel_id],
> + afe_priv->clk[apll_clk_id]);
> + if (ret)
> + return ret;
> + }
> +
> + /* enable div, set rate */
> + if (div_clk_id < 0) {
if (mck_div[mck_id].div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B) {
rate ...
} else if (mck_div[mck_id].div_clk_id < 0) {
....
}
> + dev_err(afe->dev, "invalid div_clk_id %d\n", div_clk_id);
> + return -EINVAL;
> + }
> + if (div_clk_id == MT8196_CLK_TOP_APLL12_DIV_TDMOUT_B)
> + rate = rate * 16;
> +
> + ret = mt8196_afe_enable_clk(afe, afe_priv->clk[div_clk_id]);
> + if (ret)
> + return ret;
> +
> + ret = mt8196_afe_set_clk_rate(afe, afe_priv->clk[div_clk_id], rate);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +int mt8196_mck_disable(struct mtk_base_afe *afe, int mck_id)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int m_sel_id = 0;
> + int div_clk_id = 0;
Double init again....
> +
> + dev_dbg(afe->dev, "mck_id: %d.\n", mck_id);
> +
> + if (mck_id < 0) {
> + dev_err(afe->dev, "mck_id = %d < 0\n", mck_id);
> + return -EINVAL;
> + }
> +
> + m_sel_id = mck_div[mck_id].m_sel_id;
> + div_clk_id = mck_div[mck_id].div_clk_id;
> +
> + if (div_clk_id < 0) {
> + dev_err(afe->dev, "div_clk_id = %d < 0\n",
> + div_clk_id);
> + return -EINVAL;
> + }
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[div_clk_id]);
> +
> + if (m_sel_id >= 0)
> + mt8196_afe_disable_clk(afe, afe_priv->clk[m_sel_id]);
> +
> + return 0;
> +}
> +
> +int mt8196_afe_enable_reg_rw_clk(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* bus clock for AFE external access, like DRAM */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
> +
> + /* bus clock for AFE internal access, like AFE SRAM */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> + /* enable audio vlp clock source */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> +
> + /* AFE hw clock */
> + /* IPM2.0: USE HOPPING & 26M */
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
> + mt8196_afe_enable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
> + return 0;
> +}
> +
> +int mt8196_afe_disable_reg_rw_clk(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> +
> + /* IPM2.0: Use HOPPING & 26M */
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_HOPPING]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_AFE_AUDIO_F26M]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> +
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIO_H]);
> + mt8196_afe_set_clk_parent(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS],
> + afe_priv->clk[MT8196_CLK_VLP_CLK26M]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_VLP_MUX_AUDIOINTBUS]);
> + mt8196_afe_disable_clk(afe, afe_priv->clk[MT8196_CLK_TOP_ADSP_SEL]);
> + return 0;
> +}
> +
> +int mt8196_afe_enable_main_clock(struct mtk_base_afe *afe)
> +{
Just directly call
mt8196_afe_enable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
...and drop mt8196_afe_enable_afe_on()
> + mt8196_afe_enable_afe_on(afe);
> + return 0;
> +}
> +
> +int mt8196_afe_disable_main_clock(struct mtk_base_afe *afe)
> +{
> + mt8196_afe_disable_afe_on(afe);
mt8196_afe_disable_top_cg(afe, MT8196_AUDIO_26M_EN_ON);
> + return 0;
> +}
> +
> +int mt8196_init_clock(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + int ret = 0;
> + int i = 0;
> +
> + ret = mt8196_audsys_clk_register(afe);
> + if (ret) {
> + dev_err(afe->dev, "register audsys clk fail %d\n", ret);
> + return ret;
> + }
> +
> + afe_priv->clk = devm_kcalloc(afe->dev, MT8196_CLK_NUM, sizeof(*afe_priv->clk),
> + GFP_KERNEL);
> + if (!afe_priv->clk)
> + return -ENOMEM;
> +
> + for (i = 0; i < MT8196_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, "devm_clk_get %s fail\n", aud_clks[i]);
> + return PTR_ERR(afe_priv->clk[i]);
> + }
> + }
> +
> + afe_priv->vlp_ck = syscon_regmap_lookup_by_phandle(afe->dev->of_node,
> + "vlpcksys");
> + if (IS_ERR(afe_priv->vlp_ck)) {
> + dev_err(afe->dev, "Cannot find vlpcksys\n");
> + return PTR_ERR(afe_priv->vlp_ck);
> + }
> +
> + mt8196_afe_apll_init(afe);
> +
> + ret = mt8196_afe_disable_apll(afe);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-clk.h b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> new file mode 100644
> index 000000000000..60f5e5a157d5
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-afe-clk.h
> @@ -0,0 +1,142 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * mt8196-afe-clk.h -- Mediatek 8196 afe clock ctrl definition
mt8196-afe-clk.h - MediaTek MT8195 AFE Clock Control definitions
> + *
> + * Copyright (c) 2024 MediaTek Inc.
> + * Author: Darren Ye <darren.ye at mediatek.com>
> + */
> +
..snip..
> diff --git a/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> new file mode 100644
> index 000000000000..aa40f02698ac
> --- /dev/null
> +++ b/sound/soc/mediatek/mt8196/mt8196-audsys-clk.c
> @@ -0,0 +1,252 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * mt8196-audsys-clk.c -- MediaTek 8196 audsys clock control
> + *
> + * Copyright (c) 2025 MediaTek Inc.
> + * Author: Darren Ye <darren.ye at mediatek.com>
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include "mt8196-afe-common.h"
> +#include "mt8196-audsys-clk.h"
> +#include "mt8196-audsys-clkid.h"
> +#include "mt8196-reg.h"
> +
..snip..
> +};
> +
> +static void mt8196_audsys_clk_unregister(void *data)
> +{
> + struct mtk_base_afe *afe = data;
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + struct clk *clk;
> + struct clk_lookup *cl;
> + int i;
> +
> + if (!afe_priv)
> + return;
> +
> + for (i = 0; i < CLK_AFE_NR_CLK; i++) {
> + cl = afe_priv->lookup[i];
> + if (!cl)
> + continue;
> +
> + clk = cl->clk;
> + clk_unregister_gate(clk);
> +
> + clkdev_drop(cl);
> + }
> +}
> +
> +int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + struct clk *clk;
> + struct clk_lookup *cl;
> + int i;
> +
> + afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AFE_NR_CLK,
> + sizeof(*afe_priv->lookup),
> + GFP_KERNEL);
> +
> + if (!afe_priv->lookup)
> + return -ENOMEM;
> +
> + for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
> + const struct afe_gate *gate = &aud_clks[i];
> +
> + clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
> + gate->flags, afe->base_addr + gate->reg,
> + gate->bit, gate->cg_flags, NULL);
> +
> + if (IS_ERR(clk)) {
> + dev_err(afe->dev, "Failed to register clk %s: %ld\n",
> + gate->name, PTR_ERR(clk));
> + continue;
> + }
> +
All of the above, until...
> + /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
> + cl = kzalloc(sizeof(*cl), GFP_KERNEL);
> + if (!cl)
> + return -ENOMEM;
> +
> + cl->clk = clk;
> + cl->con_id = gate->name;
> + cl->dev_id = dev_name(afe->dev);
> + cl->clk_hw = NULL;
> + clkdev_add(cl);
...here, can be simplified with a single call to
clk_register_clkdev(clk, gate->name, dev_name(afe->dev))
or alternatively, you could simplify it even more:
static void mt8196_audsys_clk_unregister(void *data)
{
/* nothing to do here, remove this function */
}
int mt8196_audsys_clk_register(struct mtk_base_afe *afe)
{
struct mt8196_afe_private *afe_priv = afe->platform_priv;
int i, ret;
for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
const struct afe_gate *gate = &aud_clks[i];
struct clk_hw *hw;
hw = devm_clk_hw_register_gate(afe->dev, gate->name, gate->parent_name,
gate->flags, afe->base_addr + gate->reg,
gate->bit, gate->cg_flags, NULL);
if (IS_ERR(clk)) {
dev_err(afe->dev, "Failed to register clk %s: %ld\n",
gate->name, PTR_ERR(clk));
continue;
}
ret = devm_clk_hw_register_clkdev(afe->dev, hw, gate->name, dev_name(afe->dev));
if (ret)
return ret;
}
return 0;
}
> +
> + afe_priv->lookup[i] = cl;
> + }
> +
> + return devm_add_action_or_reset(afe->dev, mt8196_audsys_clk_unregister, afe);
> +}
Cheers,
Angelo
More information about the Linux-mediatek
mailing list