Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/mediatek/mt8192/mt8192-dai-pcm.c
26488 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// MediaTek ALSA SoC Audio DAI I2S Control
4
//
5
// Copyright (c) 2020 MediaTek Inc.
6
// Author: Shane Chien <[email protected]>
7
//
8
9
#include <linux/regmap.h>
10
#include <sound/pcm_params.h>
11
12
#include "mt8192-afe-common.h"
13
#include "mt8192-interconnection.h"
14
15
enum AUD_TX_LCH_RPT {
16
AUD_TX_LCH_RPT_NO_REPEAT = 0,
17
AUD_TX_LCH_RPT_REPEAT = 1
18
};
19
20
enum AUD_VBT_16K_MODE {
21
AUD_VBT_16K_MODE_DISABLE = 0,
22
AUD_VBT_16K_MODE_ENABLE = 1
23
};
24
25
enum AUD_EXT_MODEM {
26
AUD_EXT_MODEM_SELECT_INTERNAL = 0,
27
AUD_EXT_MODEM_SELECT_EXTERNAL = 1
28
};
29
30
enum AUD_PCM_SYNC_TYPE {
31
/* bck sync length = 1 */
32
AUD_PCM_ONE_BCK_CYCLE_SYNC = 0,
33
/* bck sync length = PCM_INTF_CON1[9:13] */
34
AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1
35
};
36
37
enum AUD_BT_MODE {
38
AUD_BT_MODE_DUAL_MIC_ON_TX = 0,
39
AUD_BT_MODE_SINGLE_MIC_ON_TX = 1
40
};
41
42
enum AUD_PCM_AFIFO_SRC {
43
/* slave mode & external modem uses different crystal */
44
AUD_PCM_AFIFO_ASRC = 0,
45
/* slave mode & external modem uses the same crystal */
46
AUD_PCM_AFIFO_AFIFO = 1
47
};
48
49
enum AUD_PCM_CLOCK_SOURCE {
50
AUD_PCM_CLOCK_MASTER_MODE = 0,
51
AUD_PCM_CLOCK_SLAVE_MODE = 1
52
};
53
54
enum AUD_PCM_WLEN {
55
AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0,
56
AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1
57
};
58
59
enum AUD_PCM_MODE {
60
AUD_PCM_MODE_PCM_MODE_8K = 0,
61
AUD_PCM_MODE_PCM_MODE_16K = 1,
62
AUD_PCM_MODE_PCM_MODE_32K = 2,
63
AUD_PCM_MODE_PCM_MODE_48K = 3,
64
};
65
66
enum AUD_PCM_FMT {
67
AUD_PCM_FMT_I2S = 0,
68
AUD_PCM_FMT_EIAJ = 1,
69
AUD_PCM_FMT_PCM_MODE_A = 2,
70
AUD_PCM_FMT_PCM_MODE_B = 3
71
};
72
73
enum AUD_BCLK_OUT_INV {
74
AUD_BCLK_OUT_INV_NO_INVERSE = 0,
75
AUD_BCLK_OUT_INV_INVERSE = 1
76
};
77
78
enum AUD_PCM_EN {
79
AUD_PCM_EN_DISABLE = 0,
80
AUD_PCM_EN_ENABLE = 1
81
};
82
83
/* dai component */
84
static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = {
85
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN7,
86
I_ADDA_UL_CH1, 1, 0),
87
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN7,
88
I_DL2_CH1, 1, 0),
89
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN7_1,
90
I_DL4_CH1, 1, 0),
91
};
92
93
static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = {
94
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN8,
95
I_ADDA_UL_CH2, 1, 0),
96
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN8,
97
I_DL2_CH2, 1, 0),
98
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN8_1,
99
I_DL4_CH2, 1, 0),
100
};
101
102
static const struct snd_kcontrol_new mtk_pcm_1_playback_ch4_mix[] = {
103
SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN27,
104
I_I2S0_CH1, 1, 0),
105
SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN27,
106
I_I2S0_CH2, 1, 0),
107
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN27,
108
I_DL1_CH1, 1, 0),
109
SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN27,
110
I_I2S2_CH1, 1, 0),
111
SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN27,
112
I_I2S2_CH2, 1, 0),
113
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN27_1,
114
I_DL4_CH1, 1, 0),
115
};
116
117
static const struct snd_kcontrol_new mtk_pcm_2_playback_ch1_mix[] = {
118
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN17,
119
I_ADDA_UL_CH1, 1, 0),
120
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN17,
121
I_ADDA_UL_CH2, 1, 0),
122
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN17,
123
I_ADDA_UL_CH3, 1, 0),
124
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN17,
125
I_DL2_CH1, 1, 0),
126
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN17_1,
127
I_DL4_CH1, 1, 0),
128
};
129
130
static const struct snd_kcontrol_new mtk_pcm_2_playback_ch2_mix[] = {
131
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN18,
132
I_ADDA_UL_CH1, 1, 0),
133
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN18,
134
I_ADDA_UL_CH2, 1, 0),
135
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN18,
136
I_ADDA_UL_CH3, 1, 0),
137
SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN18,
138
I_DL2_CH2, 1, 0),
139
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN18_1,
140
I_DL4_CH2, 1, 0),
141
};
142
143
static const struct snd_kcontrol_new mtk_pcm_2_playback_ch3_mix[] = {
144
SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH3", AFE_CONN23,
145
I_ADDA_UL_CH3, 1, 0),
146
};
147
148
static const struct snd_kcontrol_new mtk_pcm_2_playback_ch4_mix[] = {
149
SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH1", AFE_CONN24,
150
I_I2S0_CH1, 1, 0),
151
SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN24,
152
I_I2S0_CH2, 1, 0),
153
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN24,
154
I_DL1_CH1, 1, 0),
155
SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH1", AFE_CONN24,
156
I_I2S2_CH1, 1, 0),
157
SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN24,
158
I_I2S2_CH2, 1, 0),
159
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1", AFE_CONN24_1,
160
I_DL4_CH1, 1, 0),
161
};
162
163
static const struct snd_kcontrol_new mtk_pcm_2_playback_ch5_mix[] = {
164
SOC_DAPM_SINGLE_AUTODISABLE("I2S0_CH2", AFE_CONN25,
165
I_I2S0_CH2, 1, 0),
166
SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN25,
167
I_DL1_CH2, 1, 0),
168
SOC_DAPM_SINGLE_AUTODISABLE("I2S2_CH2", AFE_CONN25,
169
I_I2S2_CH2, 1, 0),
170
SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2", AFE_CONN25_1,
171
I_DL4_CH2, 1, 0),
172
};
173
174
static int mtk_pcm_en_event(struct snd_soc_dapm_widget *w,
175
struct snd_kcontrol *kcontrol,
176
int event)
177
{
178
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
179
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
180
181
dev_info(afe->dev, "%s(), name %s, event 0x%x\n",
182
__func__, w->name, event);
183
return 0;
184
}
185
186
static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
187
/* inter-connections */
188
SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0,
189
mtk_pcm_1_playback_ch1_mix,
190
ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)),
191
SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0,
192
mtk_pcm_1_playback_ch2_mix,
193
ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)),
194
SND_SOC_DAPM_MIXER("PCM_1_PB_CH4", SND_SOC_NOPM, 0, 0,
195
mtk_pcm_1_playback_ch4_mix,
196
ARRAY_SIZE(mtk_pcm_1_playback_ch4_mix)),
197
SND_SOC_DAPM_MIXER("PCM_2_PB_CH1", SND_SOC_NOPM, 0, 0,
198
mtk_pcm_2_playback_ch1_mix,
199
ARRAY_SIZE(mtk_pcm_2_playback_ch1_mix)),
200
SND_SOC_DAPM_MIXER("PCM_2_PB_CH2", SND_SOC_NOPM, 0, 0,
201
mtk_pcm_2_playback_ch2_mix,
202
ARRAY_SIZE(mtk_pcm_2_playback_ch2_mix)),
203
SND_SOC_DAPM_MIXER("PCM_2_PB_CH3", SND_SOC_NOPM, 0, 0,
204
mtk_pcm_2_playback_ch3_mix,
205
ARRAY_SIZE(mtk_pcm_2_playback_ch3_mix)),
206
SND_SOC_DAPM_MIXER("PCM_2_PB_CH4", SND_SOC_NOPM, 0, 0,
207
mtk_pcm_2_playback_ch4_mix,
208
ARRAY_SIZE(mtk_pcm_2_playback_ch4_mix)),
209
SND_SOC_DAPM_MIXER("PCM_2_PB_CH5", SND_SOC_NOPM, 0, 0,
210
mtk_pcm_2_playback_ch5_mix,
211
ARRAY_SIZE(mtk_pcm_2_playback_ch5_mix)),
212
213
SND_SOC_DAPM_SUPPLY("PCM_1_EN",
214
PCM_INTF_CON1, PCM_EN_SFT, 0,
215
mtk_pcm_en_event,
216
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
217
218
SND_SOC_DAPM_SUPPLY("PCM_2_EN",
219
PCM2_INTF_CON, PCM2_EN_SFT, 0,
220
mtk_pcm_en_event,
221
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
222
223
SND_SOC_DAPM_INPUT("MD1_TO_AFE"),
224
SND_SOC_DAPM_INPUT("MD2_TO_AFE"),
225
SND_SOC_DAPM_OUTPUT("AFE_TO_MD1"),
226
SND_SOC_DAPM_OUTPUT("AFE_TO_MD2"),
227
};
228
229
static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
230
{"PCM 1 Playback", NULL, "PCM_1_PB_CH1"},
231
{"PCM 1 Playback", NULL, "PCM_1_PB_CH2"},
232
{"PCM 1 Playback", NULL, "PCM_1_PB_CH4"},
233
{"PCM 2 Playback", NULL, "PCM_2_PB_CH1"},
234
{"PCM 2 Playback", NULL, "PCM_2_PB_CH2"},
235
{"PCM 2 Playback", NULL, "PCM_2_PB_CH3"},
236
{"PCM 2 Playback", NULL, "PCM_2_PB_CH4"},
237
{"PCM 2 Playback", NULL, "PCM_2_PB_CH5"},
238
239
{"PCM 1 Playback", NULL, "PCM_1_EN"},
240
{"PCM 2 Playback", NULL, "PCM_2_EN"},
241
{"PCM 1 Capture", NULL, "PCM_1_EN"},
242
{"PCM 2 Capture", NULL, "PCM_2_EN"},
243
244
{"AFE_TO_MD1", NULL, "PCM 2 Playback"},
245
{"AFE_TO_MD2", NULL, "PCM 1 Playback"},
246
{"PCM 2 Capture", NULL, "MD1_TO_AFE"},
247
{"PCM 1 Capture", NULL, "MD2_TO_AFE"},
248
249
{"PCM_1_PB_CH1", "DL2_CH1", "DL2"},
250
{"PCM_1_PB_CH2", "DL2_CH2", "DL2"},
251
{"PCM_1_PB_CH4", "DL1_CH1", "DL1"},
252
{"PCM_2_PB_CH1", "DL2_CH1", "DL2"},
253
{"PCM_2_PB_CH2", "DL2_CH2", "DL2"},
254
{"PCM_2_PB_CH4", "DL1_CH1", "DL1"},
255
256
{"PCM_1_PB_CH1", "DL4_CH1", "DL4"},
257
{"PCM_1_PB_CH2", "DL4_CH2", "DL4"},
258
{"PCM_1_PB_CH4", "DL4_CH1", "DL4"},
259
{"PCM_2_PB_CH1", "DL4_CH1", "DL4"},
260
{"PCM_2_PB_CH2", "DL4_CH2", "DL4"},
261
{"PCM_2_PB_CH4", "DL4_CH1", "DL4"},
262
{"PCM_1_PB_CH4", "I2S0_CH1", "I2S0"},
263
{"PCM_2_PB_CH4", "I2S2_CH1", "I2S2"},
264
{"PCM_2_PB_CH5", "DL1_CH2", "DL1"},
265
{"PCM_2_PB_CH5", "DL4_CH2", "DL4"},
266
{"PCM_2_PB_CH5", "I2S0_CH2", "I2S0"},
267
{"PCM_2_PB_CH5", "I2S2_CH2", "I2S2"},
268
};
269
270
/* dai ops */
271
static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream,
272
struct snd_pcm_hw_params *params,
273
struct snd_soc_dai *dai)
274
{
275
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
276
struct snd_soc_dapm_widget *p = snd_soc_dai_get_widget_playback(dai);
277
struct snd_soc_dapm_widget *c = snd_soc_dai_get_widget_capture(dai);
278
unsigned int rate = params_rate(params);
279
unsigned int rate_reg = mt8192_rate_transform(afe->dev, rate, dai->id);
280
unsigned int pcm_con = 0;
281
282
dev_info(afe->dev, "%s(), id %d, stream %d, rate %d, rate_reg %d, widget active p %d, c %d\n",
283
__func__,
284
dai->id,
285
substream->stream,
286
rate,
287
rate_reg,
288
p->active,
289
c->active);
290
291
if (p->active || c->active)
292
return 0;
293
294
switch (dai->id) {
295
case MT8192_DAI_PCM_1:
296
pcm_con |= AUD_BCLK_OUT_INV_NO_INVERSE << PCM_BCLK_OUT_INV_SFT;
297
pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT;
298
pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT;
299
pcm_con |= AUD_EXT_MODEM_SELECT_INTERNAL << PCM_EXT_MODEM_SFT;
300
pcm_con |= 0 << PCM_SYNC_LENGTH_SFT;
301
pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT;
302
pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT;
303
pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT;
304
pcm_con |= AUD_PCM_CLOCK_SLAVE_MODE << PCM_SLAVE_SFT;
305
pcm_con |= rate_reg << PCM_MODE_SFT;
306
pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM_FMT_SFT;
307
308
regmap_update_bits(afe->regmap, PCM_INTF_CON1,
309
0xfffffffe, pcm_con);
310
break;
311
case MT8192_DAI_PCM_2:
312
pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM2_TX_LCH_RPT_SFT;
313
pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM2_VBT_16K_MODE_SFT;
314
pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM2_BT_MODE_SFT;
315
pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM2_AFIFO_SFT;
316
pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM2_WLEN_SFT;
317
pcm_con |= rate_reg << PCM2_MODE_SFT;
318
pcm_con |= AUD_PCM_FMT_PCM_MODE_B << PCM2_FMT_SFT;
319
320
regmap_update_bits(afe->regmap, PCM2_INTF_CON,
321
0xfffffffe, pcm_con);
322
break;
323
default:
324
dev_warn(afe->dev, "%s(), id %d not support\n",
325
__func__, dai->id);
326
return -EINVAL;
327
}
328
329
return 0;
330
}
331
332
static const struct snd_soc_dai_ops mtk_dai_pcm_ops = {
333
.hw_params = mtk_dai_pcm_hw_params,
334
};
335
336
/* dai driver */
337
#define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\
338
SNDRV_PCM_RATE_16000 |\
339
SNDRV_PCM_RATE_32000 |\
340
SNDRV_PCM_RATE_48000)
341
342
#define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
343
SNDRV_PCM_FMTBIT_S24_LE |\
344
SNDRV_PCM_FMTBIT_S32_LE)
345
346
static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
347
{
348
.name = "PCM 1",
349
.id = MT8192_DAI_PCM_1,
350
.playback = {
351
.stream_name = "PCM 1 Playback",
352
.channels_min = 1,
353
.channels_max = 2,
354
.rates = MTK_PCM_RATES,
355
.formats = MTK_PCM_FORMATS,
356
},
357
.capture = {
358
.stream_name = "PCM 1 Capture",
359
.channels_min = 1,
360
.channels_max = 2,
361
.rates = MTK_PCM_RATES,
362
.formats = MTK_PCM_FORMATS,
363
},
364
.ops = &mtk_dai_pcm_ops,
365
.symmetric_rate = 1,
366
.symmetric_sample_bits = 1,
367
},
368
{
369
.name = "PCM 2",
370
.id = MT8192_DAI_PCM_2,
371
.playback = {
372
.stream_name = "PCM 2 Playback",
373
.channels_min = 1,
374
.channels_max = 2,
375
.rates = MTK_PCM_RATES,
376
.formats = MTK_PCM_FORMATS,
377
},
378
.capture = {
379
.stream_name = "PCM 2 Capture",
380
.channels_min = 1,
381
.channels_max = 2,
382
.rates = MTK_PCM_RATES,
383
.formats = MTK_PCM_FORMATS,
384
},
385
.ops = &mtk_dai_pcm_ops,
386
.symmetric_rate = 1,
387
.symmetric_sample_bits = 1,
388
},
389
};
390
391
int mt8192_dai_pcm_register(struct mtk_base_afe *afe)
392
{
393
struct mtk_base_afe_dai *dai;
394
395
dev_info(afe->dev, "%s()\n", __func__);
396
397
dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
398
if (!dai)
399
return -ENOMEM;
400
401
list_add(&dai->list, &afe->sub_dais);
402
403
dai->dai_drivers = mtk_dai_pcm_driver;
404
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
405
406
dai->dapm_widgets = mtk_dai_pcm_widgets;
407
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
408
dai->dapm_routes = mtk_dai_pcm_routes;
409
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
410
return 0;
411
}
412
413