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