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 /* Novalake devices*/
841 {
842 .callback = sof_sdw_quirk_cb,
843 .matches = {
844 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_nvlrvp"),
845 },
846 .driver_data = (void *)(SOC_SDW_PCH_DMIC),
847 },
848 {}
849 };
850
851 static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = {
852 SND_PCI_QUIRK(0x1028, 0x0e53, "Dell XPS WCL", SOC_SDW_SIDECAR_AMPS),
853 SND_PCI_QUIRK(0x1028, 0x0e54, "Dell XPS PTL", SOC_SDW_SIDECAR_AMPS),
854 SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC),
855 SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC),
856 SND_PCI_QUIRK(0x17aa, 0x2347, "Lenovo P16", SOC_SDW_CODEC_MIC),
857 SND_PCI_QUIRK(0x17aa, 0x2348, "Lenovo P16", SOC_SDW_CODEC_MIC),
858 SND_PCI_QUIRK(0x17aa, 0x2349, "Lenovo P1", SOC_SDW_CODEC_MIC),
859 SND_PCI_QUIRK(0x17aa, 0x3821, "Lenovo 0x3821", SOC_SDW_SIDECAR_AMPS),
860 SND_PCI_QUIRK(0x17aa, 0x383c, "Lenovo 0x383c", SOC_SDW_SIDECAR_AMPS),
861 {}
862 };
863
sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach * mach)864 static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach)
865 {
866 const struct snd_pci_quirk *quirk_entry;
867
868 quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor,
869 mach->mach_params.subsystem_device,
870 sof_sdw_ssid_quirk_table);
871
872 if (quirk_entry)
873 sof_sdw_quirk = quirk_entry->value;
874 }
875
876 static const struct snd_soc_ops sdw_ops = {
877 .startup = asoc_sdw_startup,
878 .prepare = asoc_sdw_prepare,
879 .trigger = asoc_sdw_trigger,
880 .hw_params = asoc_sdw_hw_params,
881 .hw_free = asoc_sdw_hw_free,
882 .shutdown = asoc_sdw_shutdown,
883 };
884
885 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
886
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)887 static int create_sdw_dailink(struct snd_soc_card *card,
888 struct asoc_sdw_dailink *sof_dai,
889 struct snd_soc_dai_link **dai_links,
890 int *be_id, struct snd_soc_codec_conf **codec_conf)
891 {
892 struct device *dev = card->dev;
893 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
894 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
895 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
896 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
897 struct asoc_sdw_endpoint *sof_end;
898 int stream;
899 int ret;
900
901 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
902 if (sof_end->name_prefix) {
903 (*codec_conf)->dlc.name = sof_end->codec_name;
904 (*codec_conf)->name_prefix = sof_end->name_prefix;
905 (*codec_conf)++;
906 }
907
908 if (sof_end->include_sidecar && sof_end->codec_info->add_sidecar) {
909 ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
910 if (ret)
911 return ret;
912 }
913 }
914
915 /*
916 * The dai_type is used to select function topologies. Since the topology stream name
917 * and DAI link name use partial matching, unconditionally appending the dai_type provides
918 * necessary selection metadata without breaking existing topologies. Although
919 * ctx->append_dai_type is not checked here, we overwrite it to ensure consistency in case
920 * it is referenced elsewhere.
921 */
922 ctx->append_dai_type = true;
923 for_each_pcm_streams(stream) {
924 static const char * const sdw_stream_name[] = {
925 "SDW%d-Playback-%s",
926 "SDW%d-Capture-%s",
927 };
928 struct snd_soc_dai_link_ch_map *codec_maps;
929 struct snd_soc_dai_link_component *codecs;
930 struct snd_soc_dai_link_component *cpus;
931 struct snd_soc_dai_link_component *platform;
932 int num_cpus = hweight32(sof_dai->link_mask[stream]);
933 int num_codecs = sof_dai->num_devs[stream];
934 int playback, capture;
935 int cur_link = 0;
936 int i = 0, j = 0;
937 char *name;
938
939 if (!sof_dai->num_devs[stream])
940 continue;
941
942 sof_end = list_first_entry(&sof_dai->endpoints,
943 struct asoc_sdw_endpoint, list);
944
945 *be_id = sof_end->dai_info->dailink[stream];
946 if (*be_id < 0) {
947 dev_err(dev, "Invalid dailink id %d\n", *be_id);
948 return -EINVAL;
949 }
950
951 /* create stream name according to first link id */
952 name = devm_kasprintf(dev, GFP_KERNEL,
953 sdw_stream_name[stream],
954 ffs(sof_end->link_mask) - 1,
955 type_strings[sof_end->dai_info->dai_type]);
956 if (!name)
957 return -ENOMEM;
958
959 cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
960 if (!cpus)
961 return -ENOMEM;
962
963 codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
964 if (!codecs)
965 return -ENOMEM;
966
967 platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
968 if (!platform)
969 return -ENOMEM;
970
971 codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
972 if (!codec_maps)
973 return -ENOMEM;
974
975 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
976 if (!sof_end->dai_info->direction[stream])
977 continue;
978
979 if (cur_link != sof_end->link_mask) {
980 int link_num = ffs(sof_end->link_mask) - 1;
981 int pin_num = intel_ctx->sdw_pin_index[link_num]++;
982
983 cur_link = sof_end->link_mask;
984
985 cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
986 "SDW%d Pin%d",
987 link_num, pin_num);
988 if (!cpus[i].dai_name)
989 return -ENOMEM;
990 i++;
991 }
992
993 codec_maps[j].cpu = i - 1;
994 codec_maps[j].codec = j;
995
996 codecs[j].name = sof_end->codec_name;
997 codecs[j].dai_name = sof_end->dai_info->dai_name;
998 if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC &&
999 mach_params->dmic_num > 0) {
1000 dev_warn(dev,
1001 "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");
1002 }
1003 j++;
1004 }
1005
1006 WARN_ON(i != num_cpus || j != num_codecs);
1007
1008 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
1009 capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
1010
1011 asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
1012 cpus, num_cpus, platform, 1, codecs, num_codecs,
1013 1, asoc_sdw_rtd_init, &sdw_ops);
1014
1015 /*
1016 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
1017 * based on wait_for_completion(), tag them as 'nonatomic'.
1018 */
1019 (*dai_links)->nonatomic = true;
1020 (*dai_links)->ch_maps = codec_maps;
1021
1022 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
1023 if (sof_end->dai_info->init)
1024 sof_end->dai_info->init(card, *dai_links,
1025 sof_end->codec_info,
1026 playback);
1027 }
1028
1029 (*dai_links)++;
1030 }
1031
1032 return 0;
1033 }
1034
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)1035 static int create_sdw_dailinks(struct snd_soc_card *card,
1036 struct snd_soc_dai_link **dai_links, int *be_id,
1037 struct asoc_sdw_dailink *sof_dais,
1038 struct snd_soc_codec_conf **codec_conf)
1039 {
1040 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1041 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1042 int ret, i;
1043
1044 for (i = 0; i < SDW_INTEL_MAX_LINKS; i++)
1045 intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE;
1046
1047 /* generate DAI links by each sdw link */
1048 while (sof_dais->initialised) {
1049 int current_be_id = 0;
1050
1051 ret = create_sdw_dailink(card, sof_dais, dai_links,
1052 ¤t_be_id, codec_conf);
1053 if (ret)
1054 return ret;
1055
1056 /* Update the be_id to match the highest ID used for SDW link */
1057 if (*be_id < current_be_id)
1058 *be_id = current_be_id;
1059
1060 sof_dais++;
1061 }
1062
1063 return 0;
1064 }
1065
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)1066 static int create_ssp_dailinks(struct snd_soc_card *card,
1067 struct snd_soc_dai_link **dai_links, int *be_id,
1068 struct asoc_sdw_codec_info *ssp_info,
1069 unsigned long ssp_mask)
1070 {
1071 struct device *dev = card->dev;
1072 int i, j = 0;
1073 int ret;
1074
1075 for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) {
1076 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
1077 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1078 char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1079 ssp_info->acpi_id, j++);
1080 if (!name || !cpu_dai_name || !codec_name)
1081 return -ENOMEM;
1082
1083 int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
1084 int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
1085
1086 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1087 playback, capture, cpu_dai_name,
1088 "dummy", codec_name,
1089 ssp_info->dais[0].dai_name, 1, NULL,
1090 ssp_info->ops);
1091 if (ret)
1092 return ret;
1093
1094 ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0);
1095 if (ret < 0)
1096 return ret;
1097
1098 (*dai_links)++;
1099 }
1100
1101 return 0;
1102 }
1103
create_dmic_dailinks(struct snd_soc_card * card,struct snd_soc_dai_link ** dai_links,int * be_id)1104 static int create_dmic_dailinks(struct snd_soc_card *card,
1105 struct snd_soc_dai_link **dai_links, int *be_id)
1106 {
1107 struct device *dev = card->dev;
1108 int ret;
1109
1110 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01",
1111 0, 1, // DMIC only supports capture
1112 "DMIC01 Pin", "dummy",
1113 "dmic-codec", "dmic-hifi", 1,
1114 asoc_sdw_dmic_init, NULL);
1115 if (ret)
1116 return ret;
1117
1118 (*dai_links)++;
1119
1120 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k",
1121 0, 1, // DMIC only supports capture
1122 "DMIC16k Pin", "dummy",
1123 "dmic-codec", "dmic-hifi", 1,
1124 /* don't call asoc_sdw_dmic_init() twice */
1125 NULL, NULL);
1126 if (ret)
1127 return ret;
1128
1129 (*dai_links)++;
1130
1131 return 0;
1132 }
1133
create_hdmi_dailinks(struct snd_soc_card * card,struct snd_soc_dai_link ** dai_links,int * be_id,int hdmi_num)1134 static int create_hdmi_dailinks(struct snd_soc_card *card,
1135 struct snd_soc_dai_link **dai_links, int *be_id,
1136 int hdmi_num)
1137 {
1138 struct device *dev = card->dev;
1139 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1140 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1141 int i, ret;
1142
1143 for (i = 0; i < hdmi_num; i++) {
1144 char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
1145 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
1146 if (!name || !cpu_dai_name)
1147 return -ENOMEM;
1148
1149 char *codec_name, *codec_dai_name;
1150
1151 if (intel_ctx->hdmi.idisp_codec) {
1152 codec_name = "ehdaudio0D2";
1153 codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
1154 "intel-hdmi-hifi%d", i + 1);
1155 } else {
1156 codec_name = "snd-soc-dummy";
1157 codec_dai_name = "snd-soc-dummy-dai";
1158 }
1159
1160 if (!codec_dai_name)
1161 return -ENOMEM;
1162
1163 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1164 1, 0, // HDMI only supports playback
1165 cpu_dai_name, "dummy",
1166 codec_name, codec_dai_name, 1,
1167 i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
1168 if (ret)
1169 return ret;
1170
1171 (*dai_links)++;
1172 }
1173
1174 return 0;
1175 }
1176
create_bt_dailinks(struct snd_soc_card * card,struct snd_soc_dai_link ** dai_links,int * be_id)1177 static int create_bt_dailinks(struct snd_soc_card *card,
1178 struct snd_soc_dai_link **dai_links, int *be_id)
1179 {
1180 struct device *dev = card->dev;
1181 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
1182 char *cpu_dai_name;
1183 char *name;
1184 int port;
1185 int ret;
1186
1187 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1188 port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> SOF_BT_OFFLOAD_SSP_SHIFT;
1189 else
1190 port = fls(mach->mach_params.bt_link_mask) - 1;
1191
1192 name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1193 cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1194 if (!name || !cpu_dai_name)
1195 return -ENOMEM;
1196
1197 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1198 1, 1, cpu_dai_name, "dummy",
1199 snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
1200 1, NULL, NULL);
1201 if (ret)
1202 return ret;
1203
1204 (*dai_links)++;
1205
1206 return 0;
1207 }
1208
create_echoref_dailink(struct snd_soc_card * card,struct snd_soc_dai_link ** dai_links,int * be_id)1209 static int create_echoref_dailink(struct snd_soc_card *card,
1210 struct snd_soc_dai_link **dai_links, int *be_id)
1211 {
1212 struct device *dev = card->dev;
1213 int ret;
1214 char *name = devm_kasprintf(dev, GFP_KERNEL, "Loopback_Virtual");
1215
1216 if (!name)
1217 return -ENOMEM;
1218
1219 /*
1220 * use dummy DAI names as this won't be connected to an actual DAI but just to establish a
1221 * fe <-> be connection for loopback capture for echo reference
1222 */
1223 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1224 0, 1, "Loopback Virtual Pin", "dummy",
1225 snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
1226 1, NULL, NULL);
1227 if (ret)
1228 return ret;
1229
1230 (*dai_links)++;
1231
1232 dev_dbg(dev, "Added echo reference DAI link\n");
1233
1234 return 0;
1235 }
1236
sof_card_dai_links_create(struct snd_soc_card * card)1237 static int sof_card_dai_links_create(struct snd_soc_card *card)
1238 {
1239 struct device *dev = card->dev;
1240 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
1241 int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
1242 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1243 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1244 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1245 struct snd_soc_codec_conf *codec_conf;
1246 struct asoc_sdw_codec_info *ssp_info;
1247 struct asoc_sdw_endpoint *sof_ends;
1248 struct asoc_sdw_dailink *sof_dais;
1249 struct snd_soc_aux_dev *sof_aux;
1250 int num_devs = 0;
1251 int num_ends = 0;
1252 int num_aux = 0;
1253 int num_confs;
1254 struct snd_soc_dai_link *dai_links;
1255 int num_links;
1256 int be_id = 0;
1257 int hdmi_num;
1258 unsigned long ssp_mask;
1259 int ret;
1260
1261 ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux);
1262 if (ret < 0) {
1263 dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
1264 return ret;
1265 }
1266
1267 num_confs = num_ends;
1268
1269 /*
1270 * One per DAI link, worst case is a DAI link for every endpoint, also
1271 * add one additional to act as a terminator such that code can iterate
1272 * until it hits an uninitialised DAI.
1273 */
1274 sof_dais = kzalloc_objs(*sof_dais, num_ends + 1);
1275 if (!sof_dais)
1276 return -ENOMEM;
1277
1278 /* One per endpoint, ie. each DAI on each codec/amp */
1279 sof_ends = kzalloc_objs(*sof_ends, num_ends);
1280 if (!sof_ends) {
1281 ret = -ENOMEM;
1282 goto err_dai;
1283 }
1284
1285 sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL);
1286 if (!sof_aux) {
1287 ret = -ENOMEM;
1288 goto err_dai;
1289 }
1290
1291 ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
1292 if (ret < 0)
1293 goto err_end;
1294
1295 sdw_be_num = ret;
1296
1297 /*
1298 * on generic tgl platform, I2S or sdw mode is supported
1299 * based on board rework. A ACPI device is registered in
1300 * system only when I2S mode is supported, not sdw mode.
1301 * Here check ACPI ID to confirm I2S is supported.
1302 */
1303 ssp_info = asoc_sdw_find_codec_info_acpi(mach->id);
1304 if (ssp_info) {
1305 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1306 ssp_num = hweight_long(ssp_mask);
1307 }
1308
1309 if (mach_params->codec_mask & IDISP_CODEC_MASK)
1310 intel_ctx->hdmi.idisp_codec = true;
1311
1312 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1313 hdmi_num = SOF_TGL_HDMI_COUNT;
1314 else
1315 hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1316
1317 /* enable dmic01 & dmic16k */
1318 if (ctx->ignore_internal_dmic) {
1319 dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n");
1320 mach_params->dmic_num = 0;
1321 } else if (mach_params->dmic_num) {
1322 dmic_num = 2;
1323 } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) {
1324 dmic_num = 2;
1325 /*
1326 * mach_params->dmic_num will be used to set the cfg-mics value of
1327 * card->components string. Set it to the default value.
1328 */
1329 mach_params->dmic_num = DMIC_DEFAULT_CHANNELS;
1330 }
1331
1332 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT || mach_params->bt_link_mask)
1333 bt_num = 1;
1334
1335 dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
1336 sdw_be_num, ssp_num, dmic_num,
1337 intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
1338
1339 codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL);
1340 if (!codec_conf) {
1341 ret = -ENOMEM;
1342 goto err_end;
1343 }
1344
1345 /*
1346 * allocate BE dailinks, add an extra DAI link for echo reference capture.
1347 * This should be the last DAI link and it is expected both for monolithic
1348 * and functional SOF topologies to support echo reference.
1349 */
1350 num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + 1;
1351 dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
1352 if (!dai_links) {
1353 ret = -ENOMEM;
1354 goto err_end;
1355 }
1356
1357 card->codec_conf = codec_conf;
1358 card->num_configs = num_confs;
1359 card->dai_link = dai_links;
1360 card->num_links = num_links;
1361 card->aux_dev = sof_aux;
1362 card->num_aux_devs = num_aux;
1363
1364 /* SDW */
1365 if (sdw_be_num) {
1366 ret = create_sdw_dailinks(card, &dai_links, &be_id,
1367 sof_dais, &codec_conf);
1368 if (ret)
1369 goto err_end;
1370 }
1371
1372 /* SSP */
1373 if (ssp_num) {
1374 ret = create_ssp_dailinks(card, &dai_links, &be_id,
1375 ssp_info, ssp_mask);
1376 if (ret)
1377 goto err_end;
1378 }
1379
1380 /* dmic */
1381 if (dmic_num) {
1382 ret = create_dmic_dailinks(card, &dai_links, &be_id);
1383 if (ret)
1384 goto err_end;
1385 }
1386
1387 /* HDMI */
1388 ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num);
1389 if (ret)
1390 goto err_end;
1391
1392 /* BT */
1393 if (bt_num) {
1394 ret = create_bt_dailinks(card, &dai_links, &be_id);
1395 if (ret)
1396 goto err_end;
1397 }
1398
1399 /* dummy echo ref link. keep this as the last DAI link. The DAI link ID does not matter */
1400 ret = create_echoref_dailink(card, &dai_links, &be_id);
1401 if (ret) {
1402 dev_err(dev, "failed to create echo ref dai link: %d\n", ret);
1403 goto err_end;
1404 }
1405
1406 WARN_ON(codec_conf != card->codec_conf + card->num_configs);
1407 WARN_ON(dai_links != card->dai_link + card->num_links);
1408
1409 err_end:
1410 kfree(sof_ends);
1411 err_dai:
1412 kfree(sof_dais);
1413
1414 return ret;
1415 }
1416
sof_sdw_card_late_probe(struct snd_soc_card * card)1417 static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1418 {
1419 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1420 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1421 int ret = 0;
1422
1423 ret = asoc_sdw_card_late_probe(card);
1424 if (ret < 0)
1425 return ret;
1426
1427 if (intel_ctx->hdmi.idisp_codec)
1428 ret = sof_sdw_hdmi_card_late_probe(card);
1429
1430 return ret;
1431 }
1432
sof_sdw_add_dai_link(struct snd_soc_card * card,struct snd_soc_dai_link * link)1433 static int sof_sdw_add_dai_link(struct snd_soc_card *card,
1434 struct snd_soc_dai_link *link)
1435 {
1436 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1437 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1438
1439 /* Ignore the HDMI PCM link if iDisp is not present */
1440 if (strstr(link->stream_name, "HDMI") && !intel_ctx->hdmi.idisp_codec)
1441 link->ignore = true;
1442
1443 return 0;
1444 }
1445
mc_probe(struct platform_device * pdev)1446 static int mc_probe(struct platform_device *pdev)
1447 {
1448 struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
1449 struct snd_soc_card *card;
1450 struct asoc_sdw_mc_private *ctx;
1451 struct intel_mc_ctx *intel_ctx;
1452 int amp_num = 0, i;
1453 int ret;
1454
1455 dev_dbg(&pdev->dev, "Entry\n");
1456
1457 intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL);
1458 if (!intel_ctx)
1459 return -ENOMEM;
1460
1461 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1462 if (!ctx)
1463 return -ENOMEM;
1464
1465 ctx->private = intel_ctx;
1466 ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
1467 card = &ctx->card;
1468 card->dev = &pdev->dev;
1469 card->name = "soundwire";
1470 card->owner = THIS_MODULE;
1471 card->late_probe = sof_sdw_card_late_probe;
1472 card->add_dai_link = sof_sdw_add_dai_link;
1473
1474 snd_soc_card_set_drvdata(card, ctx);
1475
1476 if (mach->mach_params.subsystem_id_set) {
1477 snd_soc_card_set_pci_ssid(card,
1478 mach->mach_params.subsystem_vendor,
1479 mach->mach_params.subsystem_device);
1480 sof_sdw_check_ssid_quirk(mach);
1481 }
1482
1483 dmi_check_system(sof_sdw_quirk_table);
1484
1485 if (quirk_override != -1) {
1486 dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
1487 sof_sdw_quirk, quirk_override);
1488 sof_sdw_quirk = quirk_override;
1489 }
1490
1491 log_quirks(&pdev->dev);
1492
1493 ctx->mc_quirk = sof_sdw_quirk;
1494 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
1495 for (i = 0; i < ctx->codec_info_list_count; i++)
1496 codec_info_list[i].amp_num = 0;
1497
1498 ret = sof_card_dai_links_create(card);
1499 if (ret < 0)
1500 return ret;
1501
1502 /*
1503 * the default amp_num is zero for each codec and
1504 * amp_num will only be increased for active amp
1505 * codecs on used platform
1506 */
1507 for (i = 0; i < ctx->codec_info_list_count; i++)
1508 amp_num += codec_info_list[i].amp_num;
1509
1510 card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
1511 " cfg-amp:%d", amp_num);
1512 if (!card->components)
1513 return -ENOMEM;
1514
1515 if (mach->mach_params.dmic_num) {
1516 card->components = devm_kasprintf(&pdev->dev, GFP_KERNEL,
1517 "%s mic:dmic cfg-mics:%d",
1518 card->components,
1519 mach->mach_params.dmic_num);
1520 if (!card->components)
1521 return -ENOMEM;
1522 }
1523
1524 /* Register the card */
1525 ret = devm_snd_soc_register_card(card->dev, card);
1526 if (ret) {
1527 dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed %d\n", ret);
1528 asoc_sdw_mc_dailink_exit_loop(card);
1529 return ret;
1530 }
1531
1532 platform_set_drvdata(pdev, card);
1533
1534 return ret;
1535 }
1536
mc_remove(struct platform_device * pdev)1537 static void mc_remove(struct platform_device *pdev)
1538 {
1539 struct snd_soc_card *card = platform_get_drvdata(pdev);
1540
1541 asoc_sdw_mc_dailink_exit_loop(card);
1542 }
1543
1544 static const struct platform_device_id mc_id_table[] = {
1545 { .name = "sof_sdw" },
1546 { }
1547 };
1548 MODULE_DEVICE_TABLE(platform, mc_id_table);
1549
1550 static struct platform_driver sof_sdw_driver = {
1551 .driver = {
1552 .name = "sof_sdw",
1553 .pm = &snd_soc_pm_ops,
1554 },
1555 .probe = mc_probe,
1556 .remove = mc_remove,
1557 .id_table = mc_id_table,
1558 };
1559
1560 module_platform_driver(sof_sdw_driver);
1561
1562 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1563 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1564 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1565 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1566 MODULE_LICENSE("GPL v2");
1567 MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
1568 MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
1569