From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
To: "Darren.Ye" <darren.ye@mediatek.com>,
Liam Girdwood <lgirdwood@gmail.com>,
Mark Brown <broonie@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Matthias Brugger <matthias.bgg@gmail.com>,
Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
Linus Walleij <linus.walleij@linaro.org>,
Bartosz Golaszewski <brgl@bgdev.pl>
Cc: linux-sound@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org, linux-gpio@vger.kernel.org
Subject: Re: [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control
Date: Thu, 15 May 2025 10:30:26 +0200 [thread overview]
Message-ID: <be75ac83-5421-4bb0-a28a-57be639f427c@collabora.com> (raw)
In-Reply-To: <20250514081125.24475-4-darren.ye@mediatek.com>
Il 14/05/25 10:11, Darren.Ye ha scritto:
> From: Darren Ye <darren.ye@mediatek.com>
>
> Add audio clock wrapper and audio tuner control.
>
> Signed-off-by: Darren Ye <darren.ye@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@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@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@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
next prev parent reply other threads:[~2025-05-15 8:40 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-14 8:11 [PATCH v3 00/10] ASoC: mediatek: Add support for MT8196 SoC Darren.Ye
2025-05-14 8:11 ` [PATCH v3 01/10] ASoC: mediatek: common: modify mtk afe platform driver for mt8196 Darren.Ye
2025-05-14 8:11 ` [PATCH v3 02/10] ASoC: mediatek: mt8196: add common header Darren.Ye
2025-05-14 8:11 ` [PATCH v3 03/10] ASoC: mediatek: mt8196: support audio clock control Darren.Ye
2025-05-15 8:30 ` AngeloGioacchino Del Regno [this message]
2025-05-15 8:50 ` Chen-Yu Tsai
2025-05-15 8:54 ` Mark Brown
2025-05-15 9:31 ` Darren Ye (叶飞)
2025-05-14 8:11 ` [PATCH v3 04/10] ASoC: mediatek: mt8196: support ADDA in platform driver Darren.Ye
2025-05-14 8:17 ` Mark Brown
2025-05-14 8:58 ` Darren Ye (叶飞)
2025-05-14 8:11 ` [PATCH v3 05/10] ASoC: mediatek: mt8196: support I2S " Darren.Ye
2025-05-14 8:11 ` [PATCH v3 06/10] ASoC: mediatek: mt8196: support TDM " Darren.Ye
2025-05-14 8:11 ` [PATCH v3 07/10] ASoC: mediatek: mt8196: add " Darren.Ye
2025-05-15 4:41 ` kernel test robot
2025-05-14 8:11 ` [PATCH v3 08/10] ASoC: dt-bindings: mediatek,mt8196-afe: add audio AFE document Darren.Ye
2025-05-14 10:54 ` Krzysztof Kozlowski
2025-05-15 3:57 ` Darren Ye (叶飞)
2025-06-11 9:32 ` Krzysztof Kozlowski
2025-06-11 13:05 ` Darren Ye (叶飞)
2025-05-14 8:11 ` [PATCH v3 09/10] ASoC: mediatek: mt8196: add machine driver with nau8825 Darren.Ye
2025-05-15 7:27 ` kernel test robot
2025-05-14 8:11 ` [PATCH v3 10/10] ASoC: dt-bindings: mediatek,mt8196-nau8825: add mt8196-nau8825 document Darren.Ye
2025-05-14 10:51 ` Krzysztof Kozlowski
2025-05-15 3:50 ` Darren Ye (叶飞)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=be75ac83-5421-4bb0-a28a-57be639f427c@collabora.com \
--to=angelogioacchino.delregno@collabora.com \
--cc=brgl@bgdev.pl \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=darren.ye@mediatek.com \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linus.walleij@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-gpio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-sound@vger.kernel.org \
--cc=matthias.bgg@gmail.com \
--cc=perex@perex.cz \
--cc=robh@kernel.org \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox