158949aa3SJiaxin Yu // SPDX-License-Identifier: GPL-2.0
258949aa3SJiaxin Yu //
358949aa3SJiaxin Yu // mt8186-audsys-clk.h -- Mediatek 8186 audsys clock control
458949aa3SJiaxin Yu //
558949aa3SJiaxin Yu // Copyright (c) 2022 MediaTek Inc.
658949aa3SJiaxin Yu // Author: Jiaxin Yu <jiaxin.yu@mediatek.com>
758949aa3SJiaxin Yu
858949aa3SJiaxin Yu #include <linux/clk.h>
958949aa3SJiaxin Yu #include <linux/clk-provider.h>
1058949aa3SJiaxin Yu #include <linux/clkdev.h>
1158949aa3SJiaxin Yu #include "mt8186-afe-common.h"
1258949aa3SJiaxin Yu #include "mt8186-audsys-clk.h"
1358949aa3SJiaxin Yu #include "mt8186-audsys-clkid.h"
1458949aa3SJiaxin Yu #include "mt8186-reg.h"
1558949aa3SJiaxin Yu
1658949aa3SJiaxin Yu struct afe_gate {
1758949aa3SJiaxin Yu int id;
1858949aa3SJiaxin Yu const char *name;
1958949aa3SJiaxin Yu const char *parent_name;
2058949aa3SJiaxin Yu int reg;
2158949aa3SJiaxin Yu u8 bit;
2258949aa3SJiaxin Yu const struct clk_ops *ops;
2358949aa3SJiaxin Yu unsigned long flags;
2458949aa3SJiaxin Yu u8 cg_flags;
2558949aa3SJiaxin Yu };
2658949aa3SJiaxin Yu
2758949aa3SJiaxin Yu #define GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, _flags, _cgflags) {\
2858949aa3SJiaxin Yu .id = _id, \
2958949aa3SJiaxin Yu .name = _name, \
3058949aa3SJiaxin Yu .parent_name = _parent, \
3158949aa3SJiaxin Yu .reg = _reg, \
3258949aa3SJiaxin Yu .bit = _bit, \
3358949aa3SJiaxin Yu .flags = _flags, \
3458949aa3SJiaxin Yu .cg_flags = _cgflags, \
3558949aa3SJiaxin Yu }
3658949aa3SJiaxin Yu
3758949aa3SJiaxin Yu #define GATE_AFE(_id, _name, _parent, _reg, _bit) \
3858949aa3SJiaxin Yu GATE_AFE_FLAGS(_id, _name, _parent, _reg, _bit, \
3958949aa3SJiaxin Yu CLK_SET_RATE_PARENT, CLK_GATE_SET_TO_DISABLE)
4058949aa3SJiaxin Yu
4158949aa3SJiaxin Yu #define GATE_AUD0(_id, _name, _parent, _bit) \
4258949aa3SJiaxin Yu GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON0, _bit)
4358949aa3SJiaxin Yu
4458949aa3SJiaxin Yu #define GATE_AUD1(_id, _name, _parent, _bit) \
4558949aa3SJiaxin Yu GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON1, _bit)
4658949aa3SJiaxin Yu
4758949aa3SJiaxin Yu #define GATE_AUD2(_id, _name, _parent, _bit) \
4858949aa3SJiaxin Yu GATE_AFE(_id, _name, _parent, AUDIO_TOP_CON2, _bit)
4958949aa3SJiaxin Yu
5058949aa3SJiaxin Yu static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
5158949aa3SJiaxin Yu /* AUD0 */
5258949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_AFE, "aud_afe_clk", "top_audio", 2),
5358949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_22M, "aud_apll22m_clk", "top_aud_engen1", 8),
5458949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_24M, "aud_apll24m_clk", "top_aud_engen2", 9),
5558949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_APLL2_TUNER, "aud_apll2_tuner_clk", "top_aud_engen2", 18),
5658949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_APLL_TUNER, "aud_apll_tuner_clk", "top_aud_engen1", 19),
5758949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_TDM, "aud_tdm_clk", "top_aud_1", 20),
5858949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_ADC, "aud_adc_clk", "top_audio", 24),
5958949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_DAC, "aud_dac_clk", "top_audio", 25),
6058949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_DAC_PREDIS, "aud_dac_predis_clk", "top_audio", 26),
6158949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_TML, "aud_tml_clk", "top_audio", 27),
6258949aa3SJiaxin Yu GATE_AUD0(CLK_AUD_NLE, "aud_nle_clk", "top_audio", 28),
6358949aa3SJiaxin Yu
6458949aa3SJiaxin Yu /* AUD1 */
6558949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_I2S1_BCLK, "aud_i2s1_bclk", "top_audio", 4),
6658949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_I2S2_BCLK, "aud_i2s2_bclk", "top_audio", 5),
6758949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_I2S3_BCLK, "aud_i2s3_bclk", "top_audio", 6),
6858949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_I2S4_BCLK, "aud_i2s4_bclk", "top_audio", 7),
6958949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_CONNSYS_I2S_ASRC, "aud_connsys_i2s_asrc", "top_audio", 12),
7058949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_GENERAL1_ASRC, "aud_general1_asrc", "top_audio", 13),
7158949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_GENERAL2_ASRC, "aud_general2_asrc", "top_audio", 14),
7258949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_DAC_HIRES, "aud_dac_hires_clk", "top_audio_h", 15),
7358949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires_clk", "top_audio_h", 16),
7458949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_ADC_HIRES_TML, "aud_adc_hires_tml", "top_audio_h", 17),
7558949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_ADDA6_ADC, "aud_adda6_adc", "top_audio", 20),
7658949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_ADDA6_ADC_HIRES, "aud_adda6_adc_hires", "top_audio_h", 21),
7758949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_3RD_DAC, "aud_3rd_dac", "top_audio", 28),
7858949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_3RD_DAC_PREDIS, "aud_3rd_dac_predis", "top_audio", 29),
7958949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_3RD_DAC_TML, "aud_3rd_dac_tml", "top_audio", 30),
8058949aa3SJiaxin Yu GATE_AUD1(CLK_AUD_3RD_DAC_HIRES, "aud_3rd_dac_hires", "top_audio_h", 31),
8158949aa3SJiaxin Yu
8258949aa3SJiaxin Yu /* AUD2 */
8358949aa3SJiaxin Yu GATE_AUD2(CLK_AUD_ETDM_IN1_BCLK, "aud_etdm_in1_bclk", "top_audio", 23),
8458949aa3SJiaxin Yu GATE_AUD2(CLK_AUD_ETDM_OUT1_BCLK, "aud_etdm_out1_bclk", "top_audio", 24),
8558949aa3SJiaxin Yu };
8658949aa3SJiaxin Yu
mt8186_audsys_clk_unregister(void * data)87*a93d2afdSDouglas Anderson static void mt8186_audsys_clk_unregister(void *data)
88*a93d2afdSDouglas Anderson {
89*a93d2afdSDouglas Anderson struct mtk_base_afe *afe = data;
90*a93d2afdSDouglas Anderson struct mt8186_afe_private *afe_priv = afe->platform_priv;
91*a93d2afdSDouglas Anderson struct clk *clk;
92*a93d2afdSDouglas Anderson struct clk_lookup *cl;
93*a93d2afdSDouglas Anderson int i;
94*a93d2afdSDouglas Anderson
95*a93d2afdSDouglas Anderson if (!afe_priv)
96*a93d2afdSDouglas Anderson return;
97*a93d2afdSDouglas Anderson
98*a93d2afdSDouglas Anderson for (i = 0; i < CLK_AUD_NR_CLK; i++) {
99*a93d2afdSDouglas Anderson cl = afe_priv->lookup[i];
100*a93d2afdSDouglas Anderson if (!cl)
101*a93d2afdSDouglas Anderson continue;
102*a93d2afdSDouglas Anderson
103*a93d2afdSDouglas Anderson clk = cl->clk;
104*a93d2afdSDouglas Anderson clk_unregister_gate(clk);
105*a93d2afdSDouglas Anderson
106*a93d2afdSDouglas Anderson clkdev_drop(cl);
107*a93d2afdSDouglas Anderson }
108*a93d2afdSDouglas Anderson }
109*a93d2afdSDouglas Anderson
mt8186_audsys_clk_register(struct mtk_base_afe * afe)11058949aa3SJiaxin Yu int mt8186_audsys_clk_register(struct mtk_base_afe *afe)
11158949aa3SJiaxin Yu {
11258949aa3SJiaxin Yu struct mt8186_afe_private *afe_priv = afe->platform_priv;
11358949aa3SJiaxin Yu struct clk *clk;
11458949aa3SJiaxin Yu struct clk_lookup *cl;
11558949aa3SJiaxin Yu int i;
11658949aa3SJiaxin Yu
11758949aa3SJiaxin Yu afe_priv->lookup = devm_kcalloc(afe->dev, CLK_AUD_NR_CLK,
11858949aa3SJiaxin Yu sizeof(*afe_priv->lookup),
11958949aa3SJiaxin Yu GFP_KERNEL);
12058949aa3SJiaxin Yu
12158949aa3SJiaxin Yu if (!afe_priv->lookup)
12258949aa3SJiaxin Yu return -ENOMEM;
12358949aa3SJiaxin Yu
12458949aa3SJiaxin Yu for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
12558949aa3SJiaxin Yu const struct afe_gate *gate = &aud_clks[i];
12658949aa3SJiaxin Yu
12758949aa3SJiaxin Yu clk = clk_register_gate(afe->dev, gate->name, gate->parent_name,
12858949aa3SJiaxin Yu gate->flags, afe->base_addr + gate->reg,
12958949aa3SJiaxin Yu gate->bit, gate->cg_flags, NULL);
13058949aa3SJiaxin Yu
13158949aa3SJiaxin Yu if (IS_ERR(clk)) {
13258949aa3SJiaxin Yu dev_err(afe->dev, "Failed to register clk %s: %ld\n",
13358949aa3SJiaxin Yu gate->name, PTR_ERR(clk));
13458949aa3SJiaxin Yu continue;
13558949aa3SJiaxin Yu }
13658949aa3SJiaxin Yu
13758949aa3SJiaxin Yu /* add clk_lookup for devm_clk_get(SND_SOC_DAPM_CLOCK_SUPPLY) */
13858949aa3SJiaxin Yu cl = kzalloc(sizeof(*cl), GFP_KERNEL);
13958949aa3SJiaxin Yu if (!cl)
14058949aa3SJiaxin Yu return -ENOMEM;
14158949aa3SJiaxin Yu
14258949aa3SJiaxin Yu cl->clk = clk;
14358949aa3SJiaxin Yu cl->con_id = gate->name;
14458949aa3SJiaxin Yu cl->dev_id = dev_name(afe->dev);
14558949aa3SJiaxin Yu clkdev_add(cl);
14658949aa3SJiaxin Yu
14758949aa3SJiaxin Yu afe_priv->lookup[i] = cl;
14858949aa3SJiaxin Yu }
14958949aa3SJiaxin Yu
150*a93d2afdSDouglas Anderson return devm_add_action_or_reset(afe->dev, mt8186_audsys_clk_unregister, afe);
15158949aa3SJiaxin Yu }
15258949aa3SJiaxin Yu
153