xref: /linux/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c (revision ab7b4ee9861a340b470e59f8d19360f7bc81e9dd)
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>
6cf870273SRyder Lee  *	   Ryder Lee <ryder.lee@mediatek.com>
7d6f3710aSGarlic Tseng  *
8d6f3710aSGarlic Tseng  * This program is free software; you can redistribute it and/or modify
9d6f3710aSGarlic Tseng  * it under the terms of the GNU General Public License version 2 and
10d6f3710aSGarlic Tseng  * only version 2 as published by the Free Software Foundation.
11d6f3710aSGarlic Tseng  *
12d6f3710aSGarlic Tseng  * This program is distributed in the hope that it will be useful,
13d6f3710aSGarlic Tseng  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14d6f3710aSGarlic Tseng  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15d6f3710aSGarlic Tseng  * GNU General Public License for more details.
16d6f3710aSGarlic Tseng  */
17d6f3710aSGarlic Tseng 
18d6f3710aSGarlic Tseng #include "mt2701-afe-common.h"
19d6f3710aSGarlic Tseng #include "mt2701-afe-clock-ctrl.h"
20d6f3710aSGarlic Tseng 
21d8d99d8eSRyder Lee static const char *const base_clks[] = {
2296365d9fSRyder Lee 	[MT2701_INFRA_SYS_AUDIO] = "infra_sys_audio_clk",
23d8d99d8eSRyder Lee 	[MT2701_TOP_AUD_MCLK_SRC0] = "top_audio_mux1_sel",
24d8d99d8eSRyder Lee 	[MT2701_TOP_AUD_MCLK_SRC1] = "top_audio_mux2_sel",
2596365d9fSRyder Lee 	[MT2701_TOP_AUD_A1SYS] = "top_audio_a1sys_hp",
2696365d9fSRyder Lee 	[MT2701_TOP_AUD_A2SYS] = "top_audio_a2sys_hp",
27d8d99d8eSRyder Lee 	[MT2701_AUDSYS_AFE] = "audio_afe_pd",
28d8d99d8eSRyder Lee 	[MT2701_AUDSYS_AFE_CONN] = "audio_afe_conn_pd",
29d8d99d8eSRyder Lee 	[MT2701_AUDSYS_A1SYS] = "audio_a1sys_pd",
30d8d99d8eSRyder 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;
36d8d99d8eSRyder Lee 	int i;
37d6f3710aSGarlic Tseng 
38d8d99d8eSRyder Lee 	for (i = 0; i < MT2701_BASE_CLK_NUM; i++) {
39d8d99d8eSRyder Lee 		afe_priv->base_ck[i] = devm_clk_get(afe->dev, base_clks[i]);
40d8d99d8eSRyder Lee 		if (IS_ERR(afe_priv->base_ck[i])) {
41d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", base_clks[i]);
42d8d99d8eSRyder Lee 			return PTR_ERR(afe_priv->base_ck[i]);
43d6f3710aSGarlic Tseng 		}
44d6f3710aSGarlic Tseng 	}
45d6f3710aSGarlic Tseng 
46d8d99d8eSRyder Lee 	/* Get I2S related clocks */
47d8d99d8eSRyder Lee 	for (i = 0; i < MT2701_I2S_NUM; i++) {
48d8d99d8eSRyder Lee 		struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[i];
49*ab7b4ee9SRyder Lee 		struct clk *i2s_ck;
50d8d99d8eSRyder Lee 		char name[13];
51d8d99d8eSRyder Lee 
52d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2s%d_src_sel", i);
53d8d99d8eSRyder Lee 		i2s_path->sel_ck = devm_clk_get(afe->dev, name);
54d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->sel_ck)) {
55d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
56d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->sel_ck);
57d8d99d8eSRyder Lee 		}
58d8d99d8eSRyder Lee 
59d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2s%d_src_div", i);
60d8d99d8eSRyder Lee 		i2s_path->div_ck = devm_clk_get(afe->dev, name);
61d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->div_ck)) {
62d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
63d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->div_ck);
64d8d99d8eSRyder Lee 		}
65d8d99d8eSRyder Lee 
66d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2s%d_mclk_en", i);
67d8d99d8eSRyder Lee 		i2s_path->mclk_ck = devm_clk_get(afe->dev, name);
68d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->mclk_ck)) {
69d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
70d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->mclk_ck);
71d8d99d8eSRyder Lee 		}
72d8d99d8eSRyder Lee 
73d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2so%d_hop_ck", i);
74*ab7b4ee9SRyder Lee 		i2s_ck = devm_clk_get(afe->dev, name);
75*ab7b4ee9SRyder Lee 		if (IS_ERR(i2s_ck)) {
76d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
77*ab7b4ee9SRyder Lee 			return PTR_ERR(i2s_ck);
78d8d99d8eSRyder Lee 		}
79*ab7b4ee9SRyder Lee 		i2s_path->hop_ck[SNDRV_PCM_STREAM_PLAYBACK] = i2s_ck;
80d8d99d8eSRyder Lee 
81d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "i2si%d_hop_ck", i);
82*ab7b4ee9SRyder Lee 		i2s_ck = devm_clk_get(afe->dev, name);
83*ab7b4ee9SRyder Lee 		if (IS_ERR(i2s_ck)) {
84d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
85*ab7b4ee9SRyder Lee 			return PTR_ERR(i2s_ck);
86d8d99d8eSRyder Lee 		}
87*ab7b4ee9SRyder Lee 		i2s_path->hop_ck[SNDRV_PCM_STREAM_CAPTURE] = i2s_ck;
88d8d99d8eSRyder Lee 
89d8d99d8eSRyder Lee 		snprintf(name, sizeof(name), "asrc%d_out_ck", i);
90d8d99d8eSRyder Lee 		i2s_path->asrco_ck = devm_clk_get(afe->dev, name);
91d8d99d8eSRyder Lee 		if (IS_ERR(i2s_path->asrco_ck)) {
92d8d99d8eSRyder Lee 			dev_err(afe->dev, "failed to get %s\n", name);
93d8d99d8eSRyder Lee 			return PTR_ERR(i2s_path->asrco_ck);
94d8d99d8eSRyder Lee 		}
95d8d99d8eSRyder Lee 	}
96d8d99d8eSRyder Lee 
97d8d99d8eSRyder Lee 	/* Some platforms may support BT path */
98d8d99d8eSRyder Lee 	afe_priv->mrgif_ck = devm_clk_get(afe->dev, "audio_mrgif_pd");
99d8d99d8eSRyder Lee 	if (IS_ERR(afe_priv->mrgif_ck)) {
100d8d99d8eSRyder Lee 		if (PTR_ERR(afe_priv->mrgif_ck) == -EPROBE_DEFER)
101d8d99d8eSRyder Lee 			return -EPROBE_DEFER;
102d8d99d8eSRyder Lee 
103d8d99d8eSRyder Lee 		afe_priv->mrgif_ck = NULL;
104d8d99d8eSRyder Lee 	}
105d8d99d8eSRyder Lee 
106d6f3710aSGarlic Tseng 	return 0;
107d6f3710aSGarlic Tseng }
108d6f3710aSGarlic Tseng 
109cf870273SRyder Lee int mt2701_afe_enable_i2s(struct mtk_base_afe *afe,
110cf870273SRyder Lee 			  struct mt2701_i2s_path *i2s_path,
111cf870273SRyder Lee 			  int dir)
112d8d99d8eSRyder Lee {
113d8d99d8eSRyder Lee 	int ret;
114d8d99d8eSRyder Lee 
115d8d99d8eSRyder Lee 	ret = clk_prepare_enable(i2s_path->asrco_ck);
116d8d99d8eSRyder Lee 	if (ret) {
117d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to enable ASRC clock %d\n", ret);
118d8d99d8eSRyder Lee 		return ret;
119d8d99d8eSRyder Lee 	}
120d8d99d8eSRyder Lee 
121d8d99d8eSRyder Lee 	ret = clk_prepare_enable(i2s_path->hop_ck[dir]);
122d8d99d8eSRyder Lee 	if (ret) {
123d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to enable I2S clock %d\n", ret);
124d8d99d8eSRyder Lee 		goto err_hop_ck;
125d8d99d8eSRyder Lee 	}
126d8d99d8eSRyder Lee 
127d8d99d8eSRyder Lee 	return 0;
128d8d99d8eSRyder Lee 
129d8d99d8eSRyder Lee err_hop_ck:
130d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->asrco_ck);
131d8d99d8eSRyder Lee 
132d8d99d8eSRyder Lee 	return ret;
133d8d99d8eSRyder Lee }
134d8d99d8eSRyder Lee 
135cf870273SRyder Lee void mt2701_afe_disable_i2s(struct mtk_base_afe *afe,
136cf870273SRyder Lee 			    struct mt2701_i2s_path *i2s_path,
137cf870273SRyder Lee 			    int dir)
138d8d99d8eSRyder Lee {
139d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->hop_ck[dir]);
140d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->asrco_ck);
141d8d99d8eSRyder Lee }
142d8d99d8eSRyder Lee 
143d8d99d8eSRyder Lee int mt2701_afe_enable_mclk(struct mtk_base_afe *afe, int id)
144d8d99d8eSRyder Lee {
145d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
146d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
147d8d99d8eSRyder Lee 
148d8d99d8eSRyder Lee 	return clk_prepare_enable(i2s_path->mclk_ck);
149d8d99d8eSRyder Lee }
150d8d99d8eSRyder Lee 
151d8d99d8eSRyder Lee void mt2701_afe_disable_mclk(struct mtk_base_afe *afe, int id)
152d8d99d8eSRyder Lee {
153d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
154d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &afe_priv->i2s_path[id];
155d8d99d8eSRyder Lee 
156d8d99d8eSRyder Lee 	clk_disable_unprepare(i2s_path->mclk_ck);
157d8d99d8eSRyder Lee }
158d8d99d8eSRyder Lee 
159d8d99d8eSRyder Lee int mt2701_enable_btmrg_clk(struct mtk_base_afe *afe)
160d8d99d8eSRyder Lee {
161d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
162d8d99d8eSRyder Lee 
163d8d99d8eSRyder Lee 	return clk_prepare_enable(afe_priv->mrgif_ck);
164d8d99d8eSRyder Lee }
165d8d99d8eSRyder Lee 
166d8d99d8eSRyder Lee void mt2701_disable_btmrg_clk(struct mtk_base_afe *afe)
167d8d99d8eSRyder Lee {
168d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
169d8d99d8eSRyder Lee 
170d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->mrgif_ck);
171d8d99d8eSRyder Lee }
172d8d99d8eSRyder Lee 
173d8d99d8eSRyder Lee static int mt2701_afe_enable_audsys(struct mtk_base_afe *afe)
174d8d99d8eSRyder Lee {
175d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
176d8d99d8eSRyder Lee 	int ret;
177d8d99d8eSRyder Lee 
17896365d9fSRyder Lee 	/* Enable infra clock gate */
17996365d9fSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
180d8d99d8eSRyder Lee 	if (ret)
181d8d99d8eSRyder Lee 		return ret;
182d8d99d8eSRyder Lee 
18396365d9fSRyder Lee 	/* Enable top a1sys clock gate */
18496365d9fSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
18596365d9fSRyder Lee 	if (ret)
18696365d9fSRyder Lee 		goto err_a1sys;
18796365d9fSRyder Lee 
18896365d9fSRyder Lee 	/* Enable top a2sys clock gate */
18996365d9fSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
19096365d9fSRyder Lee 	if (ret)
19196365d9fSRyder Lee 		goto err_a2sys;
19296365d9fSRyder Lee 
19396365d9fSRyder Lee 	/* Internal clock gates */
19496365d9fSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
19596365d9fSRyder Lee 	if (ret)
19696365d9fSRyder Lee 		goto err_afe;
19796365d9fSRyder Lee 
198d8d99d8eSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
199d8d99d8eSRyder Lee 	if (ret)
200d8d99d8eSRyder Lee 		goto err_audio_a1sys;
201d8d99d8eSRyder Lee 
202d8d99d8eSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
203d8d99d8eSRyder Lee 	if (ret)
204d8d99d8eSRyder Lee 		goto err_audio_a2sys;
205d8d99d8eSRyder Lee 
206d8d99d8eSRyder Lee 	ret = clk_prepare_enable(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
207d8d99d8eSRyder Lee 	if (ret)
208d8d99d8eSRyder Lee 		goto err_afe_conn;
209d8d99d8eSRyder Lee 
210d8d99d8eSRyder Lee 	return 0;
211d8d99d8eSRyder Lee 
212d8d99d8eSRyder Lee err_afe_conn:
213d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
214d8d99d8eSRyder Lee err_audio_a2sys:
215d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
216d8d99d8eSRyder Lee err_audio_a1sys:
217d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
21896365d9fSRyder Lee err_afe:
21996365d9fSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
22096365d9fSRyder Lee err_a2sys:
22196365d9fSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
22296365d9fSRyder Lee err_a1sys:
22396365d9fSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
224d8d99d8eSRyder Lee 
225d8d99d8eSRyder Lee 	return ret;
226d8d99d8eSRyder Lee }
227d8d99d8eSRyder Lee 
228d8d99d8eSRyder Lee static void mt2701_afe_disable_audsys(struct mtk_base_afe *afe)
229d8d99d8eSRyder Lee {
230d8d99d8eSRyder Lee 	struct mt2701_afe_private *afe_priv = afe->platform_priv;
231d8d99d8eSRyder Lee 
232d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE_CONN]);
233d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A2SYS]);
234d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_A1SYS]);
235d8d99d8eSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_AUDSYS_AFE]);
23696365d9fSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A1SYS]);
23796365d9fSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_TOP_AUD_A2SYS]);
23896365d9fSRyder Lee 	clk_disable_unprepare(afe_priv->base_ck[MT2701_INFRA_SYS_AUDIO]);
239d8d99d8eSRyder Lee }
240d8d99d8eSRyder Lee 
241d6f3710aSGarlic Tseng int mt2701_afe_enable_clock(struct mtk_base_afe *afe)
242d6f3710aSGarlic Tseng {
243d8d99d8eSRyder Lee 	int ret;
244d6f3710aSGarlic Tseng 
245d8d99d8eSRyder Lee 	/* Enable audio system */
246d8d99d8eSRyder Lee 	ret = mt2701_afe_enable_audsys(afe);
247d6f3710aSGarlic Tseng 	if (ret) {
248d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to enable audio system %d\n", ret);
249d6f3710aSGarlic Tseng 		return ret;
250d6f3710aSGarlic Tseng 	}
251d6f3710aSGarlic Tseng 
252d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, ASYS_TOP_CON,
253600b2fd4SRyder Lee 			   ASYS_TOP_CON_ASYS_TIMING_ON,
254600b2fd4SRyder Lee 			   ASYS_TOP_CON_ASYS_TIMING_ON);
255d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, AFE_DAC_CON0,
256d6f3710aSGarlic Tseng 			   AFE_DAC_CON0_AFE_ON,
257d6f3710aSGarlic Tseng 			   AFE_DAC_CON0_AFE_ON);
258d8d99d8eSRyder Lee 
259d8d99d8eSRyder Lee 	/* Configure ASRC */
260d8d99d8eSRyder Lee 	regmap_write(afe->regmap, PWR1_ASM_CON1, PWR1_ASM_CON1_INIT_VAL);
261d8d99d8eSRyder Lee 	regmap_write(afe->regmap, PWR2_ASM_CON1, PWR2_ASM_CON1_INIT_VAL);
262d6f3710aSGarlic Tseng 
263d6f3710aSGarlic Tseng 	return 0;
264d6f3710aSGarlic Tseng }
265d6f3710aSGarlic Tseng 
266d8d99d8eSRyder Lee int mt2701_afe_disable_clock(struct mtk_base_afe *afe)
267d6f3710aSGarlic Tseng {
268d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, ASYS_TOP_CON,
269600b2fd4SRyder Lee 			   ASYS_TOP_CON_ASYS_TIMING_ON, 0);
270d6f3710aSGarlic Tseng 	regmap_update_bits(afe->regmap, AFE_DAC_CON0,
271d6f3710aSGarlic Tseng 			   AFE_DAC_CON0_AFE_ON, 0);
272d6f3710aSGarlic Tseng 
273d8d99d8eSRyder Lee 	mt2701_afe_disable_audsys(afe);
274d6f3710aSGarlic Tseng 
275d6f3710aSGarlic Tseng 	return 0;
276d6f3710aSGarlic Tseng }
277d6f3710aSGarlic Tseng 
278cf870273SRyder Lee int mt2701_mclk_configuration(struct mtk_base_afe *afe, int id)
279cf870273SRyder Lee 
280d6f3710aSGarlic Tseng {
281d8d99d8eSRyder Lee 	struct mt2701_afe_private *priv = afe->platform_priv;
282d8d99d8eSRyder Lee 	struct mt2701_i2s_path *i2s_path = &priv->i2s_path[id];
283cf870273SRyder Lee 	int ret = -EINVAL;
284d6f3710aSGarlic Tseng 
285d8d99d8eSRyder Lee 	/* Set mclk source */
286cf870273SRyder Lee 	if (!(MT2701_PLL_DOMAIN_0_RATE % i2s_path->mclk_rate))
287d8d99d8eSRyder Lee 		ret = clk_set_parent(i2s_path->sel_ck,
288d8d99d8eSRyder Lee 				     priv->base_ck[MT2701_TOP_AUD_MCLK_SRC0]);
289cf870273SRyder Lee 	else if (!(MT2701_PLL_DOMAIN_1_RATE % i2s_path->mclk_rate))
290d8d99d8eSRyder Lee 		ret = clk_set_parent(i2s_path->sel_ck,
291d8d99d8eSRyder Lee 				     priv->base_ck[MT2701_TOP_AUD_MCLK_SRC1]);
292d6f3710aSGarlic Tseng 
293cf870273SRyder Lee 	if (ret) {
294cf870273SRyder Lee 		dev_err(afe->dev, "failed to set mclk source\n");
295cf870273SRyder Lee 		return ret;
296cf870273SRyder Lee 	}
297d6f3710aSGarlic Tseng 
298d8d99d8eSRyder Lee 	/* Set mclk divider */
299cf870273SRyder Lee 	ret = clk_set_rate(i2s_path->div_ck, i2s_path->mclk_rate);
300cf870273SRyder Lee 	if (ret) {
301d8d99d8eSRyder Lee 		dev_err(afe->dev, "failed to set mclk divider %d\n", ret);
302cf870273SRyder Lee 		return ret;
303cf870273SRyder Lee 	}
304cf870273SRyder Lee 
305cf870273SRyder Lee 	return 0;
306d6f3710aSGarlic Tseng }
307