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