Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/mediatek/mt8183/mt8183-dai-tdm.c
26488 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// MediaTek ALSA SoC Audio DAI TDM Control
4
//
5
// Copyright (c) 2018 MediaTek Inc.
6
// Author: KaiChieh Chuang <[email protected]>
7
8
#include <linux/regmap.h>
9
#include <sound/pcm_params.h>
10
#include "mt8183-afe-clk.h"
11
#include "mt8183-afe-common.h"
12
#include "mt8183-interconnection.h"
13
#include "mt8183-reg.h"
14
15
struct mtk_afe_tdm_priv {
16
int bck_id;
17
int bck_rate;
18
int tdm_out_mode;
19
int bck_invert;
20
int lck_invert;
21
int mclk_id;
22
int mclk_multiple; /* according to sample rate */
23
int mclk_rate;
24
int mclk_apll;
25
};
26
27
enum {
28
TDM_OUT_I2S = 0,
29
TDM_OUT_TDM = 1,
30
};
31
32
enum {
33
TDM_BCK_NON_INV = 0,
34
TDM_BCK_INV = 1,
35
};
36
37
enum {
38
TDM_LCK_NON_INV = 0,
39
TDM_LCK_INV = 1,
40
};
41
42
enum {
43
TDM_WLEN_16_BIT = 1,
44
TDM_WLEN_32_BIT = 2,
45
};
46
47
enum {
48
TDM_CHANNEL_BCK_16 = 0,
49
TDM_CHANNEL_BCK_24 = 1,
50
TDM_CHANNEL_BCK_32 = 2,
51
};
52
53
enum {
54
TDM_CHANNEL_NUM_2 = 0,
55
TDM_CHANNEL_NUM_4 = 1,
56
TDM_CHANNEL_NUM_8 = 2,
57
};
58
59
enum {
60
TDM_CH_START_O30_O31 = 0,
61
TDM_CH_START_O32_O33,
62
TDM_CH_START_O34_O35,
63
TDM_CH_START_O36_O37,
64
TDM_CH_ZERO,
65
};
66
67
enum {
68
HDMI_BIT_WIDTH_16_BIT = 0,
69
HDMI_BIT_WIDTH_32_BIT = 1,
70
};
71
72
static unsigned int get_hdmi_wlen(snd_pcm_format_t format)
73
{
74
return snd_pcm_format_physical_width(format) <= 16 ?
75
HDMI_BIT_WIDTH_16_BIT : HDMI_BIT_WIDTH_32_BIT;
76
}
77
78
static unsigned int get_tdm_wlen(snd_pcm_format_t format)
79
{
80
return snd_pcm_format_physical_width(format) <= 16 ?
81
TDM_WLEN_16_BIT : TDM_WLEN_32_BIT;
82
}
83
84
static unsigned int get_tdm_channel_bck(snd_pcm_format_t format)
85
{
86
return snd_pcm_format_physical_width(format) <= 16 ?
87
TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32;
88
}
89
90
static unsigned int get_tdm_lrck_width(snd_pcm_format_t format)
91
{
92
return snd_pcm_format_physical_width(format) - 1;
93
}
94
95
static unsigned int get_tdm_ch(unsigned int ch)
96
{
97
switch (ch) {
98
case 1:
99
case 2:
100
return TDM_CHANNEL_NUM_2;
101
case 3:
102
case 4:
103
return TDM_CHANNEL_NUM_4;
104
case 5:
105
case 6:
106
case 7:
107
case 8:
108
default:
109
return TDM_CHANNEL_NUM_8;
110
}
111
}
112
113
static unsigned int get_tdm_ch_fixup(unsigned int channels)
114
{
115
if (channels > 4)
116
return 8;
117
else if (channels > 2)
118
return 4;
119
else
120
return 2;
121
}
122
123
static unsigned int get_tdm_ch_per_sdata(unsigned int mode,
124
unsigned int channels)
125
{
126
if (mode == TDM_OUT_TDM)
127
return get_tdm_ch_fixup(channels);
128
else
129
return 2;
130
}
131
132
/* interconnection */
133
enum {
134
HDMI_CONN_CH0 = 0,
135
HDMI_CONN_CH1,
136
HDMI_CONN_CH2,
137
HDMI_CONN_CH3,
138
HDMI_CONN_CH4,
139
HDMI_CONN_CH5,
140
HDMI_CONN_CH6,
141
HDMI_CONN_CH7,
142
};
143
144
static const char *const hdmi_conn_mux_map[] = {
145
"CH0", "CH1", "CH2", "CH3",
146
"CH4", "CH5", "CH6", "CH7",
147
};
148
149
static int hdmi_conn_mux_map_value[] = {
150
HDMI_CONN_CH0,
151
HDMI_CONN_CH1,
152
HDMI_CONN_CH2,
153
HDMI_CONN_CH3,
154
HDMI_CONN_CH4,
155
HDMI_CONN_CH5,
156
HDMI_CONN_CH6,
157
HDMI_CONN_CH7,
158
};
159
160
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum,
161
AFE_HDMI_CONN0,
162
HDMI_O_0_SFT,
163
HDMI_O_0_MASK,
164
hdmi_conn_mux_map,
165
hdmi_conn_mux_map_value);
166
167
static const struct snd_kcontrol_new hdmi_ch0_mux_control =
168
SOC_DAPM_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum);
169
170
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum,
171
AFE_HDMI_CONN0,
172
HDMI_O_1_SFT,
173
HDMI_O_1_MASK,
174
hdmi_conn_mux_map,
175
hdmi_conn_mux_map_value);
176
177
static const struct snd_kcontrol_new hdmi_ch1_mux_control =
178
SOC_DAPM_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum);
179
180
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum,
181
AFE_HDMI_CONN0,
182
HDMI_O_2_SFT,
183
HDMI_O_2_MASK,
184
hdmi_conn_mux_map,
185
hdmi_conn_mux_map_value);
186
187
static const struct snd_kcontrol_new hdmi_ch2_mux_control =
188
SOC_DAPM_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum);
189
190
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum,
191
AFE_HDMI_CONN0,
192
HDMI_O_3_SFT,
193
HDMI_O_3_MASK,
194
hdmi_conn_mux_map,
195
hdmi_conn_mux_map_value);
196
197
static const struct snd_kcontrol_new hdmi_ch3_mux_control =
198
SOC_DAPM_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum);
199
200
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum,
201
AFE_HDMI_CONN0,
202
HDMI_O_4_SFT,
203
HDMI_O_4_MASK,
204
hdmi_conn_mux_map,
205
hdmi_conn_mux_map_value);
206
207
static const struct snd_kcontrol_new hdmi_ch4_mux_control =
208
SOC_DAPM_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum);
209
210
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum,
211
AFE_HDMI_CONN0,
212
HDMI_O_5_SFT,
213
HDMI_O_5_MASK,
214
hdmi_conn_mux_map,
215
hdmi_conn_mux_map_value);
216
217
static const struct snd_kcontrol_new hdmi_ch5_mux_control =
218
SOC_DAPM_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum);
219
220
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum,
221
AFE_HDMI_CONN0,
222
HDMI_O_6_SFT,
223
HDMI_O_6_MASK,
224
hdmi_conn_mux_map,
225
hdmi_conn_mux_map_value);
226
227
static const struct snd_kcontrol_new hdmi_ch6_mux_control =
228
SOC_DAPM_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum);
229
230
static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum,
231
AFE_HDMI_CONN0,
232
HDMI_O_7_SFT,
233
HDMI_O_7_MASK,
234
hdmi_conn_mux_map,
235
hdmi_conn_mux_map_value);
236
237
static const struct snd_kcontrol_new hdmi_ch7_mux_control =
238
SOC_DAPM_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum);
239
240
enum {
241
SUPPLY_SEQ_APLL,
242
SUPPLY_SEQ_TDM_MCK_EN,
243
SUPPLY_SEQ_TDM_BCK_EN,
244
};
245
246
static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w,
247
struct snd_kcontrol *kcontrol,
248
int event)
249
{
250
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
251
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
252
struct mt8183_afe_private *afe_priv = afe->platform_priv;
253
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
254
255
dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
256
__func__, w->name, event);
257
258
switch (event) {
259
case SND_SOC_DAPM_PRE_PMU:
260
mt8183_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate);
261
break;
262
case SND_SOC_DAPM_POST_PMD:
263
mt8183_mck_disable(afe, tdm_priv->bck_id);
264
break;
265
default:
266
break;
267
}
268
269
return 0;
270
}
271
272
static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w,
273
struct snd_kcontrol *kcontrol,
274
int event)
275
{
276
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
277
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
278
struct mt8183_afe_private *afe_priv = afe->platform_priv;
279
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
280
281
dev_info(cmpnt->dev, "%s(), name %s, event 0x%x\n",
282
__func__, w->name, event);
283
284
switch (event) {
285
case SND_SOC_DAPM_PRE_PMU:
286
mt8183_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate);
287
break;
288
case SND_SOC_DAPM_POST_PMD:
289
tdm_priv->mclk_rate = 0;
290
mt8183_mck_disable(afe, tdm_priv->mclk_id);
291
break;
292
default:
293
break;
294
}
295
296
return 0;
297
}
298
299
static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = {
300
SND_SOC_DAPM_MUX("HDMI_CH0_MUX", SND_SOC_NOPM, 0, 0,
301
&hdmi_ch0_mux_control),
302
SND_SOC_DAPM_MUX("HDMI_CH1_MUX", SND_SOC_NOPM, 0, 0,
303
&hdmi_ch1_mux_control),
304
SND_SOC_DAPM_MUX("HDMI_CH2_MUX", SND_SOC_NOPM, 0, 0,
305
&hdmi_ch2_mux_control),
306
SND_SOC_DAPM_MUX("HDMI_CH3_MUX", SND_SOC_NOPM, 0, 0,
307
&hdmi_ch3_mux_control),
308
SND_SOC_DAPM_MUX("HDMI_CH4_MUX", SND_SOC_NOPM, 0, 0,
309
&hdmi_ch4_mux_control),
310
SND_SOC_DAPM_MUX("HDMI_CH5_MUX", SND_SOC_NOPM, 0, 0,
311
&hdmi_ch5_mux_control),
312
SND_SOC_DAPM_MUX("HDMI_CH6_MUX", SND_SOC_NOPM, 0, 0,
313
&hdmi_ch6_mux_control),
314
SND_SOC_DAPM_MUX("HDMI_CH7_MUX", SND_SOC_NOPM, 0, 0,
315
&hdmi_ch7_mux_control),
316
317
SND_SOC_DAPM_CLOCK_SUPPLY("aud_tdm_clk"),
318
319
SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN,
320
SND_SOC_NOPM, 0, 0,
321
mtk_tdm_bck_en_event,
322
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
323
324
SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN,
325
SND_SOC_NOPM, 0, 0,
326
mtk_tdm_mck_en_event,
327
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
328
};
329
330
static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source,
331
struct snd_soc_dapm_widget *sink)
332
{
333
struct snd_soc_dapm_widget *w = sink;
334
struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
335
struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt);
336
struct mt8183_afe_private *afe_priv = afe->platform_priv;
337
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[MT8183_DAI_TDM];
338
int cur_apll;
339
340
/* which apll */
341
cur_apll = mt8183_get_apll_by_name(afe, source->name);
342
343
return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0;
344
}
345
346
static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = {
347
{"HDMI_CH0_MUX", "CH0", "HDMI"},
348
{"HDMI_CH0_MUX", "CH1", "HDMI"},
349
{"HDMI_CH0_MUX", "CH2", "HDMI"},
350
{"HDMI_CH0_MUX", "CH3", "HDMI"},
351
{"HDMI_CH0_MUX", "CH4", "HDMI"},
352
{"HDMI_CH0_MUX", "CH5", "HDMI"},
353
{"HDMI_CH0_MUX", "CH6", "HDMI"},
354
{"HDMI_CH0_MUX", "CH7", "HDMI"},
355
356
{"HDMI_CH1_MUX", "CH0", "HDMI"},
357
{"HDMI_CH1_MUX", "CH1", "HDMI"},
358
{"HDMI_CH1_MUX", "CH2", "HDMI"},
359
{"HDMI_CH1_MUX", "CH3", "HDMI"},
360
{"HDMI_CH1_MUX", "CH4", "HDMI"},
361
{"HDMI_CH1_MUX", "CH5", "HDMI"},
362
{"HDMI_CH1_MUX", "CH6", "HDMI"},
363
{"HDMI_CH1_MUX", "CH7", "HDMI"},
364
365
{"HDMI_CH2_MUX", "CH0", "HDMI"},
366
{"HDMI_CH2_MUX", "CH1", "HDMI"},
367
{"HDMI_CH2_MUX", "CH2", "HDMI"},
368
{"HDMI_CH2_MUX", "CH3", "HDMI"},
369
{"HDMI_CH2_MUX", "CH4", "HDMI"},
370
{"HDMI_CH2_MUX", "CH5", "HDMI"},
371
{"HDMI_CH2_MUX", "CH6", "HDMI"},
372
{"HDMI_CH2_MUX", "CH7", "HDMI"},
373
374
{"HDMI_CH3_MUX", "CH0", "HDMI"},
375
{"HDMI_CH3_MUX", "CH1", "HDMI"},
376
{"HDMI_CH3_MUX", "CH2", "HDMI"},
377
{"HDMI_CH3_MUX", "CH3", "HDMI"},
378
{"HDMI_CH3_MUX", "CH4", "HDMI"},
379
{"HDMI_CH3_MUX", "CH5", "HDMI"},
380
{"HDMI_CH3_MUX", "CH6", "HDMI"},
381
{"HDMI_CH3_MUX", "CH7", "HDMI"},
382
383
{"HDMI_CH4_MUX", "CH0", "HDMI"},
384
{"HDMI_CH4_MUX", "CH1", "HDMI"},
385
{"HDMI_CH4_MUX", "CH2", "HDMI"},
386
{"HDMI_CH4_MUX", "CH3", "HDMI"},
387
{"HDMI_CH4_MUX", "CH4", "HDMI"},
388
{"HDMI_CH4_MUX", "CH5", "HDMI"},
389
{"HDMI_CH4_MUX", "CH6", "HDMI"},
390
{"HDMI_CH4_MUX", "CH7", "HDMI"},
391
392
{"HDMI_CH5_MUX", "CH0", "HDMI"},
393
{"HDMI_CH5_MUX", "CH1", "HDMI"},
394
{"HDMI_CH5_MUX", "CH2", "HDMI"},
395
{"HDMI_CH5_MUX", "CH3", "HDMI"},
396
{"HDMI_CH5_MUX", "CH4", "HDMI"},
397
{"HDMI_CH5_MUX", "CH5", "HDMI"},
398
{"HDMI_CH5_MUX", "CH6", "HDMI"},
399
{"HDMI_CH5_MUX", "CH7", "HDMI"},
400
401
{"HDMI_CH6_MUX", "CH0", "HDMI"},
402
{"HDMI_CH6_MUX", "CH1", "HDMI"},
403
{"HDMI_CH6_MUX", "CH2", "HDMI"},
404
{"HDMI_CH6_MUX", "CH3", "HDMI"},
405
{"HDMI_CH6_MUX", "CH4", "HDMI"},
406
{"HDMI_CH6_MUX", "CH5", "HDMI"},
407
{"HDMI_CH6_MUX", "CH6", "HDMI"},
408
{"HDMI_CH6_MUX", "CH7", "HDMI"},
409
410
{"HDMI_CH7_MUX", "CH0", "HDMI"},
411
{"HDMI_CH7_MUX", "CH1", "HDMI"},
412
{"HDMI_CH7_MUX", "CH2", "HDMI"},
413
{"HDMI_CH7_MUX", "CH3", "HDMI"},
414
{"HDMI_CH7_MUX", "CH4", "HDMI"},
415
{"HDMI_CH7_MUX", "CH5", "HDMI"},
416
{"HDMI_CH7_MUX", "CH6", "HDMI"},
417
{"HDMI_CH7_MUX", "CH7", "HDMI"},
418
419
{"TDM", NULL, "HDMI_CH0_MUX"},
420
{"TDM", NULL, "HDMI_CH1_MUX"},
421
{"TDM", NULL, "HDMI_CH2_MUX"},
422
{"TDM", NULL, "HDMI_CH3_MUX"},
423
{"TDM", NULL, "HDMI_CH4_MUX"},
424
{"TDM", NULL, "HDMI_CH5_MUX"},
425
{"TDM", NULL, "HDMI_CH6_MUX"},
426
{"TDM", NULL, "HDMI_CH7_MUX"},
427
428
{"TDM", NULL, "aud_tdm_clk"},
429
{"TDM", NULL, "TDM_BCK"},
430
{"TDM_BCK", NULL, "TDM_MCK"},
431
{"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect},
432
{"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect},
433
};
434
435
/* dai ops */
436
static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe,
437
struct mtk_afe_tdm_priv *tdm_priv,
438
int freq)
439
{
440
int apll;
441
int apll_rate;
442
443
apll = mt8183_get_apll_by_rate(afe, freq);
444
apll_rate = mt8183_get_apll_rate(afe, apll);
445
446
if (!freq || freq > apll_rate) {
447
dev_warn(afe->dev,
448
"%s(), freq(%d Hz) invalid\n", __func__, freq);
449
return -EINVAL;
450
}
451
452
if (apll_rate % freq != 0) {
453
dev_warn(afe->dev,
454
"%s(), APLL cannot generate %d Hz", __func__, freq);
455
return -EINVAL;
456
}
457
458
tdm_priv->mclk_rate = freq;
459
tdm_priv->mclk_apll = apll;
460
461
return 0;
462
}
463
464
static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
465
struct snd_pcm_hw_params *params,
466
struct snd_soc_dai *dai)
467
{
468
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
469
struct mt8183_afe_private *afe_priv = afe->platform_priv;
470
int tdm_id = dai->id;
471
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[tdm_id];
472
unsigned int tdm_out_mode = tdm_priv->tdm_out_mode;
473
unsigned int rate = params_rate(params);
474
unsigned int channels = params_channels(params);
475
unsigned int out_channels_per_sdata =
476
get_tdm_ch_per_sdata(tdm_out_mode, channels);
477
snd_pcm_format_t format = params_format(params);
478
unsigned int tdm_con = 0;
479
480
/* calculate mclk_rate, if not set explicitly */
481
if (!tdm_priv->mclk_rate) {
482
tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple;
483
mtk_dai_tdm_cal_mclk(afe,
484
tdm_priv,
485
tdm_priv->mclk_rate);
486
}
487
488
/* calculate bck */
489
tdm_priv->bck_rate = rate *
490
out_channels_per_sdata *
491
snd_pcm_format_physical_width(format);
492
493
if (tdm_priv->bck_rate > tdm_priv->mclk_rate)
494
dev_warn(afe->dev, "%s(), bck_rate > mclk_rate rate", __func__);
495
496
if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0)
497
dev_warn(afe->dev, "%s(), bck cannot generate", __func__);
498
499
dev_info(afe->dev, "%s(), id %d, rate %d, channels %d, format %d, mclk_rate %d, bck_rate %d\n",
500
__func__,
501
tdm_id, rate, channels, format,
502
tdm_priv->mclk_rate, tdm_priv->bck_rate);
503
dev_info(afe->dev, "%s(), out_channels_per_sdata = %d\n",
504
__func__, out_channels_per_sdata);
505
506
/* set tdm */
507
if (tdm_priv->bck_invert)
508
regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,
509
BCK_INVERSE_MASK_SFT,
510
0x1 << BCK_INVERSE_SFT);
511
512
if (tdm_priv->lck_invert)
513
tdm_con |= 1 << LRCK_INVERSE_SFT;
514
515
if (tdm_priv->tdm_out_mode == TDM_OUT_I2S) {
516
tdm_con |= 1 << DELAY_DATA_SFT;
517
tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT;
518
} else if (tdm_priv->tdm_out_mode == TDM_OUT_TDM) {
519
tdm_con |= 0 << DELAY_DATA_SFT;
520
tdm_con |= 0 << LRCK_TDM_WIDTH_SFT;
521
}
522
523
tdm_con |= 1 << LEFT_ALIGN_SFT;
524
tdm_con |= get_tdm_wlen(format) << WLEN_SFT;
525
tdm_con |= get_tdm_ch(out_channels_per_sdata) << CHANNEL_NUM_SFT;
526
tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT;
527
regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con);
528
529
if (out_channels_per_sdata == 2) {
530
switch (channels) {
531
case 1:
532
case 2:
533
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
534
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
535
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
536
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
537
break;
538
case 3:
539
case 4:
540
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
541
tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
542
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
543
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
544
break;
545
case 5:
546
case 6:
547
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
548
tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
549
tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
550
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
551
break;
552
case 7:
553
case 8:
554
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
555
tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT;
556
tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT;
557
tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT;
558
break;
559
default:
560
tdm_con = 0;
561
}
562
} else {
563
tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT;
564
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT;
565
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT;
566
tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT;
567
}
568
569
regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con);
570
571
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
572
AFE_HDMI_OUT_CH_NUM_MASK_SFT,
573
channels << AFE_HDMI_OUT_CH_NUM_SFT);
574
575
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
576
AFE_HDMI_OUT_BIT_WIDTH_MASK_SFT,
577
get_hdmi_wlen(format) << AFE_HDMI_OUT_BIT_WIDTH_SFT);
578
return 0;
579
}
580
581
static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream,
582
int cmd,
583
struct snd_soc_dai *dai)
584
{
585
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
586
587
switch (cmd) {
588
case SNDRV_PCM_TRIGGER_START:
589
case SNDRV_PCM_TRIGGER_RESUME:
590
/* enable Out control */
591
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
592
AFE_HDMI_OUT_ON_MASK_SFT,
593
0x1 << AFE_HDMI_OUT_ON_SFT);
594
/* enable tdm */
595
regmap_update_bits(afe->regmap, AFE_TDM_CON1,
596
TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT);
597
break;
598
case SNDRV_PCM_TRIGGER_STOP:
599
case SNDRV_PCM_TRIGGER_SUSPEND:
600
/* disable tdm */
601
regmap_update_bits(afe->regmap, AFE_TDM_CON1,
602
TDM_EN_MASK_SFT, 0);
603
/* disable Out control */
604
regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0,
605
AFE_HDMI_OUT_ON_MASK_SFT,
606
0);
607
break;
608
default:
609
return -EINVAL;
610
}
611
612
return 0;
613
}
614
615
static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai,
616
int clk_id, unsigned int freq, int dir)
617
{
618
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
619
struct mt8183_afe_private *afe_priv = afe->platform_priv;
620
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
621
622
if (!tdm_priv) {
623
dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
624
return -EINVAL;
625
}
626
627
if (dir != SND_SOC_CLOCK_OUT) {
628
dev_warn(afe->dev, "%s(), dir != SND_SOC_CLOCK_OUT", __func__);
629
return -EINVAL;
630
}
631
632
dev_info(afe->dev, "%s(), freq %d\n", __func__, freq);
633
634
return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq);
635
}
636
637
static int mtk_dai_tdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
638
{
639
struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
640
struct mt8183_afe_private *afe_priv = afe->platform_priv;
641
struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai->id];
642
643
if (!tdm_priv) {
644
dev_warn(afe->dev, "%s(), tdm_priv == NULL", __func__);
645
return -EINVAL;
646
}
647
648
/* DAI mode*/
649
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
650
case SND_SOC_DAIFMT_I2S:
651
tdm_priv->tdm_out_mode = TDM_OUT_I2S;
652
break;
653
case SND_SOC_DAIFMT_DSP_A:
654
tdm_priv->tdm_out_mode = TDM_OUT_TDM;
655
break;
656
default:
657
tdm_priv->tdm_out_mode = TDM_OUT_I2S;
658
}
659
660
/* DAI clock inversion*/
661
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
662
case SND_SOC_DAIFMT_NB_NF:
663
tdm_priv->bck_invert = TDM_BCK_NON_INV;
664
tdm_priv->lck_invert = TDM_LCK_NON_INV;
665
break;
666
case SND_SOC_DAIFMT_NB_IF:
667
tdm_priv->bck_invert = TDM_BCK_NON_INV;
668
tdm_priv->lck_invert = TDM_LCK_INV;
669
break;
670
case SND_SOC_DAIFMT_IB_NF:
671
tdm_priv->bck_invert = TDM_BCK_INV;
672
tdm_priv->lck_invert = TDM_LCK_NON_INV;
673
break;
674
case SND_SOC_DAIFMT_IB_IF:
675
default:
676
tdm_priv->bck_invert = TDM_BCK_INV;
677
tdm_priv->lck_invert = TDM_LCK_INV;
678
break;
679
}
680
681
return 0;
682
}
683
684
static const struct snd_soc_dai_ops mtk_dai_tdm_ops = {
685
.hw_params = mtk_dai_tdm_hw_params,
686
.trigger = mtk_dai_tdm_trigger,
687
.set_sysclk = mtk_dai_tdm_set_sysclk,
688
.set_fmt = mtk_dai_tdm_set_fmt,
689
};
690
691
/* dai driver */
692
#define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\
693
SNDRV_PCM_RATE_88200 |\
694
SNDRV_PCM_RATE_96000 |\
695
SNDRV_PCM_RATE_176400 |\
696
SNDRV_PCM_RATE_192000)
697
698
#define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
699
SNDRV_PCM_FMTBIT_S24_LE |\
700
SNDRV_PCM_FMTBIT_S32_LE)
701
702
static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = {
703
{
704
.name = "TDM",
705
.id = MT8183_DAI_TDM,
706
.playback = {
707
.stream_name = "TDM",
708
.channels_min = 2,
709
.channels_max = 8,
710
.rates = MTK_TDM_RATES,
711
.formats = MTK_TDM_FORMATS,
712
},
713
.ops = &mtk_dai_tdm_ops,
714
},
715
};
716
717
int mt8183_dai_tdm_register(struct mtk_base_afe *afe)
718
{
719
struct mt8183_afe_private *afe_priv = afe->platform_priv;
720
struct mtk_afe_tdm_priv *tdm_priv;
721
struct mtk_base_afe_dai *dai;
722
723
dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
724
if (!dai)
725
return -ENOMEM;
726
727
list_add(&dai->list, &afe->sub_dais);
728
729
dai->dai_drivers = mtk_dai_tdm_driver;
730
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver);
731
732
dai->dapm_widgets = mtk_dai_tdm_widgets;
733
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets);
734
dai->dapm_routes = mtk_dai_tdm_routes;
735
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes);
736
737
tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv),
738
GFP_KERNEL);
739
if (!tdm_priv)
740
return -ENOMEM;
741
742
tdm_priv->mclk_multiple = 128;
743
tdm_priv->bck_id = MT8183_I2S4_BCK;
744
tdm_priv->mclk_id = MT8183_I2S4_MCK;
745
746
afe_priv->dai_priv[MT8183_DAI_TDM] = tdm_priv;
747
return 0;
748
}
749
750