1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * MediaTek ALSA SoC Audio DAI eTDM Control |
4 | * |
5 | * Copyright (c) 2023 MediaTek Inc. |
6 | * Authors: Vic Wu <vic.wu@mediatek.com> |
7 | * Maso Huang <maso.huang@mediatek.com> |
8 | */ |
9 | |
10 | #include <linux/bitfield.h> |
11 | #include <linux/bitops.h> |
12 | #include <linux/regmap.h> |
13 | #include <sound/pcm_params.h> |
14 | #include "mt7986-afe-common.h" |
15 | #include "mt7986-reg.h" |
16 | |
17 | #define HOPPING_CLK 0 |
18 | #define APLL_CLK 1 |
19 | #define MTK_DAI_ETDM_FORMAT_I2S 0 |
20 | #define MTK_DAI_ETDM_FORMAT_DSPA 4 |
21 | #define MTK_DAI_ETDM_FORMAT_DSPB 5 |
22 | |
23 | enum { |
24 | MTK_ETDM_RATE_8K = 0, |
25 | MTK_ETDM_RATE_12K = 1, |
26 | MTK_ETDM_RATE_16K = 2, |
27 | MTK_ETDM_RATE_24K = 3, |
28 | MTK_ETDM_RATE_32K = 4, |
29 | MTK_ETDM_RATE_48K = 5, |
30 | MTK_ETDM_RATE_96K = 7, |
31 | MTK_ETDM_RATE_192K = 9, |
32 | MTK_ETDM_RATE_11K = 16, |
33 | MTK_ETDM_RATE_22K = 17, |
34 | MTK_ETDM_RATE_44K = 18, |
35 | MTK_ETDM_RATE_88K = 19, |
36 | MTK_ETDM_RATE_176K = 20, |
37 | }; |
38 | |
39 | struct mtk_dai_etdm_priv { |
40 | bool bck_inv; |
41 | bool lrck_inv; |
42 | bool slave_mode; |
43 | unsigned int format; |
44 | }; |
45 | |
46 | static unsigned int mt7986_etdm_rate_transform(struct device *dev, unsigned int rate) |
47 | { |
48 | switch (rate) { |
49 | case 8000: |
50 | return MTK_ETDM_RATE_8K; |
51 | case 11025: |
52 | return MTK_ETDM_RATE_11K; |
53 | case 12000: |
54 | return MTK_ETDM_RATE_12K; |
55 | case 16000: |
56 | return MTK_ETDM_RATE_16K; |
57 | case 22050: |
58 | return MTK_ETDM_RATE_22K; |
59 | case 24000: |
60 | return MTK_ETDM_RATE_24K; |
61 | case 32000: |
62 | return MTK_ETDM_RATE_32K; |
63 | case 44100: |
64 | return MTK_ETDM_RATE_44K; |
65 | case 48000: |
66 | return MTK_ETDM_RATE_48K; |
67 | case 88200: |
68 | return MTK_ETDM_RATE_88K; |
69 | case 96000: |
70 | return MTK_ETDM_RATE_96K; |
71 | case 176400: |
72 | return MTK_ETDM_RATE_176K; |
73 | case 192000: |
74 | return MTK_ETDM_RATE_192K; |
75 | default: |
76 | dev_warn(dev, "%s(), rate %u invalid, using %d!!!\n" , |
77 | __func__, rate, MTK_ETDM_RATE_48K); |
78 | return MTK_ETDM_RATE_48K; |
79 | } |
80 | } |
81 | |
82 | static int get_etdm_wlen(unsigned int bitwidth) |
83 | { |
84 | return bitwidth <= 16 ? 16 : 32; |
85 | } |
86 | |
87 | /* dai component */ |
88 | /* interconnection */ |
89 | |
90 | static const struct snd_kcontrol_new o124_mix[] = { |
91 | SOC_DAPM_SINGLE_AUTODISABLE("I032_Switch" , AFE_CONN124_1, 0, 1, 0), |
92 | }; |
93 | |
94 | static const struct snd_kcontrol_new o125_mix[] = { |
95 | SOC_DAPM_SINGLE_AUTODISABLE("I033_Switch" , AFE_CONN125_1, 1, 1, 0), |
96 | }; |
97 | |
98 | static const struct snd_soc_dapm_widget mtk_dai_etdm_widgets[] = { |
99 | |
100 | /* DL */ |
101 | SND_SOC_DAPM_MIXER("I150" , SND_SOC_NOPM, 0, 0, NULL, 0), |
102 | SND_SOC_DAPM_MIXER("I151" , SND_SOC_NOPM, 0, 0, NULL, 0), |
103 | /* UL */ |
104 | SND_SOC_DAPM_MIXER("O124" , SND_SOC_NOPM, 0, 0, o124_mix, ARRAY_SIZE(o124_mix)), |
105 | SND_SOC_DAPM_MIXER("O125" , SND_SOC_NOPM, 0, 0, o125_mix, ARRAY_SIZE(o125_mix)), |
106 | }; |
107 | |
108 | static const struct snd_soc_dapm_route mtk_dai_etdm_routes[] = { |
109 | {"I150" , NULL, "ETDM Capture" }, |
110 | {"I151" , NULL, "ETDM Capture" }, |
111 | {"ETDM Playback" , NULL, "O124" }, |
112 | {"ETDM Playback" , NULL, "O125" }, |
113 | {"O124" , "I032_Switch" , "I032" }, |
114 | {"O125" , "I033_Switch" , "I033" }, |
115 | }; |
116 | |
117 | /* dai ops */ |
118 | static int mtk_dai_etdm_startup(struct snd_pcm_substream *substream, |
119 | struct snd_soc_dai *dai) |
120 | { |
121 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
122 | struct mt7986_afe_private *afe_priv = afe->platform_priv; |
123 | int ret; |
124 | |
125 | ret = clk_bulk_prepare_enable(num_clks: afe_priv->num_clks, clks: afe_priv->clks); |
126 | if (ret) |
127 | return dev_err_probe(dev: afe->dev, err: ret, fmt: "Failed to enable clocks\n" ); |
128 | |
129 | regmap_update_bits(map: afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, val: 0); |
130 | regmap_update_bits(map: afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, val: 0); |
131 | |
132 | return 0; |
133 | } |
134 | |
135 | static void mtk_dai_etdm_shutdown(struct snd_pcm_substream *substream, |
136 | struct snd_soc_dai *dai) |
137 | { |
138 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
139 | struct mt7986_afe_private *afe_priv = afe->platform_priv; |
140 | |
141 | regmap_update_bits(map: afe->regmap, AUDIO_TOP_CON2, CLK_OUT5_PDN_MASK, |
142 | CLK_OUT5_PDN); |
143 | regmap_update_bits(map: afe->regmap, AUDIO_TOP_CON2, CLK_IN5_PDN_MASK, |
144 | CLK_IN5_PDN); |
145 | |
146 | clk_bulk_disable_unprepare(num_clks: afe_priv->num_clks, clks: afe_priv->clks); |
147 | } |
148 | |
149 | static unsigned int get_etdm_ch_fixup(unsigned int channels) |
150 | { |
151 | if (channels > 16) |
152 | return 24; |
153 | else if (channels > 8) |
154 | return 16; |
155 | else if (channels > 4) |
156 | return 8; |
157 | else if (channels > 2) |
158 | return 4; |
159 | else |
160 | return 2; |
161 | } |
162 | |
163 | static int mtk_dai_etdm_config(struct mtk_base_afe *afe, |
164 | struct snd_pcm_hw_params *params, |
165 | struct snd_soc_dai *dai, |
166 | int stream) |
167 | { |
168 | struct mt7986_afe_private *afe_priv = afe->platform_priv; |
169 | struct mtk_dai_etdm_priv *etdm_data = afe_priv->dai_priv[dai->id]; |
170 | unsigned int rate = params_rate(p: params); |
171 | unsigned int etdm_rate = mt7986_etdm_rate_transform(dev: afe->dev, rate); |
172 | unsigned int afe_rate = mt7986_afe_rate_transform(dev: afe->dev, rate); |
173 | unsigned int channels = params_channels(p: params); |
174 | unsigned int bit_width = params_width(p: params); |
175 | unsigned int wlen = get_etdm_wlen(bitwidth: bit_width); |
176 | unsigned int val = 0; |
177 | unsigned int mask = 0; |
178 | |
179 | dev_dbg(afe->dev, "%s(), stream %d, rate %u, bitwidth %u\n" , |
180 | __func__, stream, rate, bit_width); |
181 | |
182 | /* CON0 */ |
183 | mask |= ETDM_BIT_LEN_MASK; |
184 | val |= FIELD_PREP(ETDM_BIT_LEN_MASK, bit_width - 1); |
185 | mask |= ETDM_WRD_LEN_MASK; |
186 | val |= FIELD_PREP(ETDM_WRD_LEN_MASK, wlen - 1); |
187 | mask |= ETDM_FMT_MASK; |
188 | val |= FIELD_PREP(ETDM_FMT_MASK, etdm_data->format); |
189 | mask |= ETDM_CH_NUM_MASK; |
190 | val |= FIELD_PREP(ETDM_CH_NUM_MASK, get_etdm_ch_fixup(channels) - 1); |
191 | mask |= RELATCH_SRC_MASK; |
192 | val |= FIELD_PREP(RELATCH_SRC_MASK, APLL_CLK); |
193 | |
194 | switch (stream) { |
195 | case SNDRV_PCM_STREAM_PLAYBACK: |
196 | /* set ETDM_OUT5_CON0 */ |
197 | regmap_update_bits(map: afe->regmap, ETDM_OUT5_CON0, mask, val); |
198 | |
199 | /* set ETDM_OUT5_CON4 */ |
200 | regmap_update_bits(map: afe->regmap, ETDM_OUT5_CON4, |
201 | OUT_RELATCH_MASK, OUT_RELATCH(afe_rate)); |
202 | regmap_update_bits(map: afe->regmap, ETDM_OUT5_CON4, |
203 | OUT_CLK_SRC_MASK, OUT_CLK_SRC(APLL_CLK)); |
204 | regmap_update_bits(map: afe->regmap, ETDM_OUT5_CON4, |
205 | OUT_SEL_FS_MASK, OUT_SEL_FS(etdm_rate)); |
206 | |
207 | /* set ETDM_OUT5_CON5 */ |
208 | regmap_update_bits(map: afe->regmap, ETDM_OUT5_CON5, |
209 | ETDM_CLK_DIV_MASK, ETDM_CLK_DIV); |
210 | break; |
211 | case SNDRV_PCM_STREAM_CAPTURE: |
212 | /* set ETDM_IN5_CON0 */ |
213 | regmap_update_bits(map: afe->regmap, ETDM_IN5_CON0, mask, val); |
214 | regmap_update_bits(map: afe->regmap, ETDM_IN5_CON0, |
215 | ETDM_SYNC_MASK, ETDM_SYNC); |
216 | |
217 | /* set ETDM_IN5_CON2 */ |
218 | regmap_update_bits(map: afe->regmap, ETDM_IN5_CON2, |
219 | IN_CLK_SRC_MASK, IN_CLK_SRC(APLL_CLK)); |
220 | |
221 | /* set ETDM_IN5_CON3 */ |
222 | regmap_update_bits(map: afe->regmap, ETDM_IN5_CON3, |
223 | IN_SEL_FS_MASK, IN_SEL_FS(etdm_rate)); |
224 | |
225 | /* set ETDM_IN5_CON4 */ |
226 | regmap_update_bits(map: afe->regmap, ETDM_IN5_CON4, |
227 | IN_RELATCH_MASK, IN_RELATCH(afe_rate)); |
228 | break; |
229 | default: |
230 | break; |
231 | } |
232 | |
233 | return 0; |
234 | } |
235 | |
236 | static int mtk_dai_etdm_hw_params(struct snd_pcm_substream *substream, |
237 | struct snd_pcm_hw_params *params, |
238 | struct snd_soc_dai *dai) |
239 | { |
240 | unsigned int rate = params_rate(p: params); |
241 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
242 | |
243 | switch (rate) { |
244 | case 8000: |
245 | case 12000: |
246 | case 16000: |
247 | case 24000: |
248 | case 32000: |
249 | case 48000: |
250 | case 96000: |
251 | case 192000: |
252 | mtk_dai_etdm_config(afe, params, dai, stream: SNDRV_PCM_STREAM_PLAYBACK); |
253 | mtk_dai_etdm_config(afe, params, dai, stream: SNDRV_PCM_STREAM_CAPTURE); |
254 | return 0; |
255 | default: |
256 | dev_err(afe->dev, |
257 | "Sample rate %d invalid. Supported rates: 8/12/16/24/32/48/96/192 kHz\n" , |
258 | rate); |
259 | return -EINVAL; |
260 | } |
261 | } |
262 | |
263 | static int mtk_dai_etdm_trigger(struct snd_pcm_substream *substream, int cmd, |
264 | struct snd_soc_dai *dai) |
265 | { |
266 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
267 | |
268 | dev_dbg(afe->dev, "%s(), cmd %d, dai id %d\n" , __func__, cmd, dai->id); |
269 | switch (cmd) { |
270 | case SNDRV_PCM_TRIGGER_START: |
271 | case SNDRV_PCM_TRIGGER_RESUME: |
272 | regmap_update_bits(map: afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, |
273 | ETDM_EN); |
274 | regmap_update_bits(map: afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, |
275 | ETDM_EN); |
276 | break; |
277 | case SNDRV_PCM_TRIGGER_STOP: |
278 | case SNDRV_PCM_TRIGGER_SUSPEND: |
279 | regmap_update_bits(map: afe->regmap, ETDM_IN5_CON0, ETDM_EN_MASK, |
280 | val: 0); |
281 | regmap_update_bits(map: afe->regmap, ETDM_OUT5_CON0, ETDM_EN_MASK, |
282 | val: 0); |
283 | break; |
284 | default: |
285 | break; |
286 | } |
287 | |
288 | return 0; |
289 | } |
290 | |
291 | static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
292 | { |
293 | struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); |
294 | struct mt7986_afe_private *afe_priv = afe->platform_priv; |
295 | struct mtk_dai_etdm_priv *etdm_data; |
296 | void *priv_data; |
297 | |
298 | switch (dai->id) { |
299 | case MT7986_DAI_ETDM: |
300 | break; |
301 | default: |
302 | dev_warn(afe->dev, "%s(), id %d not support\n" , |
303 | __func__, dai->id); |
304 | return -EINVAL; |
305 | } |
306 | |
307 | priv_data = devm_kzalloc(dev: afe->dev, size: sizeof(struct mtk_dai_etdm_priv), |
308 | GFP_KERNEL); |
309 | if (!priv_data) |
310 | return -ENOMEM; |
311 | |
312 | afe_priv->dai_priv[dai->id] = priv_data; |
313 | etdm_data = afe_priv->dai_priv[dai->id]; |
314 | |
315 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
316 | case SND_SOC_DAIFMT_I2S: |
317 | etdm_data->format = MTK_DAI_ETDM_FORMAT_I2S; |
318 | break; |
319 | case SND_SOC_DAIFMT_DSP_A: |
320 | etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPA; |
321 | break; |
322 | case SND_SOC_DAIFMT_DSP_B: |
323 | etdm_data->format = MTK_DAI_ETDM_FORMAT_DSPB; |
324 | break; |
325 | default: |
326 | return -EINVAL; |
327 | } |
328 | |
329 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
330 | case SND_SOC_DAIFMT_NB_NF: |
331 | etdm_data->bck_inv = false; |
332 | etdm_data->lrck_inv = false; |
333 | break; |
334 | case SND_SOC_DAIFMT_NB_IF: |
335 | etdm_data->bck_inv = false; |
336 | etdm_data->lrck_inv = true; |
337 | break; |
338 | case SND_SOC_DAIFMT_IB_NF: |
339 | etdm_data->bck_inv = true; |
340 | etdm_data->lrck_inv = false; |
341 | break; |
342 | case SND_SOC_DAIFMT_IB_IF: |
343 | etdm_data->bck_inv = true; |
344 | etdm_data->lrck_inv = true; |
345 | break; |
346 | default: |
347 | return -EINVAL; |
348 | } |
349 | |
350 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
351 | case SND_SOC_DAIFMT_CBM_CFM: |
352 | etdm_data->slave_mode = true; |
353 | break; |
354 | case SND_SOC_DAIFMT_CBS_CFS: |
355 | etdm_data->slave_mode = false; |
356 | break; |
357 | default: |
358 | return -EINVAL; |
359 | } |
360 | |
361 | return 0; |
362 | } |
363 | |
364 | static const struct snd_soc_dai_ops mtk_dai_etdm_ops = { |
365 | .startup = mtk_dai_etdm_startup, |
366 | .shutdown = mtk_dai_etdm_shutdown, |
367 | .hw_params = mtk_dai_etdm_hw_params, |
368 | .trigger = mtk_dai_etdm_trigger, |
369 | .set_fmt = mtk_dai_etdm_set_fmt, |
370 | }; |
371 | |
372 | /* dai driver */ |
373 | #define MTK_ETDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ |
374 | SNDRV_PCM_RATE_88200 |\ |
375 | SNDRV_PCM_RATE_96000 |\ |
376 | SNDRV_PCM_RATE_176400 |\ |
377 | SNDRV_PCM_RATE_192000) |
378 | |
379 | #define MTK_ETDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ |
380 | SNDRV_PCM_FMTBIT_S24_LE |\ |
381 | SNDRV_PCM_FMTBIT_S32_LE) |
382 | |
383 | static struct snd_soc_dai_driver mtk_dai_etdm_driver[] = { |
384 | { |
385 | .name = "ETDM" , |
386 | .id = MT7986_DAI_ETDM, |
387 | .capture = { |
388 | .stream_name = "ETDM Capture" , |
389 | .channels_min = 1, |
390 | .channels_max = 2, |
391 | .rates = MTK_ETDM_RATES, |
392 | .formats = MTK_ETDM_FORMATS, |
393 | }, |
394 | .playback = { |
395 | .stream_name = "ETDM Playback" , |
396 | .channels_min = 1, |
397 | .channels_max = 2, |
398 | .rates = MTK_ETDM_RATES, |
399 | .formats = MTK_ETDM_FORMATS, |
400 | }, |
401 | .ops = &mtk_dai_etdm_ops, |
402 | .symmetric_rate = 1, |
403 | .symmetric_sample_bits = 1, |
404 | }, |
405 | }; |
406 | |
407 | int mt7986_dai_etdm_register(struct mtk_base_afe *afe) |
408 | { |
409 | struct mtk_base_afe_dai *dai; |
410 | |
411 | dai = devm_kzalloc(dev: afe->dev, size: sizeof(*dai), GFP_KERNEL); |
412 | if (!dai) |
413 | return -ENOMEM; |
414 | |
415 | list_add(new: &dai->list, head: &afe->sub_dais); |
416 | |
417 | dai->dai_drivers = mtk_dai_etdm_driver; |
418 | dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_etdm_driver); |
419 | |
420 | dai->dapm_widgets = mtk_dai_etdm_widgets; |
421 | dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_etdm_widgets); |
422 | dai->dapm_routes = mtk_dai_etdm_routes; |
423 | dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_etdm_routes); |
424 | |
425 | return 0; |
426 | } |
427 | |