xref: /linux/sound/soc/intel/boards/sof_rt5682.c (revision a6d5f9dca42eab3526e2f73aa5b7df2a5fec2c9d)
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright(c) 2019 Intel Corporation.
3 
4 /*
5  * Intel SOF Machine Driver with Realtek rt5682 Codec
6  * and speaker codec MAX98357A
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 #include "hda_dsp_common.h"
25 
26 #define NAME_SIZE 32
27 
28 #define SOF_RT5682_SSP_CODEC(quirk)		((quirk) & GENMASK(2, 0))
29 #define SOF_RT5682_SSP_CODEC_MASK			(GENMASK(2, 0))
30 #define SOF_RT5682_MCLK_EN			BIT(3)
31 #define SOF_RT5682_MCLK_24MHZ			BIT(4)
32 #define SOF_SPEAKER_AMP_PRESENT		BIT(5)
33 #define SOF_RT5682_SSP_AMP_SHIFT		6
34 #define SOF_RT5682_SSP_AMP_MASK                 (GENMASK(8, 6))
35 #define SOF_RT5682_SSP_AMP(quirk)	\
36 	(((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK)
37 #define SOF_RT5682_MCLK_BYTCHT_EN		BIT(9)
38 #define SOF_RT5682_NUM_HDMIDEV_SHIFT		10
39 #define SOF_RT5682_NUM_HDMIDEV_MASK		(GENMASK(12, 10))
40 #define SOF_RT5682_NUM_HDMIDEV(quirk)	\
41 	((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK)
42 
43 /* Default: MCLK on, MCLK 19.2M, SSP0  */
44 static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
45 					SOF_RT5682_SSP_CODEC(0);
46 
47 static int is_legacy_cpu;
48 
49 static struct snd_soc_jack sof_hdmi[3];
50 
51 struct sof_hdmi_pcm {
52 	struct list_head head;
53 	struct snd_soc_dai *codec_dai;
54 	int device;
55 };
56 
57 struct sof_card_private {
58 	struct clk *mclk;
59 	struct snd_soc_jack sof_headset;
60 	struct list_head hdmi_pcm_list;
61 	bool common_hdmi_codec_drv;
62 };
63 
64 static int sof_rt5682_quirk_cb(const struct dmi_system_id *id)
65 {
66 	sof_rt5682_quirk = (unsigned long)id->driver_data;
67 	return 1;
68 }
69 
70 static const struct dmi_system_id sof_rt5682_quirk_table[] = {
71 	{
72 		.callback = sof_rt5682_quirk_cb,
73 		.matches = {
74 			DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
75 			DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"),
76 		},
77 		.driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
78 	},
79 	{
80 		.callback = sof_rt5682_quirk_cb,
81 		.matches = {
82 			DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
83 			DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"),
84 		},
85 		.driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)),
86 	},
87 	{
88 		.callback = sof_rt5682_quirk_cb,
89 		.matches = {
90 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
91 			DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"),
92 		},
93 		.driver_data = (void *)(SOF_RT5682_MCLK_EN |
94 					SOF_RT5682_MCLK_24MHZ |
95 					SOF_RT5682_SSP_CODEC(1)),
96 	},
97 	{
98 		.callback = sof_rt5682_quirk_cb,
99 		.matches = {
100 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"),
101 		},
102 		.driver_data = (void *)(SOF_RT5682_MCLK_EN |
103 					SOF_RT5682_MCLK_24MHZ |
104 					SOF_RT5682_SSP_CODEC(0) |
105 					SOF_SPEAKER_AMP_PRESENT |
106 					SOF_RT5682_SSP_AMP(1)),
107 	},
108 	{
109 		.callback = sof_rt5682_quirk_cb,
110 		.matches = {
111 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
112 			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
113 		},
114 		.driver_data = (void *)(SOF_RT5682_MCLK_EN |
115 					SOF_RT5682_SSP_CODEC(0)),
116 	},
117 	{}
118 };
119 
120 static int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd)
121 {
122 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
123 	struct snd_soc_dai *dai = rtd->codec_dai;
124 	struct sof_hdmi_pcm *pcm;
125 
126 	pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL);
127 	if (!pcm)
128 		return -ENOMEM;
129 
130 	/* dai_link id is 1:1 mapped to the PCM device */
131 	pcm->device = rtd->dai_link->id;
132 	pcm->codec_dai = dai;
133 
134 	list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
135 
136 	return 0;
137 }
138 
139 static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd)
140 {
141 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
142 	struct snd_soc_component *component = rtd->codec_dai->component;
143 	struct snd_soc_jack *jack;
144 	int ret;
145 
146 	/* need to enable ASRC function for 24MHz mclk rate */
147 	if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) &&
148 	    (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) {
149 		rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER |
150 					RT5682_AD_STEREO1_FILTER,
151 					RT5682_CLK_SEL_I2S1_ASRC);
152 	}
153 
154 	if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
155 		/*
156 		 * The firmware might enable the clock at
157 		 * boot (this information may or may not
158 		 * be reflected in the enable clock register).
159 		 * To change the rate we must disable the clock
160 		 * first to cover these cases. Due to common
161 		 * clock framework restrictions that do not allow
162 		 * to disable a clock that has not been enabled,
163 		 * we need to enable the clock first.
164 		 */
165 		ret = clk_prepare_enable(ctx->mclk);
166 		if (!ret)
167 			clk_disable_unprepare(ctx->mclk);
168 
169 		ret = clk_set_rate(ctx->mclk, 19200000);
170 
171 		if (ret)
172 			dev_err(rtd->dev, "unable to set MCLK rate\n");
173 	}
174 
175 	/*
176 	 * Headset buttons map to the google Reference headset.
177 	 * These can be configured by userspace.
178 	 */
179 	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
180 				    SND_JACK_HEADSET | SND_JACK_BTN_0 |
181 				    SND_JACK_BTN_1 | SND_JACK_BTN_2 |
182 				    SND_JACK_BTN_3,
183 				    &ctx->sof_headset, NULL, 0);
184 	if (ret) {
185 		dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret);
186 		return ret;
187 	}
188 
189 	jack = &ctx->sof_headset;
190 
191 	snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
192 	snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
193 	snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
194 	snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
195 	ret = snd_soc_component_set_jack(component, jack, NULL);
196 
197 	if (ret) {
198 		dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret);
199 		return ret;
200 	}
201 
202 	return ret;
203 };
204 
205 static int sof_rt5682_hw_params(struct snd_pcm_substream *substream,
206 				struct snd_pcm_hw_params *params)
207 {
208 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
209 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
210 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
211 	int clk_id, clk_freq, pll_out, ret;
212 
213 	if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) {
214 		if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
215 			ret = clk_prepare_enable(ctx->mclk);
216 			if (ret < 0) {
217 				dev_err(rtd->dev,
218 					"could not configure MCLK state");
219 				return ret;
220 			}
221 		}
222 
223 		clk_id = RT5682_PLL1_S_MCLK;
224 		if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)
225 			clk_freq = 24000000;
226 		else
227 			clk_freq = 19200000;
228 	} else {
229 		clk_id = RT5682_PLL1_S_BCLK1;
230 		clk_freq = params_rate(params) * 50;
231 	}
232 
233 	pll_out = params_rate(params) * 512;
234 
235 	ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out);
236 	if (ret < 0)
237 		dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret);
238 
239 	/* Configure sysclk for codec */
240 	ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1,
241 				     pll_out, SND_SOC_CLOCK_IN);
242 	if (ret < 0)
243 		dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
244 
245 	/*
246 	 * slot_width should equal or large than data length, set them
247 	 * be the same
248 	 */
249 	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2,
250 				       params_width(params));
251 	if (ret < 0) {
252 		dev_err(rtd->dev, "set TDM slot err:%d\n", ret);
253 		return ret;
254 	}
255 
256 	return ret;
257 }
258 
259 static struct snd_soc_ops sof_rt5682_ops = {
260 	.hw_params = sof_rt5682_hw_params,
261 };
262 
263 static struct snd_soc_dai_link_component platform_component[] = {
264 	{
265 		/* name might be overridden during probe */
266 		.name = "0000:00:1f.3"
267 	}
268 };
269 
270 static int sof_card_late_probe(struct snd_soc_card *card)
271 {
272 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
273 	struct snd_soc_component *component = NULL;
274 	char jack_name[NAME_SIZE];
275 	struct sof_hdmi_pcm *pcm;
276 	int err = 0;
277 	int i = 0;
278 
279 	/* HDMI is not supported by SOF on Baytrail/CherryTrail */
280 	if (is_legacy_cpu)
281 		return 0;
282 
283 	pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm,
284 			       head);
285 	component = pcm->codec_dai->component;
286 
287 	if (ctx->common_hdmi_codec_drv)
288 		return hda_dsp_hdmi_build_controls(card, component);
289 
290 	list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
291 		component = pcm->codec_dai->component;
292 		snprintf(jack_name, sizeof(jack_name),
293 			 "HDMI/DP, pcm=%d Jack", pcm->device);
294 		err = snd_soc_card_jack_new(card, jack_name,
295 					    SND_JACK_AVOUT, &sof_hdmi[i],
296 					    NULL, 0);
297 
298 		if (err)
299 			return err;
300 
301 		err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
302 					  &sof_hdmi[i]);
303 		if (err < 0)
304 			return err;
305 
306 		i++;
307 	}
308 	if (!component)
309 		return -EINVAL;
310 
311 	return hdac_hdmi_jack_port_init(component, &card->dapm);
312 }
313 
314 static const struct snd_kcontrol_new sof_controls[] = {
315 	SOC_DAPM_PIN_SWITCH("Headphone Jack"),
316 	SOC_DAPM_PIN_SWITCH("Headset Mic"),
317 	SOC_DAPM_PIN_SWITCH("Spk"),
318 };
319 
320 static const struct snd_soc_dapm_widget sof_widgets[] = {
321 	SND_SOC_DAPM_HP("Headphone Jack", NULL),
322 	SND_SOC_DAPM_MIC("Headset Mic", NULL),
323 	SND_SOC_DAPM_SPK("Spk", NULL),
324 };
325 
326 static const struct snd_soc_dapm_widget dmic_widgets[] = {
327 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
328 };
329 
330 static const struct snd_soc_dapm_route sof_map[] = {
331 	/* HP jack connectors - unknown if we have jack detection */
332 	{ "Headphone Jack", NULL, "HPOL" },
333 	{ "Headphone Jack", NULL, "HPOR" },
334 
335 	/* other jacks */
336 	{ "IN1P", NULL, "Headset Mic" },
337 };
338 
339 static const struct snd_soc_dapm_route speaker_map[] = {
340 	/* speaker */
341 	{ "Spk", NULL, "Speaker" },
342 };
343 
344 static const struct snd_soc_dapm_route dmic_map[] = {
345 	/* digital mics */
346 	{"DMic", NULL, "SoC DMIC"},
347 };
348 
349 static int speaker_codec_init(struct snd_soc_pcm_runtime *rtd)
350 {
351 	struct snd_soc_card *card = rtd->card;
352 	int ret;
353 
354 	ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map,
355 				      ARRAY_SIZE(speaker_map));
356 
357 	if (ret)
358 		dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret);
359 	return ret;
360 }
361 
362 static int dmic_init(struct snd_soc_pcm_runtime *rtd)
363 {
364 	struct snd_soc_card *card = rtd->card;
365 	int ret;
366 
367 	ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
368 					ARRAY_SIZE(dmic_widgets));
369 	if (ret) {
370 		dev_err(card->dev, "DMic widget addition failed: %d\n", ret);
371 		/* Don't need to add routes if widget addition failed */
372 		return ret;
373 	}
374 
375 	ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map,
376 				      ARRAY_SIZE(dmic_map));
377 
378 	if (ret)
379 		dev_err(card->dev, "DMic map addition failed: %d\n", ret);
380 
381 	return ret;
382 }
383 
384 /* sof audio machine driver for rt5682 codec */
385 static struct snd_soc_card sof_audio_card_rt5682 = {
386 	.name = "rt5682", /* the sof- prefix is added by the core */
387 	.owner = THIS_MODULE,
388 	.controls = sof_controls,
389 	.num_controls = ARRAY_SIZE(sof_controls),
390 	.dapm_widgets = sof_widgets,
391 	.num_dapm_widgets = ARRAY_SIZE(sof_widgets),
392 	.dapm_routes = sof_map,
393 	.num_dapm_routes = ARRAY_SIZE(sof_map),
394 	.fully_routed = true,
395 	.late_probe = sof_card_late_probe,
396 };
397 
398 static struct snd_soc_dai_link_component rt5682_component[] = {
399 	{
400 		.name = "i2c-10EC5682:00",
401 		.dai_name = "rt5682-aif1",
402 	}
403 };
404 
405 static struct snd_soc_dai_link_component dmic_component[] = {
406 	{
407 		.name = "dmic-codec",
408 		.dai_name = "dmic-hifi",
409 	}
410 };
411 
412 static struct snd_soc_dai_link_component max98357a_component[] = {
413 	{
414 		.name = "MX98357A:00",
415 		.dai_name = "HiFi",
416 	}
417 };
418 
419 static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
420 							  int ssp_codec,
421 							  int ssp_amp,
422 							  int dmic_be_num,
423 							  int hdmi_num)
424 {
425 	struct snd_soc_dai_link_component *idisp_components;
426 	struct snd_soc_dai_link_component *cpus;
427 	struct snd_soc_dai_link *links;
428 	int i, id = 0;
429 
430 	links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
431 			     sof_audio_card_rt5682.num_links, GFP_KERNEL);
432 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
433 			     sof_audio_card_rt5682.num_links, GFP_KERNEL);
434 	if (!links || !cpus)
435 		goto devm_err;
436 
437 	/* codec SSP */
438 	links[id].name = devm_kasprintf(dev, GFP_KERNEL,
439 					"SSP%d-Codec", ssp_codec);
440 	if (!links[id].name)
441 		goto devm_err;
442 
443 	links[id].id = id;
444 	links[id].codecs = rt5682_component;
445 	links[id].num_codecs = ARRAY_SIZE(rt5682_component);
446 	links[id].platforms = platform_component;
447 	links[id].num_platforms = ARRAY_SIZE(platform_component);
448 	links[id].init = sof_rt5682_codec_init;
449 	links[id].ops = &sof_rt5682_ops;
450 	links[id].nonatomic = true;
451 	links[id].dpcm_playback = 1;
452 	links[id].dpcm_capture = 1;
453 	links[id].no_pcm = 1;
454 	links[id].cpus = &cpus[id];
455 	links[id].num_cpus = 1;
456 	if (is_legacy_cpu) {
457 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
458 							  "ssp%d-port",
459 							  ssp_codec);
460 		if (!links[id].cpus->dai_name)
461 			goto devm_err;
462 	} else {
463 		/*
464 		 * Currently, On SKL+ platforms MCLK will be turned off in sof
465 		 * runtime suspended, and it will go into runtime suspended
466 		 * right after playback is stop. However, rt5682 will output
467 		 * static noise if sysclk turns off during playback. Set
468 		 * ignore_pmdown_time to power down rt5682 immediately and
469 		 * avoid the noise.
470 		 * It can be removed once we can control MCLK by driver.
471 		 */
472 		links[id].ignore_pmdown_time = 1;
473 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
474 							  "SSP%d Pin",
475 							  ssp_codec);
476 		if (!links[id].cpus->dai_name)
477 			goto devm_err;
478 	}
479 	id++;
480 
481 	/* dmic */
482 	if (dmic_be_num > 0) {
483 		/* at least we have dmic01 */
484 		links[id].name = "dmic01";
485 		links[id].cpus = &cpus[id];
486 		links[id].cpus->dai_name = "DMIC01 Pin";
487 		links[id].init = dmic_init;
488 		if (dmic_be_num > 1) {
489 			/* set up 2 BE links at most */
490 			links[id + 1].name = "dmic16k";
491 			links[id + 1].cpus = &cpus[id + 1];
492 			links[id + 1].cpus->dai_name = "DMIC16k Pin";
493 			dmic_be_num = 2;
494 		}
495 	}
496 
497 	for (i = 0; i < dmic_be_num; i++) {
498 		links[id].id = id;
499 		links[id].num_cpus = 1;
500 		links[id].codecs = dmic_component;
501 		links[id].num_codecs = ARRAY_SIZE(dmic_component);
502 		links[id].platforms = platform_component;
503 		links[id].num_platforms = ARRAY_SIZE(platform_component);
504 		links[id].ignore_suspend = 1;
505 		links[id].dpcm_capture = 1;
506 		links[id].no_pcm = 1;
507 		id++;
508 	}
509 
510 	/* HDMI */
511 	if (hdmi_num > 0) {
512 		idisp_components = devm_kzalloc(dev,
513 				   sizeof(struct snd_soc_dai_link_component) *
514 				   hdmi_num, GFP_KERNEL);
515 		if (!idisp_components)
516 			goto devm_err;
517 	}
518 	for (i = 1; i <= hdmi_num; i++) {
519 		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
520 						"iDisp%d", i);
521 		if (!links[id].name)
522 			goto devm_err;
523 
524 		links[id].id = id;
525 		links[id].cpus = &cpus[id];
526 		links[id].num_cpus = 1;
527 		links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
528 							  "iDisp%d Pin", i);
529 		if (!links[id].cpus->dai_name)
530 			goto devm_err;
531 
532 		idisp_components[i - 1].name = "ehdaudio0D2";
533 		idisp_components[i - 1].dai_name = devm_kasprintf(dev,
534 								  GFP_KERNEL,
535 								  "intel-hdmi-hifi%d",
536 								  i);
537 		if (!idisp_components[i - 1].dai_name)
538 			goto devm_err;
539 
540 		links[id].codecs = &idisp_components[i - 1];
541 		links[id].num_codecs = 1;
542 		links[id].platforms = platform_component;
543 		links[id].num_platforms = ARRAY_SIZE(platform_component);
544 		links[id].init = sof_hdmi_init;
545 		links[id].dpcm_playback = 1;
546 		links[id].no_pcm = 1;
547 		id++;
548 	}
549 
550 	/* speaker amp */
551 	if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) {
552 		links[id].name = devm_kasprintf(dev, GFP_KERNEL,
553 						"SSP%d-Codec", ssp_amp);
554 		if (!links[id].name)
555 			goto devm_err;
556 
557 		links[id].id = id;
558 		links[id].codecs = max98357a_component;
559 		links[id].num_codecs = ARRAY_SIZE(max98357a_component);
560 		links[id].platforms = platform_component;
561 		links[id].num_platforms = ARRAY_SIZE(platform_component);
562 		links[id].init = speaker_codec_init,
563 		links[id].nonatomic = true;
564 		links[id].dpcm_playback = 1;
565 		links[id].no_pcm = 1;
566 		links[id].cpus = &cpus[id];
567 		links[id].num_cpus = 1;
568 		if (is_legacy_cpu) {
569 			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
570 								  "ssp%d-port",
571 								  ssp_amp);
572 			if (!links[id].cpus->dai_name)
573 				goto devm_err;
574 
575 		} else {
576 			links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL,
577 								  "SSP%d Pin",
578 								  ssp_amp);
579 			if (!links[id].cpus->dai_name)
580 				goto devm_err;
581 		}
582 	}
583 
584 	return links;
585 devm_err:
586 	return NULL;
587 }
588 
589 static int sof_audio_probe(struct platform_device *pdev)
590 {
591 	struct snd_soc_dai_link *dai_links;
592 	struct snd_soc_acpi_mach *mach;
593 	struct sof_card_private *ctx;
594 	int dmic_be_num, hdmi_num;
595 	int ret, ssp_amp, ssp_codec;
596 
597 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
598 	if (!ctx)
599 		return -ENOMEM;
600 
601 	if (pdev->id_entry && pdev->id_entry->driver_data)
602 		sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data;
603 
604 	dmi_check_system(sof_rt5682_quirk_table);
605 
606 	mach = (&pdev->dev)->platform_data;
607 
608 	/* A speaker amp might not be present when the quirk claims one is.
609 	 * Detect this via whether the machine driver match includes quirk_data.
610 	 */
611 	if ((sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data)
612 		sof_rt5682_quirk &= ~SOF_SPEAKER_AMP_PRESENT;
613 
614 	if (soc_intel_is_byt() || soc_intel_is_cht()) {
615 		is_legacy_cpu = 1;
616 		dmic_be_num = 0;
617 		hdmi_num = 0;
618 		/* default quirk for legacy cpu */
619 		sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
620 						SOF_RT5682_MCLK_BYTCHT_EN |
621 						SOF_RT5682_SSP_CODEC(2);
622 	} else {
623 		dmic_be_num = 2;
624 		hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >>
625 			 SOF_RT5682_NUM_HDMIDEV_SHIFT;
626 		/* default number of HDMI DAI's */
627 		if (!hdmi_num)
628 			hdmi_num = 3;
629 	}
630 
631 	/* need to get main clock from pmc */
632 	if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) {
633 		ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
634 		if (IS_ERR(ctx->mclk)) {
635 			ret = PTR_ERR(ctx->mclk);
636 
637 			dev_err(&pdev->dev,
638 				"Failed to get MCLK from pmc_plt_clk_3: %d\n",
639 				ret);
640 			return ret;
641 		}
642 
643 		ret = clk_prepare_enable(ctx->mclk);
644 		if (ret < 0) {
645 			dev_err(&pdev->dev,
646 				"could not configure MCLK state");
647 			return ret;
648 		}
649 	}
650 
651 	dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk);
652 
653 	ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >>
654 			SOF_RT5682_SSP_AMP_SHIFT;
655 
656 	ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK;
657 
658 	/* compute number of dai links */
659 	sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num;
660 
661 	if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT)
662 		sof_audio_card_rt5682.num_links++;
663 
664 	dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp,
665 					      dmic_be_num, hdmi_num);
666 	if (!dai_links)
667 		return -ENOMEM;
668 
669 	sof_audio_card_rt5682.dai_link = dai_links;
670 
671 	INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
672 
673 	sof_audio_card_rt5682.dev = &pdev->dev;
674 
675 	/* set platform name for each dailink */
676 	ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682,
677 						    mach->mach_params.platform);
678 	if (ret)
679 		return ret;
680 
681 	ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
682 
683 	snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx);
684 
685 	return devm_snd_soc_register_card(&pdev->dev,
686 					  &sof_audio_card_rt5682);
687 }
688 
689 static int sof_rt5682_remove(struct platform_device *pdev)
690 {
691 	struct snd_soc_card *card = platform_get_drvdata(pdev);
692 	struct snd_soc_component *component = NULL;
693 
694 	for_each_card_components(card, component) {
695 		if (!strcmp(component->name, rt5682_component[0].name)) {
696 			snd_soc_component_set_jack(component, NULL, NULL);
697 			break;
698 		}
699 	}
700 
701 	return 0;
702 }
703 
704 static const struct platform_device_id board_ids[] = {
705 	{
706 		.name = "sof_rt5682",
707 	},
708 	{
709 		.name = "tgl_max98357a_rt5682",
710 		.driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN |
711 					SOF_RT5682_SSP_CODEC(0) |
712 					SOF_SPEAKER_AMP_PRESENT |
713 					SOF_RT5682_SSP_AMP(1) |
714 					SOF_RT5682_NUM_HDMIDEV(4)),
715 	},
716 	{ }
717 };
718 
719 static struct platform_driver sof_audio = {
720 	.probe = sof_audio_probe,
721 	.remove = sof_rt5682_remove,
722 	.driver = {
723 		.name = "sof_rt5682",
724 		.pm = &snd_soc_pm_ops,
725 	},
726 	.id_table = board_ids,
727 };
728 module_platform_driver(sof_audio)
729 
730 /* Module information */
731 MODULE_DESCRIPTION("SOF Audio Machine driver");
732 MODULE_AUTHOR("Bard Liao <bard.liao@intel.com>");
733 MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>");
734 MODULE_LICENSE("GPL v2");
735 MODULE_ALIAS("platform:sof_rt5682");
736 MODULE_ALIAS("platform:tgl_max98357a_rt5682");
737