xref: /linux/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c (revision d8d99d8ed658a705909b07ba21b643c53851d70c)
1d6f3710aSGarlic Tseng /*
2d6f3710aSGarlic Tseng  * mt2701-afe-clock-ctrl.c  --  Mediatek 2701 afe clock ctrl
3d6f3710aSGarlic Tseng  *
4d6f3710aSGarlic Tseng  * Copyright (c) 2016 MediaTek Inc.
5d6f3710aSGarlic Tseng  * Author: Garlic Tseng <garlic.tseng@mediatek.com>
6d6f3710aSGarlic Tseng  *
7d6f3710aSGarlic Tseng  * This program is free software; you can redistribute it and/or modify
8d6f3710aSGarlic Tseng  * it under the terms of the GNU General Public License version 2 and
9d6f3710aSGarlic Tseng  * only version 2 as published by the Free Software Foundation.
10d6f3710aSGarlic Tseng  *
11d6f3710aSGarlic Tseng  * This program is distributed in the hope that it will be useful,
12d6f3710aSGarlic Tseng  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13d6f3710aSGarlic Tseng  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14d6f3710aSGarlic Tseng  * GNU General Public License for more details.
15d6f3710aSGarlic Tseng  */
16d6f3710aSGarlic Tseng 
17d6f3710aSGarlic Tseng #include <sound/soc.h>
18d6f3710aSGarlic Tseng #include <linux/regmap.h>
19d6f3710aSGarlic Tseng #include <linux/pm_runtime.h>
20d6f3710aSGarlic Tseng 
21d6f3710aSGarlic Tseng #include "mt2701-afe-common.h"
22d6f3710aSGarlic Tseng #include "mt2701-afe-clock-ctrl.h"
23d6f3710aSGarlic Tseng 
24*d8d99d8eSRyder Lee static const char *const base_clks[] = {
25*d8d99d8eSRyder Lee 	[MT2701_TOP_AUD_MCLK_SRC0] = "top_audio_mux1_sel",
26*d8d99d8eSRyder Lee 	[MT2701_TOP_AUD_MCLK_SRC1] = "top_audio_mux2_sel",
27*d8d99d8eSRyder Lee 	[MT2701_AUDSYS_AFE] = "audio_afe_pd",
28*d8d99d8eSRyder Lee 	[MT2701_AUDSYS_AFE_CONN] = "audio_afe_conn_pd",
29*d8d99d8eSRyder Lee 	[MT2701_AUDSYS_A1SYS] = "audio_a1sys_pd",
30*d8d99d8eSRyder Lee 	[MT2701_AUDSYS_A2SYS] = "audio_a2sys_pd",
31d6f3710aSGarlic Tseng };
32d6f3710aSGarlic Tseng 
33d6f3710aSGarlic Tseng int mt2701_init_clock(struct mtk_base_afe *afe)
34d6f3710aSGarlic Tseng {
35d6f3710aSGarlic Tseng 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
36*d8d99d8eSRyder Lee 	int i;
37d6f3710aSGarlic Tseng 
38*d8d99d8eSRyder Lee 	for (i = 0; i < MT2701_BASE_CLK_NUM; i++) {
39*d8d99d8eSRyder Lee 		afe_priv->base_ck[i] = devm_clk_get(afe->dev, base_clks[i]);
40*d8d99d8eSRyder Lee 		if (IS_ERR(afe_priv->base_ck[i])) {
41*d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", base_clks[i]);
42*d8d99d8eSRyder Lee 			return PTR_ERR(afe_priv->base_ck[i]);
43d6f3710aSGarlic Tseng 		}
44d6f3710aSGarlic Tseng 	}
45d6f3710aSGarlic Tseng 
46*d8d99d8eSRyder Lee 	/* Get I2S related clocks */
47*d8d99d8eSRyder Lee 	for (i = 0; i < MT2701_I2S_NUM; i++) {
48*d8d99d8eSRyder Lee 		struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i];
49*d8d99d8eSRyder Lee 		char name[13];
50*d8d99d8eSRyder Lee 
51*d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2s%d_src_sel", i);
52*d8d99d8eSRyder Lee 		i2s_path->sel_ck = devm_clk_get(afe->dev, name);
53*d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->sel_ck)) {
54*d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
55*d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->sel_ck);
56*d8d99d8eSRyder Lee 		}
57*d8d99d8eSRyder Lee 
58*d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2s%d_src_div", i);
59*d8d99d8eSRyder Lee 		i2s_path->div_ck = devm_clk_get(afe->dev, name);
60*d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->div_ck)) {
61*d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
62*d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->div_ck);
63*d8d99d8eSRyder Lee 		}
64*d8d99d8eSRyder Lee 
65*d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2s%d_mclk_en", i);
66*d8d99d8eSRyder Lee 		i2s_path->mclk_ck = devm_clk_get(afe->dev, name);
67*d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->mclk_ck)) {
68*d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
69*d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->mclk_ck);
70*d8d99d8eSRyder Lee 		}
71*d8d99d8eSRyder Lee 
72*d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2so%d_hop_ck", i);
73*d8d99d8eSRyder Lee 		i2s_path->hop_ck[I2S_OUT] = devm_clk_get(afe->dev, name);
74*d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->hop_ck[I2S_OUT])) {
75*d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
76*d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->hop_ck[I2S_OUT]);
77*d8d99d8eSRyder Lee 		}
78*d8d99d8eSRyder Lee 
79*d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2si%d_hop_ck", i);
80*d8d99d8eSRyder Lee 		i2s_path->hop_ck[I2S_IN] = devm_clk_get(afe->dev, name);
81*d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->hop_ck[I2S_IN])) {
82*d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
83*d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->hop_ck[I2S_IN]);
84*d8d99d8eSRyder Lee 		}
85*d8d99d8eSRyder Lee 
86*d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "asrc%d_out_ck", i);
87*d8d99d8eSRyder Lee 		i2s_path->asrco_ck = devm_clk_get(afe->dev, name);
88*d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->asrco_ck)) {
89*d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
90*d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->asrco_ck);
91*d8d99d8eSRyder Lee 		}
92*d8d99d8eSRyder Lee 	}
93*d8d99d8eSRyder Lee 
94*d8d99d8eSRyder Lee 	/* Some platforms may support BT path */
95*d8d99d8eSRyder Lee 	afe_priv->mrgif_ck = devm_clk_get(afe->dev, "audio_mrgif_pd");
96*d8d99d8eSRyder Lee 	if (IS_ERR(afe_priv->mrgif_ck)) {
97*d8d99d8eSRyder Lee 		if (PTR_ERR(afe_priv->mrgif_ck) == -EPROBE_DEFER)
98*d8d99d8eSRyder Lee 			return -EPROBE_DEFER;
99*d8d99d8eSRyder Lee 
100*d8d99d8eSRyder Lee 		afe_priv->mrgif_ck = NULL;
101*d8d99d8eSRyder Lee 	}
102*d8d99d8eSRyder Lee 
103d6f3710aSGarlic Tseng 	return 0;
104d6f3710aSGarlic Tseng }
105d6f3710aSGarlic Tseng 
106*d8d99d8eSRyder Lee int mt2701_afe_enable_i2s(struct mtk_base_afe *afe, int id, int dir)
107*d8d99d8eSRyder Lee {
108*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
109*d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
110*d8d99d8eSRyder Lee 	int ret;
111*d8d99d8eSRyder Lee 
112*d8d99d8eSRyder Lee 	ret = clk_prepare_enable(i2s_path->asrco_ck);
113*d8d99d8eSRyder Lee 	if (ret) {
114*d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to enable ASRC clock %d\n", ret);
115*d8d99d8eSRyder Lee 		return ret;
116*d8d99d8eSRyder Lee 	}
117*d8d99d8eSRyder Lee 
118*d8d99d8eSRyder Lee 	ret = clk_prepare_enable(i2s_path->hop_ck[dir]);
119*d8d99d8eSRyder Lee 	if (ret) {
120*d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to enable I2S clock %d\n", ret);
121*d8d99d8eSRyder Lee 		goto err_hop_ck;
122*d8d99d8eSRyder Lee 	}
123*d8d99d8eSRyder Lee 
124*d8d99d8eSRyder Lee 	return 0;
125*d8d99d8eSRyder Lee 
126*d8d99d8eSRyder Lee err_hop_ck:
127*d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->asrco_ck);
128*d8d99d8eSRyder Lee 
129*d8d99d8eSRyder Lee 	return ret;
130*d8d99d8eSRyder Lee }
131*d8d99d8eSRyder Lee 
132*d8d99d8eSRyder Lee void mt2701_afe_disable_i2s(struct mtk_base_afe *afe, int id, int dir)
133*d8d99d8eSRyder Lee {
134*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
135*d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
136*d8d99d8eSRyder Lee 
137*d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->hop_ck[dir]);
138*d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->asrco_ck);
139*d8d99d8eSRyder Lee }
140*d8d99d8eSRyder Lee 
141*d8d99d8eSRyder Lee int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id)
142*d8d99d8eSRyder Lee {
143*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
144*d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
145*d8d99d8eSRyder Lee 
146*d8d99d8eSRyder Lee 	return clk_prepare_enable(i2s_path->mclk_ck);
147*d8d99d8eSRyder Lee }
148*d8d99d8eSRyder Lee 
149*d8d99d8eSRyder Lee void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id)
150*d8d99d8eSRyder Lee {
151*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
152*d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
153*d8d99d8eSRyder Lee 
154*d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->mclk_ck);
155*d8d99d8eSRyder Lee }
156*d8d99d8eSRyder Lee 
157*d8d99d8eSRyder Lee int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe)
158*d8d99d8eSRyder Lee {
159*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
160*d8d99d8eSRyder Lee 
161*d8d99d8eSRyder Lee 	return clk_prepare_enable(afe_priv->mrgif_ck);
162*d8d99d8eSRyder Lee }
163*d8d99d8eSRyder Lee 
164*d8d99d8eSRyder Lee void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe)
165*d8d99d8eSRyder Lee {
166*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
167*d8d99d8eSRyder Lee 
168*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->mrgif_ck);
169*d8d99d8eSRyder Lee }
170*d8d99d8eSRyder Lee 
171*d8d99d8eSRyder Lee static int mt2701_afe_enable_audsys(struct mtk_base_afe *afe)
172*d8d99d8eSRyder Lee {
173*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
174*d8d99d8eSRyder Lee 	int ret;
175*d8d99d8eSRyder Lee 
176*d8d99d8eSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
177*d8d99d8eSRyder Lee 	if (ret)
178*d8d99d8eSRyder Lee 		return ret;
179*d8d99d8eSRyder Lee 
180*d8d99d8eSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
181*d8d99d8eSRyder Lee 	if (ret)
182*d8d99d8eSRyder Lee 		goto err_audio_a1sys;
183*d8d99d8eSRyder Lee 
184*d8d99d8eSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
185*d8d99d8eSRyder Lee 	if (ret)
186*d8d99d8eSRyder Lee 		goto err_audio_a2sys;
187*d8d99d8eSRyder Lee 
188*d8d99d8eSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
189*d8d99d8eSRyder Lee 	if (ret)
190*d8d99d8eSRyder Lee 		goto err_afe_conn;
191*d8d99d8eSRyder Lee 
192*d8d99d8eSRyder Lee 	return 0;
193*d8d99d8eSRyder Lee 
194*d8d99d8eSRyder Lee err_afe_conn:
195*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
196*d8d99d8eSRyder Lee err_audio_a2sys:
197*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
198*d8d99d8eSRyder Lee err_audio_a1sys:
199*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
200*d8d99d8eSRyder Lee 
201*d8d99d8eSRyder Lee 	return ret;
202*d8d99d8eSRyder Lee }
203*d8d99d8eSRyder Lee 
204*d8d99d8eSRyder Lee static void mt2701_afe_disable_audsys(struct mtk_base_afe *afe)
205*d8d99d8eSRyder Lee {
206*d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
207*d8d99d8eSRyder Lee 
208*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
209*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
210*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
211*d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
212*d8d99d8eSRyder Lee }
213*d8d99d8eSRyder Lee 
214d6f3710aSGarlic Tseng int mt2701_afe_enable_clock(struct mtk_base_afe *afe)
215d6f3710aSGarlic Tseng {
216*d8d99d8eSRyder Lee 	int ret;
217d6f3710aSGarlic Tseng 
218*d8d99d8eSRyder Lee 	/* Enable audio system */
219*d8d99d8eSRyder Lee 	ret = mt2701_afe_enable_audsys(afe);
220d6f3710aSGarlic Tseng 	if (ret) {
221*d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to enable audio system %d\n", ret);
222d6f3710aSGarlic Tseng 		return ret;
223d6f3710aSGarlic Tseng 	}
224d6f3710aSGarlic Tseng 
225d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, ASYS_TOP_CON,
226d6f3710aSGarlic Tseng 			   AUDIO_TOP_CON0_A1SYS_A2SYS_ON,
227d6f3710aSGarlic Tseng 			   AUDIO_TOP_CON0_A1SYS_A2SYS_ON);
228d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, AFE_DAC_CON0,
229d6f3710aSGarlic Tseng 			   AFE_DAC_CON0_AFE_ON,
230d6f3710aSGarlic Tseng 			   AFE_DAC_CON0_AFE_ON);
231*d8d99d8eSRyder Lee 
232*d8d99d8eSRyder Lee 	/* Configure ASRC */
233*d8d99d8eSRyder Lee 	regmap_write(afe->regmap, PWR1_ASM_CON1, PWR1_ASM_CON1_INIT_VAL);
234*d8d99d8eSRyder Lee 	regmap_write(afe->regmap, PWR2_ASM_CON1, PWR2_ASM_CON1_INIT_VAL);
235d6f3710aSGarlic Tseng 
236d6f3710aSGarlic Tseng 	return 0;
237d6f3710aSGarlic Tseng }
238d6f3710aSGarlic Tseng 
239*d8d99d8eSRyder Lee int mt2701_afe_disable_clock(struct mtk_base_afe *afe)
240d6f3710aSGarlic Tseng {
241d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, ASYS_TOP_CON,
242d6f3710aSGarlic Tseng 			   AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0);
243d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, AFE_DAC_CON0,
244d6f3710aSGarlic Tseng 			   AFE_DAC_CON0_AFE_ON, 0);
245d6f3710aSGarlic Tseng 
246*d8d99d8eSRyder Lee 	mt2701_afe_disable_audsys(afe);
247d6f3710aSGarlic Tseng 
248d6f3710aSGarlic Tseng 	return 0;
249d6f3710aSGarlic Tseng }
250d6f3710aSGarlic Tseng 
251d6f3710aSGarlic Tseng void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
252d6f3710aSGarlic Tseng 			       int mclk)
253d6f3710aSGarlic Tseng {
254*d8d99d8eSRyder Lee 	struct mt2701_afe_private *priv = afe->platform_priv;
255*d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &priv->i2s_path[id];
256d6f3710aSGarlic Tseng 	int ret;
257d6f3710aSGarlic Tseng 
258*d8d99d8eSRyder Lee 	/* Set mclk source */
259*d8d99d8eSRyder Lee 	if (domain == 0)
260*d8d99d8eSRyder Lee 		ret = clk_set_parent(i2s_path->sel_ck,
261*d8d99d8eSRyder Lee 				     priv->base_ck[MT2701_TOP_AUD_MCLK_SRC0]);
262*d8d99d8eSRyder Lee 	else
263*d8d99d8eSRyder Lee 		ret = clk_set_parent(i2s_path->sel_ck,
264*d8d99d8eSRyder Lee 				     priv->base_ck[MT2701_TOP_AUD_MCLK_SRC1]);
265d6f3710aSGarlic Tseng 
266d6f3710aSGarlic Tseng 	if (ret)
267*d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to set domain%d mclk source %d\n",
268*d8d99d8eSRyder Lee 			domain, ret);
269d6f3710aSGarlic Tseng 
270*d8d99d8eSRyder Lee 	/* Set mclk divider */
271*d8d99d8eSRyder Lee 	ret = clk_set_rate(i2s_path->div_ck, mclk);
272d6f3710aSGarlic Tseng 	if (ret)
273*d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to set mclk divider %d\n", ret);
274d6f3710aSGarlic Tseng }
275d6f3710aSGarlic Tseng 
276d6f3710aSGarlic Tseng MODULE_DESCRIPTION("MT2701 afe clock control");
277d6f3710aSGarlic Tseng MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
278d6f3710aSGarlic Tseng MODULE_LICENSE("GPL v2");
279