xref: /linux/sound/soc/intel/boards/sof_sdw.c (revision df2e3152f1cb798ed8ffa7e488c50261e6dc50e3)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2020 Intel Corporation
3 
4 /*
5  *  sof_sdw - ASOC Machine driver for Intel SoundWire platforms
6  */
7 
8 #include <linux/acpi.h>
9 #include <linux/bitmap.h>
10 #include <linux/device.h>
11 #include <linux/dmi.h>
12 #include <linux/module.h>
13 #include <linux/soundwire/sdw.h>
14 #include <linux/soundwire/sdw_type.h>
15 #include <linux/soundwire/sdw_intel.h>
16 #include <sound/soc-acpi.h>
17 #include "sof_sdw_common.h"
18 #include "../../codecs/rt711.h"
19 
20 static unsigned long sof_sdw_quirk = RT711_JD1;
21 static int quirk_override = -1;
22 module_param_named(quirk, quirk_override, int, 0444);
23 MODULE_PARM_DESC(quirk, "Board-specific quirk override");
24 
25 #define DMIC_DEFAULT_CHANNELS 2
26 
27 static void log_quirks(struct device *dev)
28 {
29 	if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk))
30 		dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
31 			SOC_SDW_JACK_JDSRC(sof_sdw_quirk));
32 	if (sof_sdw_quirk & SOC_SDW_FOUR_SPK)
33 		dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n");
34 	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
35 		dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
36 	if (sof_sdw_quirk & SOC_SDW_PCH_DMIC)
37 		dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n");
38 	if (SOF_SSP_GET_PORT(sof_sdw_quirk))
39 		dev_dbg(dev, "SSP port %ld\n",
40 			SOF_SSP_GET_PORT(sof_sdw_quirk));
41 	if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION)
42 		dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n");
43 	if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR)
44 		dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n");
45 	if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS)
46 		dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n");
47 	if (sof_sdw_quirk & SOC_SDW_CODEC_MIC)
48 		dev_dbg(dev, "quirk SOC_SDW_CODEC_MIC enabled\n");
49 }
50 
51 static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
52 {
53 	sof_sdw_quirk = (unsigned long)id->driver_data;
54 	return 1;
55 }
56 
57 static const struct dmi_system_id sof_sdw_quirk_table[] = {
58 	/* CometLake devices */
59 	{
60 		.callback = sof_sdw_quirk_cb,
61 		.matches = {
62 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
63 			DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
64 		},
65 		.driver_data = (void *)SOC_SDW_PCH_DMIC,
66 	},
67 	{
68 		.callback = sof_sdw_quirk_cb,
69 		.matches = {
70 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
71 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
72 		},
73 		.driver_data = (void *)RT711_JD2,
74 	},
75 	{
76 		/* early version of SKU 09C6 */
77 		.callback = sof_sdw_quirk_cb,
78 		.matches = {
79 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
80 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
81 		},
82 		.driver_data = (void *)RT711_JD2,
83 	},
84 	{
85 		.callback = sof_sdw_quirk_cb,
86 		.matches = {
87 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
88 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
89 		},
90 		.driver_data = (void *)(RT711_JD2),
91 	},
92 	{
93 		.callback = sof_sdw_quirk_cb,
94 		.matches = {
95 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
96 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
97 		},
98 		.driver_data = (void *)(RT711_JD2),
99 	},
100 	/* IceLake devices */
101 	{
102 		.callback = sof_sdw_quirk_cb,
103 		.matches = {
104 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
105 			DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
106 		},
107 		.driver_data = (void *)SOC_SDW_PCH_DMIC,
108 	},
109 	/* TigerLake devices */
110 	{
111 		.callback = sof_sdw_quirk_cb,
112 		.matches = {
113 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
114 			DMI_MATCH(DMI_PRODUCT_NAME,
115 				  "Tiger Lake Client Platform"),
116 		},
117 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
118 					RT711_JD1 |
119 					SOC_SDW_PCH_DMIC |
120 					SOF_SSP_PORT(SOF_I2S_SSP2)),
121 	},
122 	{
123 		.callback = sof_sdw_quirk_cb,
124 		.matches = {
125 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
126 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
127 		},
128 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
129 					RT711_JD2),
130 	},
131 	{
132 		/* another SKU of Dell Latitude 9520 */
133 		.callback = sof_sdw_quirk_cb,
134 		.matches = {
135 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
136 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F")
137 		},
138 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
139 					RT711_JD2),
140 	},
141 	{
142 		/* Dell XPS 9710 */
143 		.callback = sof_sdw_quirk_cb,
144 		.matches = {
145 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
146 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
147 		},
148 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
149 					RT711_JD2),
150 	},
151 	{
152 		.callback = sof_sdw_quirk_cb,
153 		.matches = {
154 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
155 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
156 		},
157 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
158 					RT711_JD2),
159 	},
160 	{
161 		.callback = sof_sdw_quirk_cb,
162 		.matches = {
163 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
164 			DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
165 		},
166 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
167 					SOC_SDW_PCH_DMIC |
168 					SOF_BT_OFFLOAD_SSP(2) |
169 					SOF_SSP_BT_OFFLOAD_PRESENT),
170 	},
171 	{
172 		.callback = sof_sdw_quirk_cb,
173 		.matches = {
174 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
175 			DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
176 		},
177 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
178 					SOC_SDW_PCH_DMIC),
179 	},
180 	{
181 		/*
182 		 * this entry covers multiple HP SKUs. The family name
183 		 * does not seem robust enough, so we use a partial
184 		 * match that ignores the product name suffix
185 		 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
186 		 */
187 		.callback = sof_sdw_quirk_cb,
188 		.matches = {
189 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
190 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"),
191 		},
192 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
193 					SOC_SDW_PCH_DMIC |
194 					RT711_JD1),
195 	},
196 	{
197 		/*
198 		 * this entry covers HP Spectre x360 where the DMI information
199 		 * changed somehow
200 		 */
201 		.callback = sof_sdw_quirk_cb,
202 		.matches = {
203 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
204 			DMI_MATCH(DMI_BOARD_NAME, "8709"),
205 		},
206 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
207 					SOC_SDW_PCH_DMIC |
208 					RT711_JD1),
209 	},
210 	{
211 		/* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
212 		.callback = sof_sdw_quirk_cb,
213 		.matches = {
214 			DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
215 			DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
216 		},
217 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
218 					SOC_SDW_PCH_DMIC |
219 					RT711_JD1),
220 	},
221 	{
222 		/* NUC15 LAPBC710 skews */
223 		.callback = sof_sdw_quirk_cb,
224 		.matches = {
225 			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
226 			DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"),
227 		},
228 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
229 					SOC_SDW_PCH_DMIC |
230 					RT711_JD1),
231 	},
232 	{
233 		/* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
234 		.callback = sof_sdw_quirk_cb,
235 		.matches = {
236 			DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
237 			DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
238 		},
239 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
240 					SOC_SDW_PCH_DMIC |
241 					RT711_JD2_100K),
242 	},
243 	{
244 		/* NUC15 LAPRC710 skews */
245 		.callback = sof_sdw_quirk_cb,
246 		.matches = {
247 			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
248 			DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"),
249 		},
250 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
251 					SOC_SDW_PCH_DMIC |
252 					RT711_JD2_100K),
253 	},
254 	/* TigerLake-SDCA devices */
255 	{
256 		.callback = sof_sdw_quirk_cb,
257 		.matches = {
258 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
259 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
260 		},
261 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
262 					RT711_JD2),
263 	},
264 	{
265 		.callback = sof_sdw_quirk_cb,
266 		.matches = {
267 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
268 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
269 		},
270 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
271 					RT711_JD2),
272 	},
273 	/* AlderLake devices */
274 	{
275 		.callback = sof_sdw_quirk_cb,
276 		.matches = {
277 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
278 			DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
279 		},
280 		.driver_data = (void *)(RT711_JD2_100K |
281 					SOF_SDW_TGL_HDMI |
282 					SOF_BT_OFFLOAD_SSP(2) |
283 					SOF_SSP_BT_OFFLOAD_PRESENT),
284 	},
285 	{
286 		.callback = sof_sdw_quirk_cb,
287 		.matches = {
288 			DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
289 			DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"),
290 		},
291 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
292 					RT711_JD2_100K),
293 	},
294 	{
295 		.callback = sof_sdw_quirk_cb,
296 		.matches = {
297 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
298 			DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
299 		},
300 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
301 					SOC_SDW_PCH_DMIC |
302 					SOF_BT_OFFLOAD_SSP(2) |
303 					SOF_SSP_BT_OFFLOAD_PRESENT),
304 	},
305 	{
306 		.callback = sof_sdw_quirk_cb,
307 		.matches = {
308 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
309 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
310 		},
311 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
312 					RT711_JD2),
313 	},
314 	{
315 		.callback = sof_sdw_quirk_cb,
316 		.matches = {
317 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
318 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
319 		},
320 		/* No Jack */
321 		.driver_data = (void *)(SOF_SDW_TGL_HDMI),
322 	},
323 	{
324 		.callback = sof_sdw_quirk_cb,
325 		.matches = {
326 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
327 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
328 		},
329 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
330 					RT711_JD2),
331 	},
332 	{
333 		.callback = sof_sdw_quirk_cb,
334 		.matches = {
335 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
336 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
337 		},
338 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
339 					RT711_JD2),
340 	},
341 	{
342 		.callback = sof_sdw_quirk_cb,
343 		.matches = {
344 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
345 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
346 		},
347 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
348 					RT711_JD2),
349 	},
350 	{
351 		.callback = sof_sdw_quirk_cb,
352 		.matches = {
353 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
354 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
355 		},
356 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
357 					RT711_JD2),
358 	},
359 	{
360 		.callback = sof_sdw_quirk_cb,
361 		.matches = {
362 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
363 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
364 		},
365 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
366 					RT711_JD2),
367 	},
368 	{
369 		.callback = sof_sdw_quirk_cb,
370 		.matches = {
371 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
372 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
373 		},
374 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
375 					RT711_JD2),
376 	},
377 	{
378 		.callback = sof_sdw_quirk_cb,
379 		.matches = {
380 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
381 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
382 		},
383 		/* No Jack */
384 		.driver_data = (void *)SOF_SDW_TGL_HDMI,
385 	},
386 	{
387 		.callback = sof_sdw_quirk_cb,
388 		.matches = {
389 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
390 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"),
391 		},
392 		/* No Jack */
393 		.driver_data = (void *)SOF_SDW_TGL_HDMI,
394 	},
395 
396 	{
397 		.callback = sof_sdw_quirk_cb,
398 		.matches = {
399 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
400 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
401 		},
402 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
403 					RT711_JD2),
404 	},
405 	{
406 		.callback = sof_sdw_quirk_cb,
407 		.matches = {
408 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
409 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"),
410 		},
411 		/* No Jack */
412 		.driver_data = (void *)SOF_SDW_TGL_HDMI,
413 	},
414 	{
415 		.callback = sof_sdw_quirk_cb,
416 		.matches = {
417 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
418 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"),
419 		},
420 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
421 					RT711_JD2),
422 	},
423 	{
424 		.callback = sof_sdw_quirk_cb,
425 		.matches = {
426 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
427 			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"),
428 		},
429 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
430 					RT711_JD2),
431 	},
432 	/* RaptorLake devices */
433 	{
434 		.callback = sof_sdw_quirk_cb,
435 		.matches = {
436 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
437 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA")
438 		},
439 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
440 					RT711_JD2),
441 	},
442 	{
443 		.callback = sof_sdw_quirk_cb,
444 		.matches = {
445 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
446 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F")
447 		},
448 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
449 					RT711_JD2),
450 	},
451 	{
452 		.callback = sof_sdw_quirk_cb,
453 		.matches = {
454 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
455 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
456 		},
457 		/* No Jack */
458 		.driver_data = (void *)(SOF_SDW_TGL_HDMI),
459 	},
460 	{
461 		.callback = sof_sdw_quirk_cb,
462 		.matches = {
463 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
464 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
465 		},
466 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
467 					RT711_JD2),
468 	},
469 	{
470 		.callback = sof_sdw_quirk_cb,
471 		.matches = {
472 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
473 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
474 		},
475 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
476 					RT711_JD2),
477 	},
478 	{
479 		.callback = sof_sdw_quirk_cb,
480 		.matches = {
481 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
482 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
483 		},
484 		.driver_data = (void *)(SOF_SDW_TGL_HDMI |
485 					RT711_JD2),
486 	},
487 	{
488 		.callback = sof_sdw_quirk_cb,
489 		.matches = {
490 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
491 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6")
492 		},
493 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
494 	},
495 	{
496 		.callback = sof_sdw_quirk_cb,
497 		.matches = {
498 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
499 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9")
500 		},
501 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
502 	},
503 	{
504 		.callback = sof_sdw_quirk_cb,
505 		.matches = {
506 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
507 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA")
508 		},
509 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
510 	},
511 	/* MeteorLake devices */
512 	{
513 		.callback = sof_sdw_quirk_cb,
514 		.matches = {
515 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
516 		},
517 		.driver_data = (void *)(RT711_JD1),
518 	},
519 	{
520 		.callback = sof_sdw_quirk_cb,
521 		.matches = {
522 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
523 			DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"),
524 		},
525 		.driver_data = (void *)(RT711_JD2_100K),
526 	},
527 	{
528 		.callback = sof_sdw_quirk_cb,
529 		.matches = {
530 			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
531 			DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
532 		},
533 		.driver_data = (void *)(SOC_SDW_PCH_DMIC |
534 					SOF_BT_OFFLOAD_SSP(1) |
535 					SOF_SSP_BT_OFFLOAD_PRESENT),
536 	},
537 	{
538 		.callback = sof_sdw_quirk_cb,
539 		.matches = {
540 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
541 			DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"),
542 		},
543 		.driver_data = (void *)(RT711_JD2),
544 	},
545 
546 	/* LunarLake devices */
547 	{
548 		.callback = sof_sdw_quirk_cb,
549 		.matches = {
550 			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
551 			DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
552 		},
553 		.driver_data = (void *)(RT711_JD2),
554 	},
555 	{
556 		.callback = sof_sdw_quirk_cb,
557 		.matches = {
558 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
559 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3")
560 		},
561 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
562 	},
563 	{
564 		.callback = sof_sdw_quirk_cb,
565 		.matches = {
566 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
567 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4")
568 		},
569 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
570 	},
571 	{
572 		.callback = sof_sdw_quirk_cb,
573 		.matches = {
574 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
575 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB")
576 		},
577 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
578 	},
579 	{
580 		.callback = sof_sdw_quirk_cb,
581 		.matches = {
582 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
583 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC")
584 		},
585 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
586 	},
587 	{
588 		.callback = sof_sdw_quirk_cb,
589 		.matches = {
590 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
591 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD")
592 		},
593 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
594 	},
595 	{
596 		.callback = sof_sdw_quirk_cb,
597 		.matches = {
598 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
599 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36")
600 		},
601 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
602 	},
603 	{
604 		.callback = sof_sdw_quirk_cb,
605 		.matches = {
606 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
607 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8")
608 		},
609 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
610 	},
611 	{
612 		.callback = sof_sdw_quirk_cb,
613 		.matches = {
614 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
615 			DMI_MATCH(DMI_PRODUCT_NAME, "83JX")
616 		},
617 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
618 	},
619 	{
620 		.callback = sof_sdw_quirk_cb,
621 		.matches = {
622 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
623 			DMI_MATCH(DMI_PRODUCT_NAME, "83LC")
624 		},
625 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
626 	},
627 	{
628 		.callback = sof_sdw_quirk_cb,
629 		.matches = {
630 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
631 			DMI_MATCH(DMI_PRODUCT_NAME, "83MC")
632 		},
633 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
634 	},	{
635 		.callback = sof_sdw_quirk_cb,
636 		.matches = {
637 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
638 			DMI_MATCH(DMI_PRODUCT_NAME, "83NM")
639 		},
640 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
641 	},
642 	{
643 		.callback = sof_sdw_quirk_cb,
644 		.matches = {
645 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
646 			DMI_MATCH(DMI_PRODUCT_NAME, "83HM")
647 		},
648 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS |
649 					SOC_SDW_CODEC_MIC),
650 	},
651 	{
652 		.callback = sof_sdw_quirk_cb,
653 		.matches = {
654 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
655 			DMI_MATCH(DMI_PRODUCT_NAME, "21QB")
656 		},
657 		/* Note this quirk excludes the CODEC mic */
658 		.driver_data = (void *)(SOC_SDW_CODEC_MIC),
659 	},
660 	{
661 		.callback = sof_sdw_quirk_cb,
662 		.matches = {
663 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
664 			DMI_MATCH(DMI_PRODUCT_NAME, "21QA")
665 		},
666 		/* Note this quirk excludes the CODEC mic */
667 		.driver_data = (void *)(SOC_SDW_CODEC_MIC),
668 	},
669 	{
670 		.callback = sof_sdw_quirk_cb,
671 		.matches = {
672 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
673 			DMI_MATCH(DMI_PRODUCT_NAME, "21Q6")
674 		},
675 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
676 	},
677 	{
678 		.callback = sof_sdw_quirk_cb,
679 		.matches = {
680 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
681 			DMI_MATCH(DMI_PRODUCT_NAME, "21Q7")
682 		},
683 		.driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
684 	},
685 
686 	/* ArrowLake devices */
687 	{
688 		.callback = sof_sdw_quirk_cb,
689 		.matches = {
690 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
691 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8")
692 		},
693 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
694 	},
695 	{
696 		.callback = sof_sdw_quirk_cb,
697 		.matches = {
698 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
699 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1")
700 		},
701 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
702 	},
703 	{
704 		.callback = sof_sdw_quirk_cb,
705 		.matches = {
706 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
707 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7")
708 		},
709 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
710 	},
711 	{
712 		.callback = sof_sdw_quirk_cb,
713 		.matches = {
714 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
715 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0")
716 		},
717 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
718 	},
719 	{
720 		.callback = sof_sdw_quirk_cb,
721 		.matches = {
722 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
723 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3")
724 		},
725 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
726 	},
727 	{
728 		.callback = sof_sdw_quirk_cb,
729 		.matches = {
730 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
731 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4")
732 		},
733 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
734 	},
735 	{
736 		.callback = sof_sdw_quirk_cb,
737 		.matches = {
738 			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
739 			DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5")
740 		},
741 		.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
742 	},
743 	/* Pantherlake devices*/
744 	{
745 		.callback = sof_sdw_quirk_cb,
746 		.matches = {
747 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"),
748 		},
749 		.driver_data = (void *)(SOC_SDW_PCH_DMIC),
750 	},
751 	{}
752 };
753 
754 static struct snd_soc_dai_link_component platform_component[] = {
755 	{
756 		/* name might be overridden during probe */
757 		.name = "0000:00:1f.3"
758 	}
759 };
760 
761 static const struct snd_soc_ops sdw_ops = {
762 	.startup = asoc_sdw_startup,
763 	.prepare = asoc_sdw_prepare,
764 	.trigger = asoc_sdw_trigger,
765 	.hw_params = asoc_sdw_hw_params,
766 	.hw_free = asoc_sdw_hw_free,
767 	.shutdown = asoc_sdw_shutdown,
768 };
769 
770 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
771 
772 static int create_sdw_dailink(struct snd_soc_card *card,
773 			      struct asoc_sdw_dailink *sof_dai,
774 			      struct snd_soc_dai_link **dai_links,
775 			      int *be_id, struct snd_soc_codec_conf **codec_conf)
776 {
777 	struct device *dev = card->dev;
778 	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
779 	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
780 	struct asoc_sdw_endpoint *sof_end;
781 	int stream;
782 	int ret;
783 
784 	list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
785 		if (sof_end->name_prefix) {
786 			(*codec_conf)->dlc.name = sof_end->codec_name;
787 			(*codec_conf)->name_prefix = sof_end->name_prefix;
788 			(*codec_conf)++;
789 		}
790 
791 		if (sof_end->include_sidecar) {
792 			ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
793 			if (ret)
794 				return ret;
795 		}
796 	}
797 
798 	for_each_pcm_streams(stream) {
799 		static const char * const sdw_stream_name[] = {
800 			"SDW%d-Playback",
801 			"SDW%d-Capture",
802 			"SDW%d-Playback-%s",
803 			"SDW%d-Capture-%s",
804 		};
805 		struct snd_soc_dai_link_ch_map *codec_maps;
806 		struct snd_soc_dai_link_component *codecs;
807 		struct snd_soc_dai_link_component *cpus;
808 		int num_cpus = hweight32(sof_dai->link_mask[stream]);
809 		int num_codecs = sof_dai->num_devs[stream];
810 		int playback, capture;
811 		int cur_link = 0;
812 		int i = 0, j = 0;
813 		char *name;
814 
815 		if (!sof_dai->num_devs[stream])
816 			continue;
817 
818 		sof_end = list_first_entry(&sof_dai->endpoints,
819 					   struct asoc_sdw_endpoint, list);
820 
821 		*be_id = sof_end->dai_info->dailink[stream];
822 		if (*be_id < 0) {
823 			dev_err(dev, "Invalid dailink id %d\n", *be_id);
824 			return -EINVAL;
825 		}
826 
827 		/* create stream name according to first link id */
828 		if (ctx->append_dai_type)
829 			name = devm_kasprintf(dev, GFP_KERNEL,
830 					      sdw_stream_name[stream + 2],
831 					      ffs(sof_end->link_mask) - 1,
832 					      type_strings[sof_end->dai_info->dai_type]);
833 		else
834 			name = devm_kasprintf(dev, GFP_KERNEL,
835 					      sdw_stream_name[stream],
836 					      ffs(sof_end->link_mask) - 1);
837 		if (!name)
838 			return -ENOMEM;
839 
840 		cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
841 		if (!cpus)
842 			return -ENOMEM;
843 
844 		codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
845 		if (!codecs)
846 			return -ENOMEM;
847 
848 		codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
849 		if (!codec_maps)
850 			return -ENOMEM;
851 
852 		list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
853 			if (!sof_end->dai_info->direction[stream])
854 				continue;
855 
856 			if (cur_link != sof_end->link_mask) {
857 				int link_num = ffs(sof_end->link_mask) - 1;
858 				int pin_num = intel_ctx->sdw_pin_index[link_num]++;
859 
860 				cur_link = sof_end->link_mask;
861 
862 				cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
863 								  "SDW%d Pin%d",
864 								  link_num, pin_num);
865 				if (!cpus[i].dai_name)
866 					return -ENOMEM;
867 				i++;
868 			}
869 
870 			codec_maps[j].cpu = i - 1;
871 			codec_maps[j].codec = j;
872 
873 			codecs[j].name = sof_end->codec_name;
874 			codecs[j].dai_name = sof_end->dai_info->dai_name;
875 			j++;
876 		}
877 
878 		WARN_ON(i != num_cpus || j != num_codecs);
879 
880 		playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
881 		capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
882 
883 		asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
884 				       cpus, num_cpus, platform_component,
885 				       ARRAY_SIZE(platform_component), codecs, num_codecs,
886 				       1, asoc_sdw_rtd_init, &sdw_ops);
887 
888 		/*
889 		 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
890 		 * based on wait_for_completion(), tag them as 'nonatomic'.
891 		 */
892 		(*dai_links)->nonatomic = true;
893 		(*dai_links)->ch_maps = codec_maps;
894 
895 		list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
896 			if (sof_end->dai_info->init)
897 				sof_end->dai_info->init(card, *dai_links,
898 							sof_end->codec_info,
899 							playback);
900 		}
901 
902 		(*dai_links)++;
903 	}
904 
905 	return 0;
906 }
907 
908 static int create_sdw_dailinks(struct snd_soc_card *card,
909 			       struct snd_soc_dai_link **dai_links, int *be_id,
910 			       struct asoc_sdw_dailink *sof_dais,
911 			       struct snd_soc_codec_conf **codec_conf)
912 {
913 	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
914 	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
915 	int ret, i;
916 
917 	for (i = 0; i < SDW_INTEL_MAX_LINKS; i++)
918 		intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE;
919 
920 	/* generate DAI links by each sdw link */
921 	while (sof_dais->initialised) {
922 		int current_be_id;
923 
924 		ret = create_sdw_dailink(card, sof_dais, dai_links,
925 					 &current_be_id, codec_conf);
926 		if (ret)
927 			return ret;
928 
929 		/* Update the be_id to match the highest ID used for SDW link */
930 		if (*be_id < current_be_id)
931 			*be_id = current_be_id;
932 
933 		sof_dais++;
934 	}
935 
936 	return 0;
937 }
938 
939 static int create_ssp_dailinks(struct snd_soc_card *card,
940 			       struct snd_soc_dai_link **dai_links, int *be_id,
941 			       struct asoc_sdw_codec_info *ssp_info,
942 			       unsigned long ssp_mask)
943 {
944 	struct device *dev = card->dev;
945 	int i, j = 0;
946 	int ret;
947 
948 	for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) {
949 		char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
950 		char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
951 		char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
952 						  ssp_info->acpi_id, j++);
953 		if (!name || !cpu_dai_name || !codec_name)
954 			return -ENOMEM;
955 
956 		int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
957 		int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
958 
959 		ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
960 						    playback, capture, cpu_dai_name,
961 						    platform_component->name,
962 						    ARRAY_SIZE(platform_component), codec_name,
963 						    ssp_info->dais[0].dai_name, 1, NULL,
964 						    ssp_info->ops);
965 		if (ret)
966 			return ret;
967 
968 		ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0);
969 		if (ret < 0)
970 			return ret;
971 
972 		(*dai_links)++;
973 	}
974 
975 	return 0;
976 }
977 
978 static int create_dmic_dailinks(struct snd_soc_card *card,
979 				struct snd_soc_dai_link **dai_links, int *be_id)
980 {
981 	struct device *dev = card->dev;
982 	int ret;
983 
984 	ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01",
985 					    0, 1, // DMIC only supports capture
986 					    "DMIC01 Pin", platform_component->name,
987 					    ARRAY_SIZE(platform_component),
988 					    "dmic-codec", "dmic-hifi", 1,
989 					    asoc_sdw_dmic_init, NULL);
990 	if (ret)
991 		return ret;
992 
993 	(*dai_links)++;
994 
995 	ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k",
996 					    0, 1, // DMIC only supports capture
997 					    "DMIC16k Pin", platform_component->name,
998 					    ARRAY_SIZE(platform_component),
999 					    "dmic-codec", "dmic-hifi", 1,
1000 					    /* don't call asoc_sdw_dmic_init() twice */
1001 					    NULL, NULL);
1002 	if (ret)
1003 		return ret;
1004 
1005 	(*dai_links)++;
1006 
1007 	return 0;
1008 }
1009 
1010 static int create_hdmi_dailinks(struct snd_soc_card *card,
1011 				struct snd_soc_dai_link **dai_links, int *be_id,
1012 				int hdmi_num)
1013 {
1014 	struct device *dev = card->dev;
1015 	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1016 	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1017 	int i, ret;
1018 
1019 	for (i = 0; i < hdmi_num; i++) {
1020 		char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
1021 		char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
1022 		if (!name || !cpu_dai_name)
1023 			return -ENOMEM;
1024 
1025 		char *codec_name, *codec_dai_name;
1026 
1027 		if (intel_ctx->hdmi.idisp_codec) {
1028 			codec_name = "ehdaudio0D2";
1029 			codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
1030 							"intel-hdmi-hifi%d", i + 1);
1031 		} else {
1032 			codec_name = "snd-soc-dummy";
1033 			codec_dai_name = "snd-soc-dummy-dai";
1034 		}
1035 
1036 		if (!codec_dai_name)
1037 			return -ENOMEM;
1038 
1039 		ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1040 						    1, 0, // HDMI only supports playback
1041 						    cpu_dai_name, platform_component->name,
1042 						    ARRAY_SIZE(platform_component),
1043 						    codec_name, codec_dai_name, 1,
1044 						    i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
1045 		if (ret)
1046 			return ret;
1047 
1048 		(*dai_links)++;
1049 	}
1050 
1051 	return 0;
1052 }
1053 
1054 static int create_bt_dailinks(struct snd_soc_card *card,
1055 			      struct snd_soc_dai_link **dai_links, int *be_id)
1056 {
1057 	struct device *dev = card->dev;
1058 	int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1059 			SOF_BT_OFFLOAD_SSP_SHIFT;
1060 	char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1061 	char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1062 	if (!name || !cpu_dai_name)
1063 		return -ENOMEM;
1064 
1065 	int ret;
1066 
1067 	ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1068 					    1, 1, cpu_dai_name, platform_component->name,
1069 					    ARRAY_SIZE(platform_component),
1070 					    snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
1071 					    1, NULL, NULL);
1072 	if (ret)
1073 		return ret;
1074 
1075 	(*dai_links)++;
1076 
1077 	return 0;
1078 }
1079 
1080 static int sof_card_dai_links_create(struct snd_soc_card *card)
1081 {
1082 	struct device *dev = card->dev;
1083 	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
1084 	int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
1085 	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1086 	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1087 	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1088 	struct snd_soc_codec_conf *codec_conf;
1089 	struct asoc_sdw_codec_info *ssp_info;
1090 	struct asoc_sdw_endpoint *sof_ends;
1091 	struct asoc_sdw_dailink *sof_dais;
1092 	int num_devs = 0;
1093 	int num_ends = 0;
1094 	struct snd_soc_dai_link *dai_links;
1095 	int num_links;
1096 	int be_id = 0;
1097 	int hdmi_num;
1098 	unsigned long ssp_mask;
1099 	int ret;
1100 
1101 	ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends);
1102 	if (ret < 0) {
1103 		dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
1104 		return ret;
1105 	}
1106 
1107 	/*
1108 	 * One per DAI link, worst case is a DAI link for every endpoint, also
1109 	 * add one additional to act as a terminator such that code can iterate
1110 	 * until it hits an uninitialised DAI.
1111 	 */
1112 	sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL);
1113 	if (!sof_dais)
1114 		return -ENOMEM;
1115 
1116 	/* One per endpoint, ie. each DAI on each codec/amp */
1117 	sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL);
1118 	if (!sof_ends) {
1119 		ret = -ENOMEM;
1120 		goto err_dai;
1121 	}
1122 
1123 	ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs);
1124 	if (ret < 0)
1125 		goto err_end;
1126 
1127 	sdw_be_num = ret;
1128 
1129 	/*
1130 	 * on generic tgl platform, I2S or sdw mode is supported
1131 	 * based on board rework. A ACPI device is registered in
1132 	 * system only when I2S mode is supported, not sdw mode.
1133 	 * Here check ACPI ID to confirm I2S is supported.
1134 	 */
1135 	ssp_info = asoc_sdw_find_codec_info_acpi(mach->id);
1136 	if (ssp_info) {
1137 		ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1138 		ssp_num = hweight_long(ssp_mask);
1139 	}
1140 
1141 	if (mach_params->codec_mask & IDISP_CODEC_MASK)
1142 		intel_ctx->hdmi.idisp_codec = true;
1143 
1144 	if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1145 		hdmi_num = SOF_TGL_HDMI_COUNT;
1146 	else
1147 		hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1148 
1149 	/* enable dmic01 & dmic16k */
1150 	if (ctx->ignore_internal_dmic) {
1151 		dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n");
1152 		mach_params->dmic_num = 0;
1153 	} else if (mach_params->dmic_num) {
1154 		dmic_num = 2;
1155 	} else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) {
1156 		dmic_num = 2;
1157 		/*
1158 		 * mach_params->dmic_num will be used to set the cfg-mics value of
1159 		 * card->components string. Set it to the default value.
1160 		 */
1161 		mach_params->dmic_num = DMIC_DEFAULT_CHANNELS;
1162 	}
1163 
1164 	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1165 		bt_num = 1;
1166 
1167 	dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
1168 		sdw_be_num, ssp_num, dmic_num,
1169 		intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
1170 
1171 	codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
1172 	if (!codec_conf) {
1173 		ret = -ENOMEM;
1174 		goto err_end;
1175 	}
1176 
1177 	/* allocate BE dailinks */
1178 	num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
1179 	dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
1180 	if (!dai_links) {
1181 		ret = -ENOMEM;
1182 		goto err_end;
1183 	}
1184 
1185 	card->codec_conf = codec_conf;
1186 	card->num_configs = num_devs;
1187 	card->dai_link = dai_links;
1188 	card->num_links = num_links;
1189 
1190 	/* SDW */
1191 	if (sdw_be_num) {
1192 		ret = create_sdw_dailinks(card, &dai_links, &be_id,
1193 					  sof_dais, &codec_conf);
1194 		if (ret)
1195 			goto err_end;
1196 	}
1197 
1198 	/* SSP */
1199 	if (ssp_num) {
1200 		ret = create_ssp_dailinks(card, &dai_links, &be_id,
1201 					  ssp_info, ssp_mask);
1202 		if (ret)
1203 			goto err_end;
1204 	}
1205 
1206 	/* dmic */
1207 	if (dmic_num) {
1208 		ret = create_dmic_dailinks(card, &dai_links, &be_id);
1209 		if (ret)
1210 			goto err_end;
1211 	}
1212 
1213 	/* HDMI */
1214 	ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num);
1215 	if (ret)
1216 		goto err_end;
1217 
1218 	/* BT */
1219 	if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
1220 		ret = create_bt_dailinks(card, &dai_links, &be_id);
1221 		if (ret)
1222 			goto err_end;
1223 	}
1224 
1225 	WARN_ON(codec_conf != card->codec_conf + card->num_configs);
1226 	WARN_ON(dai_links != card->dai_link + card->num_links);
1227 
1228 err_end:
1229 	kfree(sof_ends);
1230 err_dai:
1231 	kfree(sof_dais);
1232 
1233 	return ret;
1234 }
1235 
1236 static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1237 {
1238 	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1239 	struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1240 	int ret = 0;
1241 
1242 	ret = asoc_sdw_card_late_probe(card);
1243 	if (ret < 0)
1244 		return ret;
1245 
1246 	if (intel_ctx->hdmi.idisp_codec)
1247 		ret = sof_sdw_hdmi_card_late_probe(card);
1248 
1249 	return ret;
1250 }
1251 
1252 static int mc_probe(struct platform_device *pdev)
1253 {
1254 	struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
1255 	struct snd_soc_card *card;
1256 	struct asoc_sdw_mc_private *ctx;
1257 	struct intel_mc_ctx *intel_ctx;
1258 	int amp_num = 0, i;
1259 	int ret;
1260 
1261 	dev_dbg(&pdev->dev, "Entry\n");
1262 
1263 	intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL);
1264 	if (!intel_ctx)
1265 		return -ENOMEM;
1266 
1267 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1268 	if (!ctx)
1269 		return -ENOMEM;
1270 
1271 	ctx->private = intel_ctx;
1272 	ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
1273 	card = &ctx->card;
1274 	card->dev = &pdev->dev;
1275 	card->name = "soundwire";
1276 	card->owner = THIS_MODULE;
1277 	card->late_probe = sof_sdw_card_late_probe;
1278 
1279 	snd_soc_card_set_drvdata(card, ctx);
1280 
1281 	dmi_check_system(sof_sdw_quirk_table);
1282 
1283 	if (quirk_override != -1) {
1284 		dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
1285 			 sof_sdw_quirk, quirk_override);
1286 		sof_sdw_quirk = quirk_override;
1287 	}
1288 
1289 	log_quirks(card->dev);
1290 
1291 	ctx->mc_quirk = sof_sdw_quirk;
1292 	/* reset amp_num to ensure amp_num++ starts from 0 in each probe */
1293 	for (i = 0; i < ctx->codec_info_list_count; i++)
1294 		codec_info_list[i].amp_num = 0;
1295 
1296 	if (mach->mach_params.subsystem_id_set) {
1297 		snd_soc_card_set_pci_ssid(card,
1298 					  mach->mach_params.subsystem_vendor,
1299 					  mach->mach_params.subsystem_device);
1300 	}
1301 
1302 	ret = sof_card_dai_links_create(card);
1303 	if (ret < 0)
1304 		return ret;
1305 
1306 	/*
1307 	 * the default amp_num is zero for each codec and
1308 	 * amp_num will only be increased for active amp
1309 	 * codecs on used platform
1310 	 */
1311 	for (i = 0; i < ctx->codec_info_list_count; i++)
1312 		amp_num += codec_info_list[i].amp_num;
1313 
1314 	card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1315 					  " cfg-amp:%d", amp_num);
1316 	if (!card->components)
1317 		return -ENOMEM;
1318 
1319 	if (mach->mach_params.dmic_num) {
1320 		card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1321 						  "%s mic:dmic cfg-mics:%d",
1322 						  card->components,
1323 						  mach->mach_params.dmic_num);
1324 		if (!card->components)
1325 			return -ENOMEM;
1326 	}
1327 
1328 	/* Register the card */
1329 	ret = devm_snd_soc_register_card(card->dev, card);
1330 	if (ret) {
1331 		dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
1332 		asoc_sdw_mc_dailink_exit_loop(card);
1333 		return ret;
1334 	}
1335 
1336 	platform_set_drvdata(pdev, card);
1337 
1338 	return ret;
1339 }
1340 
1341 static void mc_remove(struct platform_device *pdev)
1342 {
1343 	struct snd_soc_card *card = platform_get_drvdata(pdev);
1344 
1345 	asoc_sdw_mc_dailink_exit_loop(card);
1346 }
1347 
1348 static const struct platform_device_id mc_id_table[] = {
1349 	{ "sof_sdw", },
1350 	{}
1351 };
1352 MODULE_DEVICE_TABLE(platform, mc_id_table);
1353 
1354 static struct platform_driver sof_sdw_driver = {
1355 	.driver = {
1356 		.name = "sof_sdw",
1357 		.pm = &snd_soc_pm_ops,
1358 	},
1359 	.probe = mc_probe,
1360 	.remove = mc_remove,
1361 	.id_table = mc_id_table,
1362 };
1363 
1364 module_platform_driver(sof_sdw_driver);
1365 
1366 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1367 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1368 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1369 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1370 MODULE_LICENSE("GPL v2");
1371 MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
1372 MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
1373