1
2
3
4
5
6
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/rt5682.h>
20#include <sound/soc-acpi.h>
21#include "../../codecs/rt5682.h"
22#include "../../codecs/hdac_hdmi.h"
23#include "../common/soc-intel-quirks.h"
24
25#define NAME_SIZE 32
26
27#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0))
28#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0))
29#define SOF_RT5682_MCLK_EN BIT(3)
30#define SOF_RT5682_MCLK_24MHZ BIT(4)
31#define SOF_SPEAKER_AMP_PRESENT BIT(5)
32#define SOF_RT5682_SSP_AMP_SHIFT 6
33#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6))
34#define SOF_RT5682_SSP_AMP(quirk) \
35 (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK)
36#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9)
37
38
39static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
40 SOF_RT5682_SSP_CODEC(0);
41
42static int is_legacy_cpu;
43
44static struct snd_soc_jack sof_hdmi[3];
45
46struct sof_hdmi_pcm {
47 struct list_head head;
48 struct snd_soc_dai *codec_dai;
49 int device;
50};
51
52struct sof_card_private {
53 struct clk *mclk;
54 struct snd_soc_jack sof_headset;
55 struct list_head hdmi_pcm_list;
56};
57
58static int sof_rt5682_quirk_cb(const struct dmi_system_id *id)
59{
60 sof_rt5682_quirk = (unsigned long)id->driver_data;
61 return 1;
62}
63
64static const struct dmi_system_id sof_rt5682_quirk_table[] = {
65 {
66 .callback = sof_rt5682_quirk_cb,
67 .matches = {
68 DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
69 DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"),
70 },
71 .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
72 },
73 {
74 .callback = sof_rt5682_quirk_cb,
75 .matches = {
76 DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
77 DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"),
78 },
79 .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
80 },
81 {
82 .callback = sof_rt5682_quirk_cb,
83 .matches = {
84 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
85 DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
86 },
87 .driver_data = (void *)(SOF_RT5682_MCLK_EN |
88 SOF_RT5682_MCLK_24MHZ |
89 SOF_RT5682_SSP_CODEC(1)),
90 },
91 {
92 .callback = sof_rt5682_quirk_cb,
93 .matches = {
94 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
95 DMI_MATCH(DMI_PRODUCT_NAME, "Hatch"),
96 },
97 .driver_data = (void *)(SOF_RT5682_MCLK_EN |
98 SOF_RT5682_MCLK_24MHZ |
99 SOF_RT5682_SSP_CODEC(0) |
100 SOF_SPEAKER_AMP_PRESENT |
101 SOF_RT5682_SSP_AMP(1)),
102 },
103 {
104 .callback = sof_rt5682_quirk_cb,
105 .matches = {
106 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
107 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
108 },
109 .driver_data = (void *)(SOF_RT5682_MCLK_EN |
110 SOF_RT5682_SSP_CODEC(0)),
111 },
112 {}
113};
114
115static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
116{
117 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
118 struct snd_soc_dai *dai = rtd->codec_dai;
119 struct sof_hdmi_pcm *pcm;
120
121 pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
122 if (!pcm)
123 return -ENOMEM;
124
125
126 pcm->device = rtd->dai_link->id;
127 pcm->codec_dai = dai;
128
129 list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
130
131 return 0;
132}
133
134static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
135{
136 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
137 struct snd_soc_component *component = rtd->codec_dai->component;
138 struct snd_soc_jack *jack;
139 int ret;
140
141
142 if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) &&
143 (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) {
144 rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
145 RT5682_AD_STEREO1_FILTER,
146 RT5682_CLK_SEL_I2S1_ASRC);
147 }
148
149 if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
150
151
152
153
154
155
156
157
158
159
160 ret = clk_prepare_enable(ctx->mclk);
161 if (!ret)
162 clk_disable_unprepare(ctx->mclk);
163
164 ret = clk_set_rate(ctx->mclk, 19200000);
165
166 if (ret)
167 dev_err(rtd->dev, "unable to set MCLK rate\n");
168 }
169
170
171
172
173
174 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
175 SND_JACK_HEADSET | SND_JACK_BTN_0 |
176 SND_JACK_BTN_1 | SND_JACK_BTN_2 |
177 SND_JACK_BTN_3,
178 &ctx->sof_headset, NULL, 0);
179 if (ret) {
180 dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
181 return ret;
182 }
183
184 jack = &ctx->sof_headset;
185
186 snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
187 snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
188 snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
189 snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
190 ret = snd_soc_component_set_jack(component, jack, NULL);
191
192 if (ret) {
193 dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
194 return ret;
195 }
196
197 return ret;
198};
199
200static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
201 struct snd_pcm_hw_params *params)
202{
203 struct snd_soc_pcm_runtime *rtd = substream->private_data;
204 struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
205 struct snd_soc_dai *codec_dai = rtd->codec_dai;
206 int clk_id, clk_freq, pll_out, ret;
207
208 if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) {
209 if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
210 ret = clk_prepare_enable(ctx->mclk);
211 if (ret < 0) {
212 dev_err(rtd->dev,
213 "could not configure MCLK state");
214 return ret;
215 }
216 }
217
218 clk_id = RT5682_PLL1_S_MCLK;
219 if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)
220 clk_freq = 24000000;
221 else
222 clk_freq = 19200000;
223 } else {
224 clk_id = RT5682_PLL1_S_BCLK1;
225 clk_freq = params_rate(params) * 50;
226 }
227
228 pll_out = params_rate(params) * 512;
229
230 ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
231 if (ret < 0)
232 dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret);
233
234
235 ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
236 pll_out, SND_SOC_CLOCK_IN);
237 if (ret < 0)
238 dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
239
240
241
242
243
244 ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2,
245 params_width(params));
246 if (ret < 0) {
247 dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
248 return ret;
249 }
250
251 return ret;
252}
253
254static struct snd_soc_ops sof_rt5682_ops = {
255 .hw_params = sof_rt5682_hw_params,
256};
257
258static struct snd_soc_dai_link_component platform_component[] = {
259 {
260
261 .name = "0000:00:1f.3"
262 }
263};
264
265static int sof_card_late_probe(struct snd_soc_card *card)
266{
267 struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
268 struct snd_soc_component *component = NULL;
269 char jack_name[NAME_SIZE];
270 struct sof_hdmi_pcm *pcm;
271 int err = 0;
272 int i = 0;
273
274
275 if (is_legacy_cpu)
276 return 0;
277
278 list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
279 component = pcm->codec_dai->component;
280 snprintf(jack_name, sizeof(jack_name),
281 "HDMI/DP, pcm=%d Jack", pcm->device);
282 err = snd_soc_card_jack_new(card, jack_name,
283 SND_JACK_AVOUT, &sof_hdmi[i],
284 NULL, 0);
285
286 if (err)
287 return err;
288
289 err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
290 &sof_hdmi[i]);
291 if (err < 0)
292 return err;
293
294 i++;
295 }
296 if (!component)
297 return -EINVAL;
298
299 return hdac_hdmi_jack_port_init(component, &card->dapm);
300}
301
302static const struct snd_kcontrol_new sof_controls[] = {
303 SOC_DAPM_PIN_SWITCH("Headphone Jack"),
304 SOC_DAPM_PIN_SWITCH("Headset Mic"),
305 SOC_DAPM_PIN_SWITCH("Spk"),
306};
307
308static const struct snd_soc_dapm_widget sof_widgets[] = {
309 SND_SOC_DAPM_HP("Headphone Jack", NULL),
310 SND_SOC_DAPM_MIC("Headset Mic", NULL),
311 SND_SOC_DAPM_SPK("Spk", NULL),
312};
313
314static const struct snd_soc_dapm_route sof_map[] = {
315
316 { "Headphone Jack", NULL, "HPOL" },
317 { "Headphone Jack", NULL, "HPOR" },
318
319
320 { "IN1P", NULL, "Headset Mic" },
321
322};
323
324static const struct snd_soc_dapm_route speaker_map[] = {
325
326 { "Spk", NULL, "Speaker" },
327};
328
329static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
330{
331 struct snd_soc_card *card = rtd->card;
332 int ret;
333
334 ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map,
335 ARRAY_SIZE(speaker_map));
336
337 if (ret)
338 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
339 return ret;
340}
341
342
343static struct snd_soc_card sof_audio_card_rt5682 = {
344 .name = "sof_rt5682",
345 .owner = THIS_MODULE,
346 .controls = sof_controls,
347 .num_controls = ARRAY_SIZE(sof_controls),
348 .dapm_widgets = sof_widgets,
349 .num_dapm_widgets = ARRAY_SIZE(sof_widgets),
350 .dapm_routes = sof_map,
351 .num_dapm_routes = ARRAY_SIZE(sof_map),
352 .fully_routed = true,
353 .late_probe = sof_card_late_probe,
354};
355
356static struct snd_soc_dai_link_component rt5682_component[] = {
357 {
358 .name = "i2c-10EC5682:00",
359 .dai_name = "rt5682-aif1",
360 }
361};
362
363static struct snd_soc_dai_link_component dmic_component[] = {
364 {
365 .name = "dmic-codec",
366 .dai_name = "dmic-hifi",
367 }
368};
369
370static struct snd_soc_dai_link_component max98357a_component[] = {
371 {
372 .name = "MX98357A:00",
373 .dai_name = "HiFi",
374 }
375};
376
377static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
378 int ssp_codec,
379 int ssp_amp,
380 int dmic_be_num,
381 int hdmi_num)
382{
383 struct snd_soc_dai_link_component *idisp_components;
384 struct snd_soc_dai_link_component *cpus;
385 struct snd_soc_dai_link *links;
386 int i, id = 0;
387
388 links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
389 sof_audio_card_rt5682.num_links, GFP_KERNEL);
390 cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
391 sof_audio_card_rt5682.num_links, GFP_KERNEL);
392 if (!links || !cpus)
393 goto devm_err;
394
395
396 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
397 "SSP%d-Codec", ssp_codec);
398 if (!links[id].name)
399 goto devm_err;
400
401 links[id].id = id;
402 links[id].codecs = rt5682_component;
403 links[id].num_codecs = ARRAY_SIZE(rt5682_component);
404 links[id].platforms = platform_component;
405 links[id].num_platforms = ARRAY_SIZE(platform_component);
406 links[id].init = sof_rt5682_codec_init;
407 links[id].ops = &sof_rt5682_ops;
408 links[id].nonatomic = true;
409 links[id].dpcm_playback = 1;
410 links[id].dpcm_capture = 1;
411 links[id].no_pcm = 1;
412 links[id].cpus = &cpus[id];
413 links[id].num_cpus = 1;
414 if (is_legacy_cpu) {
415 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
416 "ssp%d-port",
417 ssp_codec);
418 if (!links[id].cpus->dai_name)
419 goto devm_err;
420 } else {
421
422
423
424
425
426
427
428
429
430 links[id].ignore_pmdown_time = 1;
431 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
432 "SSP%d Pin",
433 ssp_codec);
434 if (!links[id].cpus->dai_name)
435 goto devm_err;
436 }
437 id++;
438
439
440 if (dmic_be_num > 0) {
441
442 links[id].name = "dmic01";
443 links[id].cpus = &cpus[id];
444 links[id].cpus->dai_name = "DMIC01 Pin";
445 if (dmic_be_num > 1) {
446
447 links[id + 1].name = "dmic16k";
448 links[id + 1].cpus = &cpus[id + 1];
449 links[id + 1].cpus->dai_name = "DMIC16k Pin";
450 dmic_be_num = 2;
451 }
452 }
453
454 for (i = 0; i < dmic_be_num; i++) {
455 links[id].id = id;
456 links[id].num_cpus = 1;
457 links[id].codecs = dmic_component;
458 links[id].num_codecs = ARRAY_SIZE(dmic_component);
459 links[id].platforms = platform_component;
460 links[id].num_platforms = ARRAY_SIZE(platform_component);
461 links[id].ignore_suspend = 1;
462 links[id].dpcm_capture = 1;
463 links[id].no_pcm = 1;
464 id++;
465 }
466
467
468 if (hdmi_num > 0) {
469 idisp_components = devm_kzalloc(dev,
470 sizeof(struct snd_soc_dai_link_component) *
471 hdmi_num, GFP_KERNEL);
472 if (!idisp_components)
473 goto devm_err;
474 }
475 for (i = 1; i <= hdmi_num; i++) {
476 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
477 "iDisp%d", i);
478 if (!links[id].name)
479 goto devm_err;
480
481 links[id].id = id;
482 links[id].cpus = &cpus[id];
483 links[id].num_cpus = 1;
484 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
485 "iDisp%d Pin", i);
486 if (!links[id].cpus->dai_name)
487 goto devm_err;
488
489 idisp_components[i - 1].name = "ehdaudio0D2";
490 idisp_components[i - 1].dai_name = devm_kasprintf(dev,
491 GFP_KERNEL,
492 "intel-hdmi-hifi%d",
493 i);
494 if (!idisp_components[i - 1].dai_name)
495 goto devm_err;
496
497 links[id].codecs = &idisp_components[i - 1];
498 links[id].num_codecs = 1;
499 links[id].platforms = platform_component;
500 links[id].num_platforms = ARRAY_SIZE(platform_component);
501 links[id].init = sof_hdmi_init;
502 links[id].dpcm_playback = 1;
503 links[id].no_pcm = 1;
504 id++;
505 }
506
507
508 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) {
509 links[id].name = devm_kasprintf(dev, GFP_KERNEL,
510 "SSP%d-Codec", ssp_amp);
511 if (!links[id].name)
512 goto devm_err;
513
514 links[id].id = id;
515 links[id].codecs = max98357a_component;
516 links[id].num_codecs = ARRAY_SIZE(max98357a_component);
517 links[id].platforms = platform_component;
518 links[id].num_platforms = ARRAY_SIZE(platform_component);
519 links[id].init = speaker_codec_init,
520 links[id].nonatomic = true;
521 links[id].dpcm_playback = 1;
522 links[id].no_pcm = 1;
523 links[id].cpus = &cpus[id];
524 links[id].num_cpus = 1;
525 if (is_legacy_cpu) {
526 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
527 "ssp%d-port",
528 ssp_amp);
529 if (!links[id].cpus->dai_name)
530 goto devm_err;
531
532 } else {
533 links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
534 "SSP%d Pin",
535 ssp_amp);
536 if (!links[id].cpus->dai_name)
537 goto devm_err;
538 }
539 }
540
541 return links;
542devm_err:
543 return NULL;
544}
545
546static int sof_audio_probe(struct platform_device *pdev)
547{
548 struct snd_soc_dai_link *dai_links;
549 struct snd_soc_acpi_mach *mach;
550 struct sof_card_private *ctx;
551 int dmic_be_num, hdmi_num;
552 int ret, ssp_amp, ssp_codec;
553
554 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
555 if (!ctx)
556 return -ENOMEM;
557
558 if (soc_intel_is_byt() || soc_intel_is_cht()) {
559 is_legacy_cpu = 1;
560 dmic_be_num = 0;
561 hdmi_num = 0;
562
563 sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
564 SOF_RT5682_MCLK_BYTCHT_EN |
565 SOF_RT5682_SSP_CODEC(2);
566 } else {
567 dmic_be_num = 2;
568 hdmi_num = 3;
569 }
570
571 dmi_check_system(sof_rt5682_quirk_table);
572
573
574 if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
575 ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
576 ret = clk_prepare_enable(ctx->mclk);
577 if (ret < 0) {
578 dev_err(&pdev->dev,
579 "could not configure MCLK state");
580 return ret;
581 }
582 }
583
584 dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
585
586 ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >>
587 SOF_RT5682_SSP_AMP_SHIFT;
588
589 ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK;
590
591
592 sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num;
593
594 if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT)
595 sof_audio_card_rt5682.num_links++;
596
597 dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
598 dmic_be_num, hdmi_num);
599 if (!dai_links)
600 return -ENOMEM;
601
602 sof_audio_card_rt5682.dai_link = dai_links;
603
604 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
605
606 sof_audio_card_rt5682.dev = &pdev->dev;
607 mach = (&pdev->dev)->platform_data;
608
609
610 ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682,
611 mach->mach_params.platform);
612 if (ret)
613 return ret;
614
615 snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx);
616
617 return devm_snd_soc_register_card(&pdev->dev,
618 &sof_audio_card_rt5682);
619}
620
621static struct platform_driver sof_audio = {
622 .probe = sof_audio_probe,
623 .driver = {
624 .name = "sof_rt5682",
625 .pm = &snd_soc_pm_ops,
626 },
627};
628module_platform_driver(sof_audio)
629
630
631MODULE_DESCRIPTION("SOF Audio Machine driver");
632MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>");
633MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
634MODULE_LICENSE("GPL v2");
635MODULE_ALIAS("platform:sof_rt5682");
636