Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/intel/boards/sof_rt5682.c
26493 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
// Copyright(c) 2019-2020 Intel Corporation.
3
4
/*
5
* Intel SOF Machine Driver with Realtek rt5682 Codec
6
* and speaker codec MAX98357A or RT1015.
7
*/
8
#include <linux/i2c.h>
9
#include <linux/input.h>
10
#include <linux/module.h>
11
#include <linux/platform_device.h>
12
#include <linux/clk.h>
13
#include <linux/dmi.h>
14
#include <sound/core.h>
15
#include <sound/jack.h>
16
#include <sound/pcm.h>
17
#include <sound/pcm_params.h>
18
#include <sound/soc.h>
19
#include <sound/sof.h>
20
#include <sound/rt5682.h>
21
#include <sound/rt5682s.h>
22
#include <sound/soc-acpi.h>
23
#include "../../codecs/rt5682.h"
24
#include "../../codecs/rt5682s.h"
25
#include "../../codecs/rt5645.h"
26
#include "../common/soc-intel-quirks.h"
27
#include "sof_board_helpers.h"
28
#include "sof_maxim_common.h"
29
#include "sof_realtek_common.h"
30
31
/* Driver-specific board quirks: from bit 0 to 7 */
32
#define SOF_RT5682_MCLK_EN BIT(0)
33
34
/* Default: MCLK on, MCLK 19.2M, SSP0 */
35
static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
36
SOF_SSP_PORT_CODEC(0);
37
38
static int sof_rt5682_quirk_cb(const struct dmi_system_id *id)
39
{
40
sof_rt5682_quirk = (unsigned long)id->driver_data;
41
return 1;
42
}
43
44
static const struct dmi_system_id sof_rt5682_quirk_table[] = {
45
{
46
.callback = sof_rt5682_quirk_cb,
47
.matches = {
48
DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
49
DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"),
50
},
51
.driver_data = (void *)(SOF_SSP_PORT_CODEC(2)),
52
},
53
{
54
.callback = sof_rt5682_quirk_cb,
55
.matches = {
56
DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
57
DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"),
58
},
59
.driver_data = (void *)(SOF_SSP_PORT_CODEC(2)),
60
},
61
{
62
.callback = sof_rt5682_quirk_cb,
63
.matches = {
64
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
65
DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
66
},
67
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
68
SOF_SSP_PORT_CODEC(1)),
69
},
70
{
71
.callback = sof_rt5682_quirk_cb,
72
.matches = {
73
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"),
74
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"),
75
},
76
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
77
SOF_SSP_PORT_CODEC(0) |
78
SOF_SSP_PORT_AMP(2) |
79
SOF_NUM_IDISP_HDMI(4)),
80
},
81
{
82
.callback = sof_rt5682_quirk_cb,
83
.matches = {
84
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
85
DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
86
DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"),
87
},
88
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
89
SOF_SSP_PORT_CODEC(0) |
90
SOF_SSP_PORT_AMP(2) |
91
SOF_NUM_IDISP_HDMI(4)),
92
},
93
{
94
.callback = sof_rt5682_quirk_cb,
95
.matches = {
96
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
97
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"),
98
},
99
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
100
SOF_SSP_PORT_CODEC(0) |
101
SOF_SSP_PORT_AMP(2) |
102
SOF_NUM_IDISP_HDMI(4)),
103
},
104
{
105
.callback = sof_rt5682_quirk_cb,
106
.matches = {
107
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Brya"),
108
DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"),
109
},
110
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
111
SOF_SSP_PORT_CODEC(0) |
112
SOF_SSP_PORT_AMP(2) |
113
SOF_NUM_IDISP_HDMI(4)),
114
},
115
{
116
.callback = sof_rt5682_quirk_cb,
117
.matches = {
118
DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Rex"),
119
},
120
.driver_data = (void *)(SOF_RT5682_MCLK_EN |
121
SOF_SSP_PORT_CODEC(2) |
122
SOF_SSP_PORT_AMP(0) |
123
SOF_SSP_PORT_BT_OFFLOAD(1) |
124
SOF_BT_OFFLOAD_PRESENT
125
),
126
},
127
{}
128
};
129
130
static struct snd_soc_jack_pin jack_pins[] = {
131
{
132
.pin = "Headphone Jack",
133
.mask = SND_JACK_HEADPHONE,
134
},
135
{
136
.pin = "Headset Mic",
137
.mask = SND_JACK_MICROPHONE,
138
},
139
};
140
141
static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
142
{
143
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
144
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
145
struct snd_soc_jack *jack = &ctx->headset_jack;
146
int extra_jack_data;
147
int ret, mclk_freq;
148
149
if (ctx->rt5682.mclk_en) {
150
mclk_freq = sof_dai_get_mclk(rtd);
151
if (mclk_freq <= 0) {
152
dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_freq);
153
return -EINVAL;
154
}
155
156
/* need to enable ASRC function for 24MHz mclk rate */
157
if (mclk_freq == 24000000) {
158
dev_info(rtd->dev, "enable ASRC\n");
159
160
switch (ctx->codec_type) {
161
case CODEC_RT5650:
162
rt5645_sel_asrc_clk_src(component,
163
RT5645_DA_STEREO_FILTER |
164
RT5645_AD_STEREO_FILTER,
165
RT5645_CLK_SEL_I2S1_ASRC);
166
rt5645_sel_asrc_clk_src(component,
167
RT5645_DA_MONO_L_FILTER |
168
RT5645_DA_MONO_R_FILTER,
169
RT5645_CLK_SEL_I2S2_ASRC);
170
break;
171
case CODEC_RT5682:
172
rt5682_sel_asrc_clk_src(component,
173
RT5682_DA_STEREO1_FILTER |
174
RT5682_AD_STEREO1_FILTER,
175
RT5682_CLK_SEL_I2S1_ASRC);
176
break;
177
case CODEC_RT5682S:
178
rt5682s_sel_asrc_clk_src(component,
179
RT5682S_DA_STEREO1_FILTER |
180
RT5682S_AD_STEREO1_FILTER,
181
RT5682S_CLK_SEL_I2S1_ASRC);
182
break;
183
default:
184
dev_err(rtd->dev, "invalid codec type %d\n",
185
ctx->codec_type);
186
return -EINVAL;
187
}
188
}
189
190
if (ctx->rt5682.is_legacy_cpu) {
191
/*
192
* The firmware might enable the clock at
193
* boot (this information may or may not
194
* be reflected in the enable clock register).
195
* To change the rate we must disable the clock
196
* first to cover these cases. Due to common
197
* clock framework restrictions that do not allow
198
* to disable a clock that has not been enabled,
199
* we need to enable the clock first.
200
*/
201
ret = clk_prepare_enable(ctx->rt5682.mclk);
202
if (!ret)
203
clk_disable_unprepare(ctx->rt5682.mclk);
204
205
ret = clk_set_rate(ctx->rt5682.mclk, 19200000);
206
207
if (ret)
208
dev_err(rtd->dev, "unable to set MCLK rate\n");
209
}
210
}
211
212
/*
213
* Headset buttons map to the google Reference headset.
214
* These can be configured by userspace.
215
*/
216
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
217
SND_JACK_HEADSET | SND_JACK_BTN_0 |
218
SND_JACK_BTN_1 | SND_JACK_BTN_2 |
219
SND_JACK_BTN_3,
220
jack,
221
jack_pins,
222
ARRAY_SIZE(jack_pins));
223
if (ret) {
224
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
225
return ret;
226
}
227
228
snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
229
snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
230
snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
231
snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
232
233
if (ctx->codec_type == CODEC_RT5650) {
234
extra_jack_data = SND_JACK_MICROPHONE | SND_JACK_BTN_0;
235
ret = snd_soc_component_set_jack(component, jack, &extra_jack_data);
236
} else
237
ret = snd_soc_component_set_jack(component, jack, NULL);
238
239
if (ret) {
240
dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
241
return ret;
242
}
243
244
return ret;
245
};
246
247
static void sof_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd)
248
{
249
struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component;
250
251
snd_soc_component_set_jack(component, NULL, NULL);
252
}
253
254
static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
255
struct snd_pcm_hw_params *params)
256
{
257
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
258
struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
259
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
260
int pll_id, pll_source, pll_in, pll_out, clk_id, ret;
261
262
if (ctx->rt5682.mclk_en) {
263
if (ctx->rt5682.is_legacy_cpu) {
264
ret = clk_prepare_enable(ctx->rt5682.mclk);
265
if (ret < 0) {
266
dev_err(rtd->dev,
267
"could not configure MCLK state");
268
return ret;
269
}
270
}
271
272
switch (ctx->codec_type) {
273
case CODEC_RT5650:
274
pll_source = RT5645_PLL1_S_MCLK;
275
break;
276
case CODEC_RT5682:
277
pll_source = RT5682_PLL1_S_MCLK;
278
break;
279
case CODEC_RT5682S:
280
pll_source = RT5682S_PLL_S_MCLK;
281
break;
282
default:
283
dev_err(rtd->dev, "invalid codec type %d\n",
284
ctx->codec_type);
285
return -EINVAL;
286
}
287
288
/* get the tplg configured mclk. */
289
pll_in = sof_dai_get_mclk(rtd);
290
if (pll_in <= 0) {
291
dev_err(rtd->dev, "invalid mclk freq %d\n", pll_in);
292
return -EINVAL;
293
}
294
} else {
295
switch (ctx->codec_type) {
296
case CODEC_RT5650:
297
pll_source = RT5645_PLL1_S_BCLK1;
298
break;
299
case CODEC_RT5682:
300
pll_source = RT5682_PLL1_S_BCLK1;
301
break;
302
case CODEC_RT5682S:
303
pll_source = RT5682S_PLL_S_BCLK1;
304
break;
305
default:
306
dev_err(rtd->dev, "invalid codec type %d\n",
307
ctx->codec_type);
308
return -EINVAL;
309
}
310
311
/* get the tplg configured bclk. */
312
pll_in = sof_dai_get_bclk(rtd);
313
if (pll_in <= 0) {
314
dev_err(rtd->dev, "invalid bclk freq %d\n", pll_in);
315
return -EINVAL;
316
}
317
}
318
319
pll_out = params_rate(params) * 512;
320
321
/* when MCLK is 512FS, no need to set PLL configuration additionally. */
322
if (pll_in == pll_out) {
323
switch (ctx->codec_type) {
324
case CODEC_RT5650:
325
clk_id = RT5645_SCLK_S_MCLK;
326
break;
327
case CODEC_RT5682:
328
clk_id = RT5682_SCLK_S_MCLK;
329
break;
330
case CODEC_RT5682S:
331
clk_id = RT5682S_SCLK_S_MCLK;
332
break;
333
default:
334
dev_err(rtd->dev, "invalid codec type %d\n",
335
ctx->codec_type);
336
return -EINVAL;
337
}
338
} else {
339
switch (ctx->codec_type) {
340
case CODEC_RT5650:
341
pll_id = 0; /* not used in codec driver */
342
clk_id = RT5645_SCLK_S_PLL1;
343
break;
344
case CODEC_RT5682:
345
pll_id = RT5682_PLL1;
346
clk_id = RT5682_SCLK_S_PLL1;
347
break;
348
case CODEC_RT5682S:
349
/* check plla_table and pllb_table in rt5682s.c */
350
switch (pll_in) {
351
case 3072000:
352
case 24576000:
353
/*
354
* For MCLK = 24.576MHz and sample rate = 96KHz case, use PLL1 We don't test
355
* pll_out or params_rate() here since rt5682s PLL2 doesn't support 24.576MHz
356
* input, so we have no choice but to use PLL1. Besides, we will not use PLL at
357
* all if pll_in == pll_out. ex, MCLK = 24.576Mhz and sample rate = 48KHz
358
*/
359
pll_id = RT5682S_PLL1;
360
clk_id = RT5682S_SCLK_S_PLL1;
361
break;
362
default:
363
pll_id = RT5682S_PLL2;
364
clk_id = RT5682S_SCLK_S_PLL2;
365
break;
366
}
367
break;
368
default:
369
dev_err(rtd->dev, "invalid codec type %d\n", ctx->codec_type);
370
return -EINVAL;
371
}
372
373
/* Configure pll for codec */
374
ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, pll_in,
375
pll_out);
376
if (ret < 0)
377
dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret);
378
}
379
380
/* Configure sysclk for codec */
381
ret = snd_soc_dai_set_sysclk(codec_dai, clk_id,
382
pll_out, SND_SOC_CLOCK_IN);
383
if (ret < 0)
384
dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
385
386
/*
387
* slot_width should equal or large than data length, set them
388
* be the same
389
*/
390
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2,
391
params_width(params));
392
if (ret < 0) {
393
dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
394
return ret;
395
}
396
397
return ret;
398
}
399
400
static const struct snd_soc_ops sof_rt5682_ops = {
401
.hw_params = sof_rt5682_hw_params,
402
};
403
404
static int sof_card_late_probe(struct snd_soc_card *card)
405
{
406
struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
407
struct snd_soc_dapm_context *dapm = &card->dapm;
408
int err;
409
410
if (ctx->amp_type == CODEC_MAX98373) {
411
/* Disable Left and Right Spk pin after boot */
412
snd_soc_dapm_disable_pin(dapm, "Left Spk");
413
snd_soc_dapm_disable_pin(dapm, "Right Spk");
414
err = snd_soc_dapm_sync(dapm);
415
if (err < 0)
416
return err;
417
}
418
419
return sof_intel_board_card_late_probe(card);
420
}
421
422
static const struct snd_kcontrol_new sof_controls[] = {
423
SOC_DAPM_PIN_SWITCH("Headphone Jack"),
424
SOC_DAPM_PIN_SWITCH("Headset Mic"),
425
};
426
427
static const struct snd_soc_dapm_widget sof_widgets[] = {
428
SND_SOC_DAPM_HP("Headphone Jack", NULL),
429
SND_SOC_DAPM_MIC("Headset Mic", NULL),
430
};
431
432
static const struct snd_soc_dapm_route sof_map[] = {
433
/* HP jack connectors - unknown if we have jack detection */
434
{ "Headphone Jack", NULL, "HPOL" },
435
{ "Headphone Jack", NULL, "HPOR" },
436
437
/* other jacks */
438
{ "IN1P", NULL, "Headset Mic" },
439
};
440
441
static const struct snd_kcontrol_new rt5650_spk_kcontrols[] = {
442
SOC_DAPM_PIN_SWITCH("Left Spk"),
443
SOC_DAPM_PIN_SWITCH("Right Spk"),
444
445
};
446
447
static const struct snd_soc_dapm_widget rt5650_spk_widgets[] = {
448
SND_SOC_DAPM_SPK("Left Spk", NULL),
449
SND_SOC_DAPM_SPK("Right Spk", NULL),
450
};
451
452
static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = {
453
/* speaker */
454
{ "Left Spk", NULL, "SPOL" },
455
{ "Right Spk", NULL, "SPOR" },
456
};
457
458
static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd)
459
{
460
struct snd_soc_card *card = rtd->card;
461
int ret;
462
463
ret = snd_soc_dapm_new_controls(&card->dapm, rt5650_spk_widgets,
464
ARRAY_SIZE(rt5650_spk_widgets));
465
if (ret) {
466
dev_err(rtd->dev, "fail to add rt5650 spk widgets, ret %d\n",
467
ret);
468
return ret;
469
}
470
471
ret = snd_soc_add_card_controls(card, rt5650_spk_kcontrols,
472
ARRAY_SIZE(rt5650_spk_kcontrols));
473
if (ret) {
474
dev_err(rtd->dev, "fail to add rt5650 spk kcontrols, ret %d\n",
475
ret);
476
return ret;
477
}
478
479
ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes,
480
ARRAY_SIZE(rt5650_spk_dapm_routes));
481
if (ret)
482
dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret);
483
484
return ret;
485
}
486
487
/* sof audio machine driver for rt5682 codec */
488
static struct snd_soc_card sof_audio_card_rt5682 = {
489
.name = "rt5682", /* the sof- prefix is added by the core */
490
.owner = THIS_MODULE,
491
.controls = sof_controls,
492
.num_controls = ARRAY_SIZE(sof_controls),
493
.dapm_widgets = sof_widgets,
494
.num_dapm_widgets = ARRAY_SIZE(sof_widgets),
495
.dapm_routes = sof_map,
496
.num_dapm_routes = ARRAY_SIZE(sof_map),
497
.fully_routed = true,
498
.late_probe = sof_card_late_probe,
499
};
500
501
static struct snd_soc_dai_link_component rt5682_component[] = {
502
{
503
.name = "i2c-10EC5682:00",
504
.dai_name = "rt5682-aif1",
505
}
506
};
507
508
static struct snd_soc_dai_link_component rt5682s_component[] = {
509
{
510
.name = "i2c-RTL5682:00",
511
.dai_name = "rt5682s-aif1",
512
}
513
};
514
515
static struct snd_soc_dai_link_component rt5650_components[] = {
516
{
517
.name = "i2c-10EC5650:00",
518
.dai_name = "rt5645-aif1",
519
},
520
{
521
.name = "i2c-10EC5650:00",
522
.dai_name = "rt5645-aif2",
523
}
524
};
525
526
static int
527
sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card,
528
struct sof_card_private *ctx)
529
{
530
int ret;
531
532
ret = sof_intel_board_set_dai_link(dev, card, ctx);
533
if (ret)
534
return ret;
535
536
if (!ctx->codec_link) {
537
dev_err(dev, "codec link not available");
538
return -EINVAL;
539
}
540
541
/* codec-specific fields for headphone codec */
542
switch (ctx->codec_type) {
543
case CODEC_RT5650:
544
ctx->codec_link->codecs = &rt5650_components[0];
545
ctx->codec_link->num_codecs = 1;
546
break;
547
case CODEC_RT5682:
548
ctx->codec_link->codecs = rt5682_component;
549
ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682_component);
550
break;
551
case CODEC_RT5682S:
552
ctx->codec_link->codecs = rt5682s_component;
553
ctx->codec_link->num_codecs = ARRAY_SIZE(rt5682s_component);
554
break;
555
default:
556
dev_err(dev, "invalid codec type %d\n", ctx->codec_type);
557
return -EINVAL;
558
}
559
560
ctx->codec_link->init = sof_rt5682_codec_init;
561
ctx->codec_link->exit = sof_rt5682_codec_exit;
562
ctx->codec_link->ops = &sof_rt5682_ops;
563
564
if (!ctx->rt5682.is_legacy_cpu) {
565
/*
566
* Currently, On SKL+ platforms MCLK will be turned off in sof
567
* runtime suspended, and it will go into runtime suspended
568
* right after playback is stop. However, rt5682 will output
569
* static noise if sysclk turns off during playback. Set
570
* ignore_pmdown_time to power down rt5682 immediately and
571
* avoid the noise.
572
* It can be removed once we can control MCLK by driver.
573
*/
574
ctx->codec_link->ignore_pmdown_time = 1;
575
}
576
577
if (ctx->amp_type == CODEC_NONE)
578
return 0;
579
580
if (!ctx->amp_link) {
581
dev_err(dev, "amp link not available");
582
return -EINVAL;
583
}
584
585
/* codec-specific fields for speaker amplifier */
586
switch (ctx->amp_type) {
587
case CODEC_MAX98357A:
588
max_98357a_dai_link(ctx->amp_link);
589
break;
590
case CODEC_MAX98360A:
591
max_98360a_dai_link(ctx->amp_link);
592
break;
593
case CODEC_MAX98373:
594
max_98373_dai_link(dev, ctx->amp_link);
595
break;
596
case CODEC_MAX98390:
597
max_98390_dai_link(dev, ctx->amp_link);
598
break;
599
case CODEC_RT1011:
600
sof_rt1011_dai_link(dev, ctx->amp_link);
601
break;
602
case CODEC_RT1015:
603
sof_rt1015_dai_link(ctx->amp_link);
604
break;
605
case CODEC_RT1015P:
606
sof_rt1015p_dai_link(ctx->amp_link);
607
break;
608
case CODEC_RT1019P:
609
sof_rt1019p_dai_link(ctx->amp_link);
610
break;
611
case CODEC_RT5650:
612
/* use AIF2 to support speaker pipeline */
613
ctx->amp_link->codecs = &rt5650_components[1];
614
ctx->amp_link->num_codecs = 1;
615
ctx->amp_link->init = rt5650_spk_init;
616
ctx->amp_link->ops = &sof_rt5682_ops;
617
break;
618
default:
619
dev_err(dev, "invalid amp type %d\n", ctx->amp_type);
620
return -EINVAL;
621
}
622
623
return 0;
624
}
625
626
#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \
627
SOF_LINK_CODEC, \
628
SOF_LINK_DMIC01, \
629
SOF_LINK_IDISP_HDMI, \
630
SOF_LINK_NONE, \
631
SOF_LINK_NONE, \
632
SOF_LINK_NONE)
633
634
static int sof_audio_probe(struct platform_device *pdev)
635
{
636
struct snd_soc_acpi_mach *mach = pdev->dev.platform_data;
637
struct sof_card_private *ctx;
638
char *card_name;
639
int ret;
640
641
if (pdev->id_entry && pdev->id_entry->driver_data)
642
sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
643
644
dmi_check_system(sof_rt5682_quirk_table);
645
646
dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
647
648
/* initialize ctx with board quirk */
649
ctx = sof_intel_board_get_ctx(&pdev->dev, sof_rt5682_quirk);
650
if (!ctx)
651
return -ENOMEM;
652
653
if (ctx->codec_type == CODEC_RT5650) {
654
card_name = devm_kstrdup(&pdev->dev, "rt5650", GFP_KERNEL);
655
if (!card_name)
656
return -ENOMEM;
657
658
sof_audio_card_rt5682.name = card_name;
659
660
/* create speaker dai link also */
661
if (ctx->amp_type == CODEC_NONE)
662
ctx->amp_type = CODEC_RT5650;
663
}
664
665
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
666
ctx->hdmi.idisp_codec = true;
667
668
if (soc_intel_is_byt() || soc_intel_is_cht()) {
669
ctx->rt5682.is_legacy_cpu = true;
670
ctx->dmic_be_num = 0;
671
/* HDMI is not supported by SOF on Baytrail/CherryTrail */
672
ctx->hdmi_num = 0;
673
} else if (soc_intel_is_glk()) {
674
/* dmic16k not support */
675
ctx->dmic_be_num = 1;
676
677
/* overwrite the DAI link order for GLK boards */
678
ctx->link_order_overwrite = GLK_LINK_ORDER;
679
680
/* backward-compatible with existing devices */
681
switch (ctx->amp_type) {
682
case CODEC_MAX98357A:
683
card_name = devm_kstrdup(&pdev->dev, "glkrt5682max",
684
GFP_KERNEL);
685
if (!card_name)
686
return -ENOMEM;
687
688
sof_audio_card_rt5682.name = card_name;
689
break;
690
default:
691
break;
692
}
693
} else if (soc_intel_is_cml()) {
694
/* backward-compatible with existing devices */
695
switch (ctx->amp_type) {
696
case CODEC_RT1011:
697
card_name = devm_kstrdup(&pdev->dev, "cml_rt1011_rt5682",
698
GFP_KERNEL);
699
if (!card_name)
700
return -ENOMEM;
701
702
sof_audio_card_rt5682.name = card_name;
703
break;
704
default:
705
break;
706
}
707
}
708
709
if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) {
710
ctx->rt5682.mclk_en = true;
711
712
/* need to get main clock from pmc */
713
if (ctx->rt5682.is_legacy_cpu) {
714
ctx->rt5682.mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
715
if (IS_ERR(ctx->rt5682.mclk)) {
716
ret = PTR_ERR(ctx->rt5682.mclk);
717
718
dev_err(&pdev->dev,
719
"Failed to get MCLK from pmc_plt_clk_3: %d\n",
720
ret);
721
return ret;
722
}
723
724
ret = clk_prepare_enable(ctx->rt5682.mclk);
725
if (ret < 0) {
726
dev_err(&pdev->dev,
727
"could not configure MCLK state");
728
return ret;
729
}
730
}
731
}
732
733
/* update dai_link */
734
ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx);
735
if (ret)
736
return ret;
737
738
/* update codec_conf */
739
switch (ctx->amp_type) {
740
case CODEC_MAX98373:
741
max_98373_set_codec_conf(&sof_audio_card_rt5682);
742
break;
743
case CODEC_MAX98390:
744
max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682);
745
break;
746
case CODEC_RT1011:
747
sof_rt1011_codec_conf(&pdev->dev, &sof_audio_card_rt5682);
748
break;
749
case CODEC_RT1015:
750
sof_rt1015_codec_conf(&sof_audio_card_rt5682);
751
break;
752
case CODEC_RT1015P:
753
sof_rt1015p_codec_conf(&sof_audio_card_rt5682);
754
break;
755
case CODEC_MAX98357A:
756
case CODEC_MAX98360A:
757
case CODEC_RT1019P:
758
case CODEC_RT5650:
759
case CODEC_NONE:
760
/* no codec conf required */
761
break;
762
default:
763
dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type);
764
return -EINVAL;
765
}
766
767
sof_audio_card_rt5682.dev = &pdev->dev;
768
769
/* set platform name for each dailink */
770
ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682,
771
mach->mach_params.platform);
772
if (ret)
773
return ret;
774
775
snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx);
776
777
return devm_snd_soc_register_card(&pdev->dev,
778
&sof_audio_card_rt5682);
779
}
780
781
static const struct platform_device_id board_ids[] = {
782
{
783
.name = "sof_rt5682",
784
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
785
SOF_SSP_PORT_CODEC(2)),
786
},
787
{
788
.name = "glk_rt5682_def",
789
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
790
SOF_SSP_PORT_CODEC(2) |
791
SOF_SSP_PORT_AMP(1)),
792
},
793
{
794
.name = "icl_rt5682_def",
795
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
796
SOF_SSP_PORT_CODEC(0)),
797
},
798
{
799
.name = "cml_rt5682_def",
800
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
801
SOF_SSP_PORT_CODEC(0) |
802
SOF_SSP_PORT_AMP(1)),
803
},
804
{
805
.name = "jsl_rt5682_def",
806
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
807
SOF_SSP_PORT_CODEC(0) |
808
SOF_SSP_PORT_AMP(1)),
809
},
810
{
811
.name = "tgl_rt5682_def",
812
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
813
SOF_SSP_PORT_CODEC(0) |
814
SOF_SSP_PORT_AMP(1) |
815
SOF_NUM_IDISP_HDMI(4) |
816
SOF_SSP_PORT_BT_OFFLOAD(2) |
817
SOF_BT_OFFLOAD_PRESENT),
818
},
819
{
820
.name = "adl_rt5682_def",
821
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
822
SOF_SSP_PORT_CODEC(0) |
823
SOF_SSP_PORT_AMP(1) |
824
SOF_NUM_IDISP_HDMI(4) |
825
SOF_SSP_PORT_BT_OFFLOAD(2) |
826
SOF_BT_OFFLOAD_PRESENT),
827
},
828
{
829
.name = "adl_mx98357_rt5682",
830
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
831
SOF_SSP_PORT_CODEC(0) |
832
SOF_SSP_PORT_AMP(2) |
833
SOF_NUM_IDISP_HDMI(4)),
834
},
835
{
836
.name = "adl_rt5682_c1_h02",
837
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
838
SOF_SSP_PORT_CODEC(1) |
839
/* SSP 0 and SSP 2 are used for HDMI IN */
840
SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
841
},
842
{
843
.name = "rpl_mx98357_rt5682",
844
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
845
SOF_SSP_PORT_CODEC(0) |
846
SOF_SSP_PORT_AMP(2) |
847
SOF_NUM_IDISP_HDMI(4)),
848
},
849
{
850
.name = "rpl_rt5682_def",
851
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
852
SOF_SSP_PORT_CODEC(0) |
853
SOF_SSP_PORT_AMP(1) |
854
SOF_NUM_IDISP_HDMI(4) |
855
SOF_SSP_PORT_BT_OFFLOAD(2) |
856
SOF_BT_OFFLOAD_PRESENT),
857
},
858
{
859
.name = "rpl_rt5682_c1_h02",
860
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
861
SOF_SSP_PORT_CODEC(1) |
862
/* SSP 0 and SSP 2 are used for HDMI IN */
863
SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
864
},
865
{
866
.name = "mtl_rt5682_def",
867
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
868
SOF_SSP_PORT_CODEC(0) |
869
SOF_SSP_PORT_AMP(1) |
870
SOF_SSP_PORT_BT_OFFLOAD(2) |
871
SOF_BT_OFFLOAD_PRESENT),
872
},
873
{
874
.name = "mtl_rt5682_c1_h02",
875
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
876
SOF_SSP_PORT_CODEC(1) |
877
/* SSP 0 and SSP 2 are used for HDMI IN */
878
SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
879
},
880
{
881
.name = "arl_rt5682_c1_h02",
882
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
883
SOF_SSP_PORT_CODEC(1) |
884
/* SSP 0 and SSP 2 are used for HDMI IN */
885
SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
886
},
887
{
888
.name = "ptl_rt5682_def",
889
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
890
SOF_SSP_PORT_CODEC(0) |
891
SOF_SSP_PORT_AMP(1) |
892
SOF_SSP_PORT_BT_OFFLOAD(2) |
893
SOF_BT_OFFLOAD_PRESENT),
894
},
895
{
896
.name = "ptl_rt5682_c1_h02",
897
.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
898
SOF_SSP_PORT_CODEC(1) |
899
/* SSP 0 and SSP 2 are used for HDMI IN */
900
SOF_SSP_MASK_HDMI_CAPTURE(0x5)),
901
},
902
{ }
903
};
904
MODULE_DEVICE_TABLE(platform, board_ids);
905
906
static struct platform_driver sof_audio = {
907
.probe = sof_audio_probe,
908
.driver = {
909
.name = "sof_rt5682",
910
.pm = &snd_soc_pm_ops,
911
},
912
.id_table = board_ids,
913
};
914
module_platform_driver(sof_audio)
915
916
/* Module information */
917
MODULE_DESCRIPTION("SOF Audio Machine driver");
918
MODULE_AUTHOR("Bard Liao <[email protected]>");
919
MODULE_AUTHOR("Sathya Prakash M R <[email protected]>");
920
MODULE_AUTHOR("Brent Lu <[email protected]>");
921
MODULE_AUTHOR("Mac Chiang <[email protected]>");
922
MODULE_LICENSE("GPL v2");
923
MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS");
924
MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON");
925
MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON");
926
927