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 ¤t_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