xref: /linux/sound/soc/mediatek/mt8365/mt8365-dai-adda.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * MediaTek 8365 ALSA SoC Audio DAI ADDA Control
4  *
5  * Copyright (c) 2024 MediaTek Inc.
6  * Authors: Jia Zeng <jia.zeng@mediatek.com>
7  *          Alexandre Mergnat <amergnat@baylibre.com>
8  */
9 
10 #include <linux/bitops.h>
11 #include <linux/regmap.h>
12 #include <sound/pcm_params.h>
13 #include "mt8365-afe-clk.h"
14 #include "mt8365-afe-common.h"
15 #include "../common/mtk-dai-adda-common.h"
16 
17 static int adda_afe_on_ref_cnt;
18 
19 /* DAI Drivers */
20 
mt8365_dai_set_adda_out(struct mtk_base_afe * afe,unsigned int rate)21 static int mt8365_dai_set_adda_out(struct mtk_base_afe *afe, unsigned int rate)
22 {
23 	unsigned int val;
24 
25 	if (rate == 8000 || rate == 16000)
26 		val = AFE_ADDA_DL_VOICE_DATA;
27 	else
28 		val = 0;
29 
30 	val |= FIELD_PREP(AFE_ADDA_DL_SAMPLING_RATE,
31 		mtk_adda_dl_rate_transform(afe, rate));
32 	val |= AFE_ADDA_DL_8X_UPSAMPLE |
33 	       AFE_ADDA_DL_MUTE_OFF_CH1 |
34 	       AFE_ADDA_DL_MUTE_OFF_CH2 |
35 	       AFE_ADDA_DL_DEGRADE_GAIN;
36 
37 	regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON0, 0xffffffff, 0);
38 	regmap_update_bits(afe->regmap, AFE_ADDA_PREDIS_CON1, 0xffffffff, 0);
39 	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0xffffffff, val);
40 	/* SA suggest apply -0.3db to audio/speech path */
41 	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON1,
42 			   0xffffffff, 0xf74f0000);
43 	/* SA suggest use default value for sdm */
44 	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SDM_DCCOMP_CON,
45 			   0xffffffff, 0x0700701e);
46 
47 	return 0;
48 }
49 
mt8365_dai_set_adda_in(struct mtk_base_afe * afe,unsigned int rate)50 static int mt8365_dai_set_adda_in(struct mtk_base_afe *afe, unsigned int rate)
51 {
52 	unsigned int val;
53 
54 	val = FIELD_PREP(AFE_ADDA_UL_SAMPLING_RATE,
55 			 mtk_adda_ul_rate_transform(afe, rate));
56 	regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0,
57 			   AFE_ADDA_UL_SAMPLING_RATE, val);
58 	/* Using Internal ADC */
59 	regmap_update_bits(afe->regmap, AFE_ADDA_TOP_CON0, 0x1, 0x0);
60 
61 	return 0;
62 }
63 
mt8365_dai_enable_adda_on(struct mtk_base_afe * afe)64 int mt8365_dai_enable_adda_on(struct mtk_base_afe *afe)
65 {
66 	unsigned long flags;
67 	struct mt8365_afe_private *afe_priv = afe->platform_priv;
68 
69 	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
70 
71 	adda_afe_on_ref_cnt++;
72 	if (adda_afe_on_ref_cnt == 1)
73 		regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
74 				   AFE_ADDA_UL_DL_ADDA_AFE_ON,
75 				   AFE_ADDA_UL_DL_ADDA_AFE_ON);
76 
77 	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
78 
79 	return 0;
80 }
81 
mt8365_dai_disable_adda_on(struct mtk_base_afe * afe)82 int mt8365_dai_disable_adda_on(struct mtk_base_afe *afe)
83 {
84 	unsigned long flags;
85 	struct mt8365_afe_private *afe_priv = afe->platform_priv;
86 
87 	spin_lock_irqsave(&afe_priv->afe_ctrl_lock, flags);
88 
89 	adda_afe_on_ref_cnt--;
90 	if (adda_afe_on_ref_cnt == 0)
91 		regmap_update_bits(afe->regmap, AFE_ADDA_UL_DL_CON0,
92 				   AFE_ADDA_UL_DL_ADDA_AFE_ON,
93 				   ~AFE_ADDA_UL_DL_ADDA_AFE_ON);
94 	else if (adda_afe_on_ref_cnt < 0) {
95 		adda_afe_on_ref_cnt = 0;
96 		dev_warn(afe->dev, "Abnormal adda_on ref count. Force it to 0\n");
97 	}
98 
99 	spin_unlock_irqrestore(&afe_priv->afe_ctrl_lock, flags);
100 
101 	return 0;
102 }
103 
mt8365_dai_set_adda_out_enable(struct mtk_base_afe * afe,bool enable)104 static void mt8365_dai_set_adda_out_enable(struct mtk_base_afe *afe,
105 					   bool enable)
106 {
107 	regmap_update_bits(afe->regmap, AFE_ADDA_DL_SRC2_CON0, 0x1, enable);
108 
109 	if (enable)
110 		mt8365_dai_enable_adda_on(afe);
111 	else
112 		mt8365_dai_disable_adda_on(afe);
113 }
114 
mt8365_dai_set_adda_in_enable(struct mtk_base_afe * afe,bool enable)115 static void mt8365_dai_set_adda_in_enable(struct mtk_base_afe *afe, bool enable)
116 {
117 	if (enable) {
118 		regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x1);
119 		mt8365_dai_enable_adda_on(afe);
120 		/* enable aud_pad_top fifo */
121 		regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
122 				   0xffffffff, 0x31);
123 	} else {
124 		/* disable aud_pad_top fifo */
125 		regmap_update_bits(afe->regmap, AFE_AUD_PAD_TOP,
126 				   0xffffffff, 0x30);
127 		regmap_update_bits(afe->regmap, AFE_ADDA_UL_SRC_CON0, 0x1, 0x0);
128 		/* de suggest disable ADDA_UL_SRC at least wait 125us */
129 		usleep_range(150, 300);
130 		mt8365_dai_disable_adda_on(afe);
131 	}
132 }
133 
mt8365_dai_int_adda_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)134 static int mt8365_dai_int_adda_startup(struct snd_pcm_substream *substream,
135 				       struct snd_soc_dai *dai)
136 {
137 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
138 	unsigned int stream = substream->stream;
139 
140 	mt8365_afe_enable_main_clk(afe);
141 
142 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
143 		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC);
144 		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
145 	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
146 		mt8365_afe_enable_top_cg(afe, MT8365_TOP_CG_ADC);
147 	}
148 
149 	return 0;
150 }
151 
mt8365_dai_int_adda_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)152 static void mt8365_dai_int_adda_shutdown(struct snd_pcm_substream *substream,
153 					 struct snd_soc_dai *dai)
154 {
155 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
156 	struct mt8365_afe_private *afe_priv = afe->platform_priv;
157 	struct mt8365_be_dai_data *be =
158 		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
159 	unsigned int stream = substream->stream;
160 
161 	if (be->prepared[stream]) {
162 		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
163 			mt8365_dai_set_adda_out_enable(afe, false);
164 			mt8365_afe_set_i2s_out_enable(afe, false);
165 		} else {
166 			mt8365_dai_set_adda_in_enable(afe, false);
167 		}
168 		be->prepared[stream] = false;
169 	}
170 
171 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
172 		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC_PREDIS);
173 		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_DAC);
174 	} else if (stream == SNDRV_PCM_STREAM_CAPTURE) {
175 		mt8365_afe_disable_top_cg(afe, MT8365_TOP_CG_ADC);
176 	}
177 
178 	mt8365_afe_disable_main_clk(afe);
179 }
180 
mt8365_dai_int_adda_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)181 static int mt8365_dai_int_adda_prepare(struct snd_pcm_substream *substream,
182 				       struct snd_soc_dai *dai)
183 {
184 	struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
185 	struct mt8365_afe_private *afe_priv = afe->platform_priv;
186 	struct mt8365_be_dai_data *be =
187 		&afe_priv->be_data[dai->id - MT8365_AFE_BACKEND_BASE];
188 	unsigned int rate = substream->runtime->rate;
189 	int bit_width = snd_pcm_format_width(substream->runtime->format);
190 	int ret;
191 
192 	dev_info(afe->dev, "%s '%s' rate = %u\n", __func__,
193 		 snd_pcm_stream_str(substream), rate);
194 
195 	if (be->prepared[substream->stream]) {
196 		dev_info(afe->dev, "%s '%s' prepared already\n",
197 			 __func__, snd_pcm_stream_str(substream));
198 		return 0;
199 	}
200 
201 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
202 		ret = mt8365_dai_set_adda_out(afe, rate);
203 		if (ret)
204 			return ret;
205 
206 		ret = mt8365_afe_set_i2s_out(afe, rate, bit_width);
207 		if (ret)
208 			return ret;
209 
210 		mt8365_dai_set_adda_out_enable(afe, true);
211 		mt8365_afe_set_i2s_out_enable(afe, true);
212 	} else {
213 		ret = mt8365_dai_set_adda_in(afe, rate);
214 		if (ret)
215 			return ret;
216 
217 		mt8365_dai_set_adda_in_enable(afe, true);
218 	}
219 	be->prepared[substream->stream] = true;
220 	return 0;
221 }
222 
223 static const struct snd_soc_dai_ops mt8365_afe_int_adda_ops = {
224 	.startup	= mt8365_dai_int_adda_startup,
225 	.shutdown	= mt8365_dai_int_adda_shutdown,
226 	.prepare	= mt8365_dai_int_adda_prepare,
227 };
228 
229 static struct snd_soc_dai_driver mtk_dai_adda_driver[] = {
230 	{
231 		.name = "INT ADDA",
232 		.id = MT8365_AFE_IO_INT_ADDA,
233 		.playback = {
234 			.stream_name = "INT ADDA Playback",
235 			.channels_min = 1,
236 			.channels_max = 2,
237 			.rates = SNDRV_PCM_RATE_8000_48000,
238 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
239 		},
240 		.capture = {
241 			.stream_name = "INT ADDA Capture",
242 			.channels_min = 1,
243 			.channels_max = 2,
244 			.rates = SNDRV_PCM_RATE_16000 |
245 				 SNDRV_PCM_RATE_32000 |
246 				 SNDRV_PCM_RATE_48000,
247 			.formats = SNDRV_PCM_FMTBIT_S16_LE |
248 				   SNDRV_PCM_FMTBIT_S32_LE,
249 		},
250 		.ops = &mt8365_afe_int_adda_ops,
251 	}
252 };
253 
254 /* DAI Controls */
255 
256 static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = {
257 	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH1 Switch", AFE_CONN3,
258 				    10, 1, 0),
259 };
260 
261 static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = {
262 	SOC_DAPM_SINGLE_AUTODISABLE("GAIN1_OUT_CH2 Switch", AFE_CONN4,
263 				    11, 1, 0),
264 };
265 
266 static const struct snd_kcontrol_new int_adda_o03_o04_enable_ctl =
267 	SOC_DAPM_SINGLE_VIRT("Switch", 1);
268 
269 /* DAI widget */
270 
271 static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = {
272 	SND_SOC_DAPM_SWITCH("INT ADDA O03_O04", SND_SOC_NOPM, 0, 0,
273 			    &int_adda_o03_o04_enable_ctl),
274 	/* inter-connections */
275 	SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0,
276 			   mtk_adda_dl_ch1_mix,
277 			   ARRAY_SIZE(mtk_adda_dl_ch1_mix)),
278 	SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0,
279 			   mtk_adda_dl_ch2_mix,
280 			   ARRAY_SIZE(mtk_adda_dl_ch2_mix)),
281 };
282 
283 /* DAI route */
284 
285 static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = {
286 	{"INT ADDA O03_O04", "Switch", "O03"},
287 	{"INT ADDA O03_O04", "Switch", "O04"},
288 	{"INT ADDA Playback", NULL, "INT ADDA O03_O04"},
289 	{"INT ADDA Playback", NULL, "ADDA_DL_CH1"},
290 	{"INT ADDA Playback", NULL, "ADDA_DL_CH2"},
291 	{"AIN Mux", "INT ADC", "INT ADDA Capture"},
292 	{"ADDA_DL_CH1", "GAIN1_OUT_CH1", "Hostless FM DL"},
293 	{"ADDA_DL_CH2", "GAIN1_OUT_CH2", "Hostless FM DL"},
294 };
295 
mt8365_dai_adda_register(struct mtk_base_afe * afe)296 int mt8365_dai_adda_register(struct mtk_base_afe *afe)
297 {
298 	struct mtk_base_afe_dai *dai;
299 
300 	dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
301 	if (!dai)
302 		return -ENOMEM;
303 	list_add(&dai->list, &afe->sub_dais);
304 	dai->dai_drivers = mtk_dai_adda_driver;
305 	dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver);
306 	dai->dapm_widgets = mtk_dai_adda_widgets;
307 	dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets);
308 	dai->dapm_routes = mtk_dai_adda_routes;
309 	dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes);
310 	return 0;
311 }
312