]>
Commit | Line | Data |
---|---|---|
42a589e8 KC |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // MediaTek ALSA SoC Audio DAI ADDA Control | |
4 | // | |
5 | // Copyright (c) 2018 MediaTek Inc. | |
6 | // Author: KaiChieh Chuang <[email protected]> | |
7 | ||
8 | #include <linux/regmap.h> | |
9 | #include <linux/delay.h> | |
10 | #include "mt6797-afe-common.h" | |
11 | #include "mt6797-interconnection.h" | |
12 | #include "mt6797-reg.h" | |
13 | ||
14 | enum { | |
15 | MTK_AFE_ADDA_DL_RATE_8K = 0, | |
16 | MTK_AFE_ADDA_DL_RATE_11K = 1, | |
17 | MTK_AFE_ADDA_DL_RATE_12K = 2, | |
18 | MTK_AFE_ADDA_DL_RATE_16K = 3, | |
19 | MTK_AFE_ADDA_DL_RATE_22K = 4, | |
20 | MTK_AFE_ADDA_DL_RATE_24K = 5, | |
21 | MTK_AFE_ADDA_DL_RATE_32K = 6, | |
22 | MTK_AFE_ADDA_DL_RATE_44K = 7, | |
23 | MTK_AFE_ADDA_DL_RATE_48K = 8, | |
24 | MTK_AFE_ADDA_DL_RATE_96K = 9, | |
25 | MTK_AFE_ADDA_DL_RATE_192K = 10, | |
26 | }; | |
27 | ||
28 | enum { | |
29 | MTK_AFE_ADDA_UL_RATE_8K = 0, | |
30 | MTK_AFE_ADDA_UL_RATE_16K = 1, | |
31 | MTK_AFE_ADDA_UL_RATE_32K = 2, | |
32 | MTK_AFE_ADDA_UL_RATE_48K = 3, | |
33 | MTK_AFE_ADDA_UL_RATE_96K = 4, | |
34 | MTK_AFE_ADDA_UL_RATE_192K = 5, | |
35 | MTK_AFE_ADDA_UL_RATE_48K_HD = 6, | |
36 | }; | |
37 | ||
38 | static unsigned int adda_dl_rate_transform(struct mtk_base_afe *afe, | |
39 | unsigned int rate) | |
40 | { | |
41 | switch (rate) { | |
42 | case 8000: | |
43 | return MTK_AFE_ADDA_DL_RATE_8K; | |
44 | case 11025: | |
45 | return MTK_AFE_ADDA_DL_RATE_11K; | |
46 | case 12000: | |
47 | return MTK_AFE_ADDA_DL_RATE_12K; | |
48 | case 16000: | |
49 | return MTK_AFE_ADDA_DL_RATE_16K; | |
50 | case 22050: | |
51 | return MTK_AFE_ADDA_DL_RATE_22K; | |
52 | case 24000: | |
53 | return MTK_AFE_ADDA_DL_RATE_24K; | |
54 | case 32000: | |
55 | return MTK_AFE_ADDA_DL_RATE_32K; | |
56 | case 44100: | |
57 | return MTK_AFE_ADDA_DL_RATE_44K; | |
58 | case 48000: | |
59 | return MTK_AFE_ADDA_DL_RATE_48K; | |
60 | case 96000: | |
61 | return MTK_AFE_ADDA_DL_RATE_96K; | |
62 | case 192000: | |
63 | return MTK_AFE_ADDA_DL_RATE_192K; | |
64 | default: | |
65 | dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", | |
66 | __func__, rate); | |
67 | return MTK_AFE_ADDA_DL_RATE_48K; | |
68 | } | |
69 | } | |
70 | ||
71 | static unsigned int adda_ul_rate_transform(struct mtk_base_afe *afe, | |
72 | unsigned int rate) | |
73 | { | |
74 | switch (rate) { | |
75 | case 8000: | |
76 | return MTK_AFE_ADDA_UL_RATE_8K; | |
77 | case 16000: | |
78 | return MTK_AFE_ADDA_UL_RATE_16K; | |
79 | case 32000: | |
80 | return MTK_AFE_ADDA_UL_RATE_32K; | |
81 | case 48000: | |
82 | return MTK_AFE_ADDA_UL_RATE_48K; | |
83 | case 96000: | |
84 | return MTK_AFE_ADDA_UL_RATE_96K; | |
85 | case 192000: | |
86 | return MTK_AFE_ADDA_UL_RATE_192K; | |
87 | default: | |
88 | dev_warn(afe->dev, "%s(), rate %d invalid, use 48kHz!!!\n", | |
89 | __func__, rate); | |
90 | return MTK_AFE_ADDA_UL_RATE_48K; | |
91 | } | |
92 | } | |
93 | ||
94 | /* dai component */ | |
95 | static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { | |
96 | SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0), | |
97 | SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0), | |
98 | SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0), | |
99 | SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3, | |
100 | I_ADDA_UL_CH2, 1, 0), | |
101 | SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3, | |
102 | I_ADDA_UL_CH1, 1, 0), | |
2c1a5c04 KCC |
103 | SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3, |
104 | I_PCM_1_CAP_CH1, 1, 0), | |
105 | SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3, | |
106 | I_PCM_2_CAP_CH1, 1, 0), | |
42a589e8 KC |
107 | }; |
108 | ||
109 | static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { | |
110 | SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0), | |
111 | SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0), | |
112 | SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0), | |
113 | SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0), | |
114 | SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0), | |
115 | SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0), | |
116 | SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4, | |
117 | I_ADDA_UL_CH2, 1, 0), | |
118 | SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4, | |
119 | I_ADDA_UL_CH1, 1, 0), | |
2c1a5c04 KCC |
120 | SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4, |
121 | I_PCM_1_CAP_CH1, 1, 0), | |
122 | SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4, | |
123 | I_PCM_2_CAP_CH1, 1, 0), | |
124 | SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4, | |
125 | I_PCM_1_CAP_CH2, 1, 0), | |
126 | SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4, | |
127 | I_PCM_2_CAP_CH2, 1, 0), | |
42a589e8 KC |
128 | }; |
129 | ||
130 | static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, | |
131 | struct snd_kcontrol *kcontrol, | |
132 | int event) | |
133 | { | |
134 | struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); | |
135 | struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); | |
136 | ||
137 | dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", | |
138 | __func__, w->name, event); | |
139 | ||
140 | switch (event) { | |
141 | case SND_SOC_DAPM_POST_PMD: | |
142 | /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ | |
143 | usleep_range(125, 135); | |
144 | break; | |
145 | default: | |
146 | break; | |
147 | } | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | enum { | |
153 | SUPPLY_SEQ_AUD_TOP_PDN, | |
154 | SUPPLY_SEQ_ADDA_AFE_ON, | |
155 | SUPPLY_SEQ_ADDA_DL_ON, | |
156 | SUPPLY_SEQ_ADDA_UL_ON, | |
157 | }; | |
158 | ||
159 | static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { | |
160 | /* adda */ | |
161 | SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, | |
162 | mtk_adda_dl_ch1_mix, | |
163 | ARRAY_SIZE(mtk_adda_dl_ch1_mix)), | |
164 | SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, | |
165 | mtk_adda_dl_ch2_mix, | |
166 | ARRAY_SIZE(mtk_adda_dl_ch2_mix)), | |
167 | ||
168 | SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, | |
169 | AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0, | |
170 | NULL, 0), | |
171 | ||
172 | SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, | |
173 | AFE_ADDA_DL_SRC2_CON0, | |
174 | DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, | |
175 | NULL, 0), | |
176 | ||
177 | SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, | |
178 | AFE_ADDA_UL_SRC_CON0, | |
179 | UL_SRC_ON_TMP_CTL_SFT, 0, | |
180 | mtk_adda_ul_event, | |
181 | SND_SOC_DAPM_POST_PMD), | |
182 | ||
183 | SND_SOC_DAPM_SUPPLY_S("aud_dac_clk", SUPPLY_SEQ_AUD_TOP_PDN, | |
184 | AUDIO_TOP_CON0, PDN_DAC_SFT, 1, | |
185 | NULL, 0), | |
186 | SND_SOC_DAPM_SUPPLY_S("aud_dac_predis_clk", SUPPLY_SEQ_AUD_TOP_PDN, | |
187 | AUDIO_TOP_CON0, PDN_DAC_PREDIS_SFT, 1, | |
188 | NULL, 0), | |
189 | ||
190 | SND_SOC_DAPM_SUPPLY_S("aud_adc_clk", SUPPLY_SEQ_AUD_TOP_PDN, | |
191 | AUDIO_TOP_CON0, PDN_ADC_SFT, 1, | |
192 | NULL, 0), | |
193 | ||
194 | SND_SOC_DAPM_CLOCK_SUPPLY("mtkaif_26m_clk"), | |
195 | }; | |
196 | ||
197 | static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { | |
198 | /* playback */ | |
199 | {"ADDA_DL_CH1", "DL1_CH1", "DL1"}, | |
200 | {"ADDA_DL_CH2", "DL1_CH1", "DL1"}, | |
201 | {"ADDA_DL_CH2", "DL1_CH2", "DL1"}, | |
202 | ||
203 | {"ADDA_DL_CH1", "DL2_CH1", "DL2"}, | |
204 | {"ADDA_DL_CH2", "DL2_CH1", "DL2"}, | |
205 | {"ADDA_DL_CH2", "DL2_CH2", "DL2"}, | |
206 | ||
207 | {"ADDA_DL_CH1", "DL3_CH1", "DL3"}, | |
208 | {"ADDA_DL_CH2", "DL3_CH1", "DL3"}, | |
209 | {"ADDA_DL_CH2", "DL3_CH2", "DL3"}, | |
210 | ||
211 | {"ADDA Playback", NULL, "ADDA_DL_CH1"}, | |
212 | {"ADDA Playback", NULL, "ADDA_DL_CH2"}, | |
213 | ||
214 | /* adda enable */ | |
215 | {"ADDA Playback", NULL, "ADDA Enable"}, | |
216 | {"ADDA Playback", NULL, "ADDA Playback Enable"}, | |
217 | {"ADDA Capture", NULL, "ADDA Enable"}, | |
218 | {"ADDA Capture", NULL, "ADDA Capture Enable"}, | |
219 | ||
220 | /* clk */ | |
221 | {"ADDA Playback", NULL, "mtkaif_26m_clk"}, | |
222 | {"ADDA Playback", NULL, "aud_dac_clk"}, | |
223 | {"ADDA Playback", NULL, "aud_dac_predis_clk"}, | |
224 | ||
225 | {"ADDA Capture", NULL, "mtkaif_26m_clk"}, | |
226 | {"ADDA Capture", NULL, "aud_adc_clk"}, | |
227 | }; | |
228 | ||
229 | /* dai ops */ | |
230 | static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, | |
231 | struct snd_pcm_hw_params *params, | |
232 | struct snd_soc_dai *dai) | |
233 | { | |
234 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); | |
235 | unsigned int rate = params_rate(params); | |
236 | ||
237 | dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", | |
238 | __func__, dai->id, substream->stream, rate); | |
239 | ||
240 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
241 | unsigned int dl_src2_con0 = 0; | |
242 | unsigned int dl_src2_con1 = 0; | |
243 | ||
244 | /* clean predistortion */ | |
245 | regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0); | |
246 | regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0); | |
247 | ||
248 | /* set input sampling rate */ | |
249 | dl_src2_con0 = adda_dl_rate_transform(afe, rate) << 28; | |
250 | ||
251 | /* set output mode */ | |
252 | switch (rate) { | |
253 | case 192000: | |
254 | dl_src2_con0 |= (0x1 << 24); /* UP_SAMPLING_RATE_X2 */ | |
255 | dl_src2_con0 |= 1 << 14; | |
256 | break; | |
257 | case 96000: | |
258 | dl_src2_con0 |= (0x2 << 24); /* UP_SAMPLING_RATE_X4 */ | |
259 | dl_src2_con0 |= 1 << 14; | |
260 | break; | |
261 | default: | |
262 | dl_src2_con0 |= (0x3 << 24); /* UP_SAMPLING_RATE_X8 */ | |
263 | break; | |
264 | } | |
265 | ||
266 | /* turn off mute function */ | |
267 | dl_src2_con0 |= (0x03 << 11); | |
268 | ||
269 | /* set voice input data if input sample rate is 8k or 16k */ | |
270 | if (rate == 8000 || rate == 16000) | |
271 | dl_src2_con0 |= 0x01 << 5; | |
272 | ||
273 | if (rate < 96000) { | |
274 | /* SA suggest apply -0.3db to audio/speech path */ | |
275 | dl_src2_con1 = 0xf74f0000; | |
276 | } else { | |
277 | /* SA suggest apply -0.3db to audio/speech path | |
278 | * with DL gain set to half, | |
279 | * 0xFFFF = 0dB -> 0x8000 = 0dB when 96k, 192k | |
280 | */ | |
281 | dl_src2_con1 = 0x7ba70000; | |
282 | } | |
283 | ||
284 | /* turn on down-link gain */ | |
285 | dl_src2_con0 = dl_src2_con0 | (0x01 << 1); | |
286 | ||
287 | regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON0, dl_src2_con0); | |
288 | regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON1, dl_src2_con1); | |
289 | } else { | |
290 | unsigned int voice_mode = 0; | |
291 | unsigned int ul_src_con0 = 0; /* default value */ | |
292 | ||
293 | /* Using Internal ADC */ | |
294 | regmap_update_bits(afe->regmap, | |
295 | AFE_ADDA_TOP_CON0, | |
296 | 0x1 << 0, | |
297 | 0x0 << 0); | |
298 | ||
299 | voice_mode = adda_ul_rate_transform(afe, rate); | |
300 | ||
301 | ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); | |
302 | ||
303 | /* up8x txif sat on */ | |
304 | regmap_write(afe->regmap, AFE_ADDA_NEWIF_CFG0, 0x03F87201); | |
305 | ||
306 | if (rate >= 96000) { /* hires */ | |
307 | /* use hires format [1 0 23] */ | |
308 | regmap_update_bits(afe->regmap, | |
309 | AFE_ADDA_NEWIF_CFG0, | |
310 | 0x1 << 5, | |
311 | 0x1 << 5); | |
312 | ||
313 | regmap_update_bits(afe->regmap, | |
314 | AFE_ADDA_NEWIF_CFG2, | |
315 | 0xf << 28, | |
316 | voice_mode << 28); | |
317 | } else { /* normal 8~48k */ | |
318 | /* use fixed 260k anc path */ | |
319 | regmap_update_bits(afe->regmap, | |
320 | AFE_ADDA_NEWIF_CFG2, | |
321 | 0xf << 28, | |
322 | 8 << 28); | |
323 | ||
324 | /* ul_use_cic_out */ | |
325 | ul_src_con0 |= 0x1 << 20; | |
326 | } | |
327 | ||
328 | regmap_update_bits(afe->regmap, | |
329 | AFE_ADDA_NEWIF_CFG2, | |
330 | 0xf << 28, | |
331 | 8 << 28); | |
332 | ||
333 | regmap_update_bits(afe->regmap, | |
334 | AFE_ADDA_UL_SRC_CON0, | |
335 | 0xfffffffe, | |
336 | ul_src_con0); | |
337 | } | |
338 | ||
339 | return 0; | |
340 | } | |
341 | ||
342 | static const struct snd_soc_dai_ops mtk_dai_adda_ops = { | |
343 | .hw_params = mtk_dai_adda_hw_params, | |
344 | }; | |
345 | ||
346 | /* dai driver */ | |
347 | #define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ | |
348 | SNDRV_PCM_RATE_96000 |\ | |
349 | SNDRV_PCM_RATE_192000) | |
350 | ||
351 | #define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ | |
352 | SNDRV_PCM_RATE_16000 |\ | |
353 | SNDRV_PCM_RATE_32000 |\ | |
354 | SNDRV_PCM_RATE_48000 |\ | |
355 | SNDRV_PCM_RATE_96000 |\ | |
356 | SNDRV_PCM_RATE_192000) | |
357 | ||
358 | #define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ | |
359 | SNDRV_PCM_FMTBIT_S24_LE |\ | |
360 | SNDRV_PCM_FMTBIT_S32_LE) | |
361 | ||
362 | static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { | |
363 | { | |
364 | .name = "ADDA", | |
365 | .id = MT6797_DAI_ADDA, | |
366 | .playback = { | |
367 | .stream_name = "ADDA Playback", | |
368 | .channels_min = 1, | |
369 | .channels_max = 2, | |
370 | .rates = MTK_ADDA_PLAYBACK_RATES, | |
371 | .formats = MTK_ADDA_FORMATS, | |
372 | }, | |
373 | .capture = { | |
374 | .stream_name = "ADDA Capture", | |
375 | .channels_min = 1, | |
376 | .channels_max = 2, | |
377 | .rates = MTK_ADDA_CAPTURE_RATES, | |
378 | .formats = MTK_ADDA_FORMATS, | |
379 | }, | |
380 | .ops = &mtk_dai_adda_ops, | |
381 | }, | |
382 | }; | |
383 | ||
384 | int mt6797_dai_adda_register(struct mtk_base_afe *afe) | |
385 | { | |
386 | int id = MT6797_DAI_ADDA; | |
387 | ||
388 | afe->sub_dais[id].dai_drivers = mtk_dai_adda_driver; | |
389 | afe->sub_dais[id].num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); | |
390 | ||
391 | afe->sub_dais[id].dapm_widgets = mtk_dai_adda_widgets; | |
392 | afe->sub_dais[id].num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); | |
393 | afe->sub_dais[id].dapm_routes = mtk_dai_adda_routes; | |
394 | afe->sub_dais[id].num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); | |
395 | return 0; | |
396 | } |