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