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