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 /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
235 .callback = sof_sdw_quirk_cb,
236 .matches = {
237 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
238 DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
239 },
240 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
241 SOC_SDW_PCH_DMIC |
242 RT711_JD2_100K),
243 },
244 {
245 /* NUC15 LAPRC710 skews */
246 .callback = sof_sdw_quirk_cb,
247 .matches = {
248 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
249 DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"),
250 },
251 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
252 SOC_SDW_PCH_DMIC |
253 RT711_JD2_100K),
254 },
255 /* TigerLake-SDCA devices */
256 {
257 .callback = sof_sdw_quirk_cb,
258 .matches = {
259 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
260 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
261 },
262 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
263 RT711_JD2),
264 },
265 {
266 .callback = sof_sdw_quirk_cb,
267 .matches = {
268 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
269 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
270 },
271 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
272 RT711_JD2),
273 },
274 /* AlderLake devices */
275 {
276 .callback = sof_sdw_quirk_cb,
277 .matches = {
278 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
279 DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
280 },
281 .driver_data = (void *)(RT711_JD2_100K |
282 SOF_SDW_TGL_HDMI |
283 SOF_BT_OFFLOAD_SSP(2) |
284 SOF_SSP_BT_OFFLOAD_PRESENT),
285 },
286 {
287 .callback = sof_sdw_quirk_cb,
288 .matches = {
289 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
290 DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"),
291 },
292 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
293 RT711_JD2_100K),
294 },
295 {
296 .callback = sof_sdw_quirk_cb,
297 .matches = {
298 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
299 DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
300 },
301 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
302 SOC_SDW_PCH_DMIC |
303 SOF_BT_OFFLOAD_SSP(2) |
304 SOF_SSP_BT_OFFLOAD_PRESENT),
305 },
306 {
307 .callback = sof_sdw_quirk_cb,
308 .matches = {
309 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
310 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
311 },
312 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
313 RT711_JD2),
314 },
315 {
316 .callback = sof_sdw_quirk_cb,
317 .matches = {
318 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
319 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
320 },
321 /* No Jack */
322 .driver_data = (void *)(SOF_SDW_TGL_HDMI),
323 },
324 {
325 .callback = sof_sdw_quirk_cb,
326 .matches = {
327 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
328 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
329 },
330 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
331 RT711_JD2),
332 },
333 {
334 .callback = sof_sdw_quirk_cb,
335 .matches = {
336 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
337 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
338 },
339 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
340 RT711_JD2),
341 },
342 {
343 .callback = sof_sdw_quirk_cb,
344 .matches = {
345 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
346 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
347 },
348 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
349 RT711_JD2),
350 },
351 {
352 .callback = sof_sdw_quirk_cb,
353 .matches = {
354 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
355 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
356 },
357 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
358 RT711_JD2),
359 },
360 {
361 .callback = sof_sdw_quirk_cb,
362 .matches = {
363 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
364 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
365 },
366 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
367 RT711_JD2),
368 },
369 {
370 .callback = sof_sdw_quirk_cb,
371 .matches = {
372 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
373 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
374 },
375 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
376 RT711_JD2),
377 },
378 {
379 .callback = sof_sdw_quirk_cb,
380 .matches = {
381 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
382 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
383 },
384 /* No Jack */
385 .driver_data = (void *)SOF_SDW_TGL_HDMI,
386 },
387 {
388 .callback = sof_sdw_quirk_cb,
389 .matches = {
390 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
391 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B14"),
392 },
393 /* No Jack */
394 .driver_data = (void *)SOF_SDW_TGL_HDMI,
395 },
396
397 {
398 .callback = sof_sdw_quirk_cb,
399 .matches = {
400 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
401 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
402 },
403 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
404 RT711_JD2),
405 },
406 {
407 .callback = sof_sdw_quirk_cb,
408 .matches = {
409 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
410 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B34"),
411 },
412 /* No Jack */
413 .driver_data = (void *)SOF_SDW_TGL_HDMI,
414 },
415 {
416 .callback = sof_sdw_quirk_cb,
417 .matches = {
418 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
419 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"),
420 },
421 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
422 RT711_JD2),
423 },
424 {
425 .callback = sof_sdw_quirk_cb,
426 .matches = {
427 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
428 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"),
429 },
430 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
431 RT711_JD2),
432 },
433 /* RaptorLake devices */
434 {
435 .callback = sof_sdw_quirk_cb,
436 .matches = {
437 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
438 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA")
439 },
440 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
441 RT711_JD2),
442 },
443 {
444 .callback = sof_sdw_quirk_cb,
445 .matches = {
446 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
447 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F")
448 },
449 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
450 RT711_JD2),
451 },
452 {
453 .callback = sof_sdw_quirk_cb,
454 .matches = {
455 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
456 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
457 },
458 /* No Jack */
459 .driver_data = (void *)(SOF_SDW_TGL_HDMI),
460 },
461 {
462 .callback = sof_sdw_quirk_cb,
463 .matches = {
464 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
465 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
466 },
467 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
468 RT711_JD2),
469 },
470 {
471 .callback = sof_sdw_quirk_cb,
472 .matches = {
473 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
474 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
475 },
476 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
477 RT711_JD2),
478 },
479 {
480 .callback = sof_sdw_quirk_cb,
481 .matches = {
482 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
483 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
484 },
485 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
486 RT711_JD2),
487 },
488 {
489 .callback = sof_sdw_quirk_cb,
490 .matches = {
491 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
492 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6")
493 },
494 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
495 },
496 {
497 .callback = sof_sdw_quirk_cb,
498 .matches = {
499 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
500 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9")
501 },
502 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
503 },
504 {
505 .callback = sof_sdw_quirk_cb,
506 .matches = {
507 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
508 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA")
509 },
510 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
511 },
512 /* MeteorLake devices */
513 {
514 .callback = sof_sdw_quirk_cb,
515 .matches = {
516 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
517 },
518 .driver_data = (void *)(RT711_JD1),
519 },
520 {
521 .callback = sof_sdw_quirk_cb,
522 .matches = {
523 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
524 DMI_MATCH(DMI_PRODUCT_NAME, "Meteor Lake Client Platform"),
525 },
526 .driver_data = (void *)(RT711_JD2_100K),
527 },
528 {
529 .callback = sof_sdw_quirk_cb,
530 .matches = {
531 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
532 DMI_MATCH(DMI_PRODUCT_NAME, "Rex"),
533 },
534 .driver_data = (void *)(SOC_SDW_PCH_DMIC |
535 SOF_BT_OFFLOAD_SSP(1) |
536 SOF_SSP_BT_OFFLOAD_PRESENT),
537 },
538 {
539 .callback = sof_sdw_quirk_cb,
540 .matches = {
541 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
542 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"),
543 },
544 .driver_data = (void *)(RT711_JD2),
545 },
546
547 /* LunarLake devices */
548 {
549 .callback = sof_sdw_quirk_cb,
550 .matches = {
551 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
552 DMI_MATCH(DMI_PRODUCT_NAME, "Lunar Lake Client Platform"),
553 },
554 .driver_data = (void *)(RT711_JD2),
555 },
556 {
557 .callback = sof_sdw_quirk_cb,
558 .matches = {
559 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
560 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3")
561 },
562 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
563 },
564 {
565 .callback = sof_sdw_quirk_cb,
566 .matches = {
567 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
568 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4")
569 },
570 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS),
571 },
572 {
573 .callback = sof_sdw_quirk_cb,
574 .matches = {
575 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
576 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB")
577 },
578 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
579 },
580 {
581 .callback = sof_sdw_quirk_cb,
582 .matches = {
583 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
584 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC")
585 },
586 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
587 },
588 {
589 .callback = sof_sdw_quirk_cb,
590 .matches = {
591 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
592 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD")
593 },
594 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
595 },
596 {
597 .callback = sof_sdw_quirk_cb,
598 .matches = {
599 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
600 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36")
601 },
602 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
603 },
604 {
605 .callback = sof_sdw_quirk_cb,
606 .matches = {
607 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
608 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8")
609 },
610 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
611 },
612 {
613 .callback = sof_sdw_quirk_cb,
614 .matches = {
615 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
616 DMI_MATCH(DMI_PRODUCT_NAME, "83JX")
617 },
618 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
619 },
620 {
621 .callback = sof_sdw_quirk_cb,
622 .matches = {
623 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
624 DMI_MATCH(DMI_PRODUCT_NAME, "83LC")
625 },
626 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
627 },
628 {
629 .callback = sof_sdw_quirk_cb,
630 .matches = {
631 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
632 DMI_MATCH(DMI_PRODUCT_NAME, "83MC")
633 },
634 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
635 }, {
636 .callback = sof_sdw_quirk_cb,
637 .matches = {
638 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
639 DMI_MATCH(DMI_PRODUCT_NAME, "83NM")
640 },
641 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
642 },
643 {
644 .callback = sof_sdw_quirk_cb,
645 .matches = {
646 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
647 DMI_MATCH(DMI_PRODUCT_NAME, "83HM")
648 },
649 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS |
650 SOC_SDW_CODEC_MIC),
651 },
652 {
653 .callback = sof_sdw_quirk_cb,
654 .matches = {
655 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
656 DMI_MATCH(DMI_PRODUCT_NAME, "21QB")
657 },
658 /* Note this quirk excludes the CODEC mic */
659 .driver_data = (void *)(SOC_SDW_CODEC_MIC),
660 },
661 {
662 .callback = sof_sdw_quirk_cb,
663 .matches = {
664 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
665 DMI_MATCH(DMI_PRODUCT_NAME, "21QA")
666 },
667 /* Note this quirk excludes the CODEC mic */
668 .driver_data = (void *)(SOC_SDW_CODEC_MIC),
669 },
670 {
671 .callback = sof_sdw_quirk_cb,
672 .matches = {
673 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
674 DMI_MATCH(DMI_PRODUCT_NAME, "21Q6")
675 },
676 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
677 },
678 {
679 .callback = sof_sdw_quirk_cb,
680 .matches = {
681 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
682 DMI_MATCH(DMI_PRODUCT_NAME, "21Q7")
683 },
684 .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC),
685 },
686
687 /* ArrowLake devices */
688 {
689 .callback = sof_sdw_quirk_cb,
690 .matches = {
691 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
692 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8")
693 },
694 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
695 },
696 {
697 .callback = sof_sdw_quirk_cb,
698 .matches = {
699 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
700 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1")
701 },
702 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
703 },
704 {
705 .callback = sof_sdw_quirk_cb,
706 .matches = {
707 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
708 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7")
709 },
710 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
711 },
712 {
713 .callback = sof_sdw_quirk_cb,
714 .matches = {
715 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
716 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0")
717 },
718 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
719 },
720 {
721 .callback = sof_sdw_quirk_cb,
722 .matches = {
723 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
724 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3")
725 },
726 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
727 },
728 {
729 .callback = sof_sdw_quirk_cb,
730 .matches = {
731 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
732 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4")
733 },
734 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
735 },
736 {
737 .callback = sof_sdw_quirk_cb,
738 .matches = {
739 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
740 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5")
741 },
742 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
743 },
744 {
745 .callback = sof_sdw_quirk_cb,
746 .matches = {
747 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
748 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CCC")
749 },
750 .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
751 },
752 /* Pantherlake devices*/
753 {
754 .callback = sof_sdw_quirk_cb,
755 .matches = {
756 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"),
757 },
758 .driver_data = (void *)(SOC_SDW_PCH_DMIC),
759 },
760 {
761 .callback = sof_sdw_quirk_cb,
762 .matches = {
763 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
764 DMI_MATCH(DMI_PRODUCT_NAME, "Fatcat"),
765 },
766 .driver_data = (void *)(SOC_SDW_PCH_DMIC |
767 SOF_BT_OFFLOAD_SSP(2) |
768 SOF_SSP_BT_OFFLOAD_PRESENT),
769 },
770 /* Wildcatlake devices*/
771 {
772 .callback = sof_sdw_quirk_cb,
773 .matches = {
774 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_wclrvp"),
775 },
776 .driver_data = (void *)(SOC_SDW_PCH_DMIC),
777 },
778 {
779 .callback = sof_sdw_quirk_cb,
780 .matches = {
781 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
782 DMI_MATCH(DMI_PRODUCT_NAME, "Ocelot"),
783 },
784 .driver_data = (void *)(SOC_SDW_PCH_DMIC |
785 SOF_BT_OFFLOAD_SSP(2) |
786 SOF_SSP_BT_OFFLOAD_PRESENT),
787 },
788 {}
789 };
790
791 static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = {
792 SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC),
793 SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC),
794 SND_PCI_QUIRK(0x17aa, 0x2347, "Lenovo P16", SOC_SDW_CODEC_MIC),
795 SND_PCI_QUIRK(0x17aa, 0x2348, "Lenovo P16", SOC_SDW_CODEC_MIC),
796 SND_PCI_QUIRK(0x17aa, 0x2349, "Lenovo P1", SOC_SDW_CODEC_MIC),
797 {}
798 };
799
sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach * mach)800 static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach)
801 {
802 const struct snd_pci_quirk *quirk_entry;
803
804 quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor,
805 mach->mach_params.subsystem_device,
806 sof_sdw_ssid_quirk_table);
807
808 if (quirk_entry)
809 sof_sdw_quirk = quirk_entry->value;
810 }
811
812 static const struct snd_soc_ops sdw_ops = {
813 .startup = asoc_sdw_startup,
814 .prepare = asoc_sdw_prepare,
815 .trigger = asoc_sdw_trigger,
816 .hw_params = asoc_sdw_hw_params,
817 .hw_free = asoc_sdw_hw_free,
818 .shutdown = asoc_sdw_shutdown,
819 };
820
821 static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
822
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)823 static int create_sdw_dailink(struct snd_soc_card *card,
824 struct asoc_sdw_dailink *sof_dai,
825 struct snd_soc_dai_link **dai_links,
826 int *be_id, struct snd_soc_codec_conf **codec_conf)
827 {
828 struct device *dev = card->dev;
829 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
830 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
831 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
832 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
833 struct asoc_sdw_endpoint *sof_end;
834 int stream;
835 int ret;
836
837 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
838 if (sof_end->name_prefix) {
839 (*codec_conf)->dlc.name = sof_end->codec_name;
840 (*codec_conf)->name_prefix = sof_end->name_prefix;
841 (*codec_conf)++;
842 }
843
844 if (sof_end->include_sidecar) {
845 ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf);
846 if (ret)
847 return ret;
848 }
849 }
850
851 for_each_pcm_streams(stream) {
852 static const char * const sdw_stream_name[] = {
853 "SDW%d-Playback",
854 "SDW%d-Capture",
855 "SDW%d-Playback-%s",
856 "SDW%d-Capture-%s",
857 };
858 struct snd_soc_dai_link_ch_map *codec_maps;
859 struct snd_soc_dai_link_component *codecs;
860 struct snd_soc_dai_link_component *cpus;
861 struct snd_soc_dai_link_component *platform;
862 int num_cpus = hweight32(sof_dai->link_mask[stream]);
863 int num_codecs = sof_dai->num_devs[stream];
864 int playback, capture;
865 int cur_link = 0;
866 int i = 0, j = 0;
867 char *name;
868
869 if (!sof_dai->num_devs[stream])
870 continue;
871
872 sof_end = list_first_entry(&sof_dai->endpoints,
873 struct asoc_sdw_endpoint, list);
874
875 *be_id = sof_end->dai_info->dailink[stream];
876 if (*be_id < 0) {
877 dev_err(dev, "Invalid dailink id %d\n", *be_id);
878 return -EINVAL;
879 }
880
881 /* create stream name according to first link id */
882 if (ctx->append_dai_type)
883 name = devm_kasprintf(dev, GFP_KERNEL,
884 sdw_stream_name[stream + 2],
885 ffs(sof_end->link_mask) - 1,
886 type_strings[sof_end->dai_info->dai_type]);
887 else
888 name = devm_kasprintf(dev, GFP_KERNEL,
889 sdw_stream_name[stream],
890 ffs(sof_end->link_mask) - 1);
891 if (!name)
892 return -ENOMEM;
893
894 cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL);
895 if (!cpus)
896 return -ENOMEM;
897
898 codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL);
899 if (!codecs)
900 return -ENOMEM;
901
902 platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);
903 if (!platform)
904 return -ENOMEM;
905
906 codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL);
907 if (!codec_maps)
908 return -ENOMEM;
909
910 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
911 if (!sof_end->dai_info->direction[stream])
912 continue;
913
914 if (cur_link != sof_end->link_mask) {
915 int link_num = ffs(sof_end->link_mask) - 1;
916 int pin_num = intel_ctx->sdw_pin_index[link_num]++;
917
918 cur_link = sof_end->link_mask;
919
920 cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL,
921 "SDW%d Pin%d",
922 link_num, pin_num);
923 if (!cpus[i].dai_name)
924 return -ENOMEM;
925 i++;
926 }
927
928 codec_maps[j].cpu = i - 1;
929 codec_maps[j].codec = j;
930
931 codecs[j].name = sof_end->codec_name;
932 codecs[j].dai_name = sof_end->dai_info->dai_name;
933 if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC &&
934 mach_params->dmic_num > 0) {
935 dev_warn(dev,
936 "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");
937 }
938 j++;
939 }
940
941 WARN_ON(i != num_cpus || j != num_codecs);
942
943 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
944 capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
945
946 asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture,
947 cpus, num_cpus, platform, 1, codecs, num_codecs,
948 1, asoc_sdw_rtd_init, &sdw_ops);
949
950 /*
951 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
952 * based on wait_for_completion(), tag them as 'nonatomic'.
953 */
954 (*dai_links)->nonatomic = true;
955 (*dai_links)->ch_maps = codec_maps;
956
957 list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
958 if (sof_end->dai_info->init)
959 sof_end->dai_info->init(card, *dai_links,
960 sof_end->codec_info,
961 playback);
962 }
963
964 (*dai_links)++;
965 }
966
967 return 0;
968 }
969
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)970 static int create_sdw_dailinks(struct snd_soc_card *card,
971 struct snd_soc_dai_link **dai_links, int *be_id,
972 struct asoc_sdw_dailink *sof_dais,
973 struct snd_soc_codec_conf **codec_conf)
974 {
975 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
976 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
977 int ret, i;
978
979 for (i = 0; i < SDW_INTEL_MAX_LINKS; i++)
980 intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE;
981
982 /* generate DAI links by each sdw link */
983 while (sof_dais->initialised) {
984 int current_be_id = 0;
985
986 ret = create_sdw_dailink(card, sof_dais, dai_links,
987 ¤t_be_id, codec_conf);
988 if (ret)
989 return ret;
990
991 /* Update the be_id to match the highest ID used for SDW link */
992 if (*be_id < current_be_id)
993 *be_id = current_be_id;
994
995 sof_dais++;
996 }
997
998 return 0;
999 }
1000
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)1001 static int create_ssp_dailinks(struct snd_soc_card *card,
1002 struct snd_soc_dai_link **dai_links, int *be_id,
1003 struct asoc_sdw_codec_info *ssp_info,
1004 unsigned long ssp_mask)
1005 {
1006 struct device *dev = card->dev;
1007 int i, j = 0;
1008 int ret;
1009
1010 for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) {
1011 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i);
1012 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1013 char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1014 ssp_info->acpi_id, j++);
1015 if (!name || !cpu_dai_name || !codec_name)
1016 return -ENOMEM;
1017
1018 int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK];
1019 int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE];
1020
1021 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1022 playback, capture, cpu_dai_name,
1023 "dummy", codec_name,
1024 ssp_info->dais[0].dai_name, 1, NULL,
1025 ssp_info->ops);
1026 if (ret)
1027 return ret;
1028
1029 ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0);
1030 if (ret < 0)
1031 return ret;
1032
1033 (*dai_links)++;
1034 }
1035
1036 return 0;
1037 }
1038
create_dmic_dailinks(struct snd_soc_card * card,struct snd_soc_dai_link ** dai_links,int * be_id)1039 static int create_dmic_dailinks(struct snd_soc_card *card,
1040 struct snd_soc_dai_link **dai_links, int *be_id)
1041 {
1042 struct device *dev = card->dev;
1043 int ret;
1044
1045 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01",
1046 0, 1, // DMIC only supports capture
1047 "DMIC01 Pin", "dummy",
1048 "dmic-codec", "dmic-hifi", 1,
1049 asoc_sdw_dmic_init, NULL);
1050 if (ret)
1051 return ret;
1052
1053 (*dai_links)++;
1054
1055 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k",
1056 0, 1, // DMIC only supports capture
1057 "DMIC16k Pin", "dummy",
1058 "dmic-codec", "dmic-hifi", 1,
1059 /* don't call asoc_sdw_dmic_init() twice */
1060 NULL, NULL);
1061 if (ret)
1062 return ret;
1063
1064 (*dai_links)++;
1065
1066 return 0;
1067 }
1068
create_hdmi_dailinks(struct snd_soc_card * card,struct snd_soc_dai_link ** dai_links,int * be_id,int hdmi_num)1069 static int create_hdmi_dailinks(struct snd_soc_card *card,
1070 struct snd_soc_dai_link **dai_links, int *be_id,
1071 int hdmi_num)
1072 {
1073 struct device *dev = card->dev;
1074 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1075 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1076 int i, ret;
1077
1078 for (i = 0; i < hdmi_num; i++) {
1079 char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1);
1080 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1);
1081 if (!name || !cpu_dai_name)
1082 return -ENOMEM;
1083
1084 char *codec_name, *codec_dai_name;
1085
1086 if (intel_ctx->hdmi.idisp_codec) {
1087 codec_name = "ehdaudio0D2";
1088 codec_dai_name = devm_kasprintf(dev, GFP_KERNEL,
1089 "intel-hdmi-hifi%d", i + 1);
1090 } else {
1091 codec_name = "snd-soc-dummy";
1092 codec_dai_name = "snd-soc-dummy-dai";
1093 }
1094
1095 if (!codec_dai_name)
1096 return -ENOMEM;
1097
1098 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1099 1, 0, // HDMI only supports playback
1100 cpu_dai_name, "dummy",
1101 codec_name, codec_dai_name, 1,
1102 i == 0 ? sof_sdw_hdmi_init : NULL, NULL);
1103 if (ret)
1104 return ret;
1105
1106 (*dai_links)++;
1107 }
1108
1109 return 0;
1110 }
1111
create_bt_dailinks(struct snd_soc_card * card,struct snd_soc_dai_link ** dai_links,int * be_id)1112 static int create_bt_dailinks(struct snd_soc_card *card,
1113 struct snd_soc_dai_link **dai_links, int *be_id)
1114 {
1115 struct device *dev = card->dev;
1116 int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1117 SOF_BT_OFFLOAD_SSP_SHIFT;
1118 char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1119 char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1120 if (!name || !cpu_dai_name)
1121 return -ENOMEM;
1122
1123 int ret;
1124
1125 ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name,
1126 1, 1, cpu_dai_name, "dummy",
1127 snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name,
1128 1, NULL, NULL);
1129 if (ret)
1130 return ret;
1131
1132 (*dai_links)++;
1133
1134 return 0;
1135 }
1136
sof_card_dai_links_create(struct snd_soc_card * card)1137 static int sof_card_dai_links_create(struct snd_soc_card *card)
1138 {
1139 struct device *dev = card->dev;
1140 struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
1141 int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
1142 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1143 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1144 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1145 struct snd_soc_codec_conf *codec_conf;
1146 struct asoc_sdw_codec_info *ssp_info;
1147 struct asoc_sdw_endpoint *sof_ends;
1148 struct asoc_sdw_dailink *sof_dais;
1149 int num_devs = 0;
1150 int num_ends = 0;
1151 struct snd_soc_dai_link *dai_links;
1152 int num_links;
1153 int be_id = 0;
1154 int hdmi_num;
1155 unsigned long ssp_mask;
1156 int ret;
1157
1158 ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends);
1159 if (ret < 0) {
1160 dev_err(dev, "failed to count devices/endpoints: %d\n", ret);
1161 return ret;
1162 }
1163
1164 /*
1165 * One per DAI link, worst case is a DAI link for every endpoint, also
1166 * add one additional to act as a terminator such that code can iterate
1167 * until it hits an uninitialised DAI.
1168 */
1169 sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL);
1170 if (!sof_dais)
1171 return -ENOMEM;
1172
1173 /* One per endpoint, ie. each DAI on each codec/amp */
1174 sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL);
1175 if (!sof_ends) {
1176 ret = -ENOMEM;
1177 goto err_dai;
1178 }
1179
1180 ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs);
1181 if (ret < 0)
1182 goto err_end;
1183
1184 sdw_be_num = ret;
1185
1186 /*
1187 * on generic tgl platform, I2S or sdw mode is supported
1188 * based on board rework. A ACPI device is registered in
1189 * system only when I2S mode is supported, not sdw mode.
1190 * Here check ACPI ID to confirm I2S is supported.
1191 */
1192 ssp_info = asoc_sdw_find_codec_info_acpi(mach->id);
1193 if (ssp_info) {
1194 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1195 ssp_num = hweight_long(ssp_mask);
1196 }
1197
1198 if (mach_params->codec_mask & IDISP_CODEC_MASK)
1199 intel_ctx->hdmi.idisp_codec = true;
1200
1201 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1202 hdmi_num = SOF_TGL_HDMI_COUNT;
1203 else
1204 hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1205
1206 /* enable dmic01 & dmic16k */
1207 if (ctx->ignore_internal_dmic) {
1208 dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n");
1209 mach_params->dmic_num = 0;
1210 } else if (mach_params->dmic_num) {
1211 dmic_num = 2;
1212 } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) {
1213 dmic_num = 2;
1214 /*
1215 * mach_params->dmic_num will be used to set the cfg-mics value of
1216 * card->components string. Set it to the default value.
1217 */
1218 mach_params->dmic_num = DMIC_DEFAULT_CHANNELS;
1219 }
1220
1221 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1222 bt_num = 1;
1223
1224 dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
1225 sdw_be_num, ssp_num, dmic_num,
1226 intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
1227
1228 codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL);
1229 if (!codec_conf) {
1230 ret = -ENOMEM;
1231 goto err_end;
1232 }
1233
1234 /* allocate BE dailinks */
1235 num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;
1236 dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL);
1237 if (!dai_links) {
1238 ret = -ENOMEM;
1239 goto err_end;
1240 }
1241
1242 card->codec_conf = codec_conf;
1243 card->num_configs = num_devs;
1244 card->dai_link = dai_links;
1245 card->num_links = num_links;
1246
1247 /* SDW */
1248 if (sdw_be_num) {
1249 ret = create_sdw_dailinks(card, &dai_links, &be_id,
1250 sof_dais, &codec_conf);
1251 if (ret)
1252 goto err_end;
1253 }
1254
1255 /* SSP */
1256 if (ssp_num) {
1257 ret = create_ssp_dailinks(card, &dai_links, &be_id,
1258 ssp_info, ssp_mask);
1259 if (ret)
1260 goto err_end;
1261 }
1262
1263 /* dmic */
1264 if (dmic_num) {
1265 ret = create_dmic_dailinks(card, &dai_links, &be_id);
1266 if (ret)
1267 goto err_end;
1268 }
1269
1270 /* HDMI */
1271 ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num);
1272 if (ret)
1273 goto err_end;
1274
1275 /* BT */
1276 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
1277 ret = create_bt_dailinks(card, &dai_links, &be_id);
1278 if (ret)
1279 goto err_end;
1280 }
1281
1282 WARN_ON(codec_conf != card->codec_conf + card->num_configs);
1283 WARN_ON(dai_links != card->dai_link + card->num_links);
1284
1285 err_end:
1286 kfree(sof_ends);
1287 err_dai:
1288 kfree(sof_dais);
1289
1290 return ret;
1291 }
1292
sof_sdw_card_late_probe(struct snd_soc_card * card)1293 static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1294 {
1295 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1296 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1297 int ret = 0;
1298
1299 ret = asoc_sdw_card_late_probe(card);
1300 if (ret < 0)
1301 return ret;
1302
1303 if (intel_ctx->hdmi.idisp_codec)
1304 ret = sof_sdw_hdmi_card_late_probe(card);
1305
1306 return ret;
1307 }
1308
sof_sdw_add_dai_link(struct snd_soc_card * card,struct snd_soc_dai_link * link)1309 static int sof_sdw_add_dai_link(struct snd_soc_card *card,
1310 struct snd_soc_dai_link *link)
1311 {
1312 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1313 struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private;
1314
1315 /* Ignore the HDMI PCM link if iDisp is not present */
1316 if (strstr(link->stream_name, "HDMI") && !intel_ctx->hdmi.idisp_codec)
1317 link->ignore = true;
1318
1319 return 0;
1320 }
1321
mc_probe(struct platform_device * pdev)1322 static int mc_probe(struct platform_device *pdev)
1323 {
1324 struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev);
1325 struct snd_soc_card *card;
1326 struct asoc_sdw_mc_private *ctx;
1327 struct intel_mc_ctx *intel_ctx;
1328 int amp_num = 0, i;
1329 int ret;
1330
1331 dev_dbg(&pdev->dev, "Entry\n");
1332
1333 intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL);
1334 if (!intel_ctx)
1335 return -ENOMEM;
1336
1337 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1338 if (!ctx)
1339 return -ENOMEM;
1340
1341 ctx->private = intel_ctx;
1342 ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count();
1343 card = &ctx->card;
1344 card->dev = &pdev->dev;
1345 card->name = "soundwire";
1346 card->owner = THIS_MODULE;
1347 card->late_probe = sof_sdw_card_late_probe;
1348 card->add_dai_link = sof_sdw_add_dai_link;
1349
1350 snd_soc_card_set_drvdata(card, ctx);
1351
1352 if (mach->mach_params.subsystem_id_set) {
1353 snd_soc_card_set_pci_ssid(card,
1354 mach->mach_params.subsystem_vendor,
1355 mach->mach_params.subsystem_device);
1356 sof_sdw_check_ssid_quirk(mach);
1357 }
1358
1359 dmi_check_system(sof_sdw_quirk_table);
1360
1361 if (quirk_override != -1) {
1362 dev_info(card->dev, "Overriding quirk 0x%lx => 0x%x\n",
1363 sof_sdw_quirk, quirk_override);
1364 sof_sdw_quirk = quirk_override;
1365 }
1366
1367 log_quirks(card->dev);
1368
1369 ctx->mc_quirk = sof_sdw_quirk;
1370 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
1371 for (i = 0; i < ctx->codec_info_list_count; i++)
1372 codec_info_list[i].amp_num = 0;
1373
1374 ret = sof_card_dai_links_create(card);
1375 if (ret < 0)
1376 return ret;
1377
1378 /*
1379 * the default amp_num is zero for each codec and
1380 * amp_num will only be increased for active amp
1381 * codecs on used platform
1382 */
1383 for (i = 0; i < ctx->codec_info_list_count; i++)
1384 amp_num += codec_info_list[i].amp_num;
1385
1386 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1387 " cfg-amp:%d", amp_num);
1388 if (!card->components)
1389 return -ENOMEM;
1390
1391 if (mach->mach_params.dmic_num) {
1392 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1393 "%s mic:dmic cfg-mics:%d",
1394 card->components,
1395 mach->mach_params.dmic_num);
1396 if (!card->components)
1397 return -ENOMEM;
1398 }
1399
1400 /* Register the card */
1401 ret = devm_snd_soc_register_card(card->dev, card);
1402 if (ret) {
1403 dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret);
1404 asoc_sdw_mc_dailink_exit_loop(card);
1405 return ret;
1406 }
1407
1408 platform_set_drvdata(pdev, card);
1409
1410 return ret;
1411 }
1412
mc_remove(struct platform_device * pdev)1413 static void mc_remove(struct platform_device *pdev)
1414 {
1415 struct snd_soc_card *card = platform_get_drvdata(pdev);
1416
1417 asoc_sdw_mc_dailink_exit_loop(card);
1418 }
1419
1420 static const struct platform_device_id mc_id_table[] = {
1421 { "sof_sdw", },
1422 {}
1423 };
1424 MODULE_DEVICE_TABLE(platform, mc_id_table);
1425
1426 static struct platform_driver sof_sdw_driver = {
1427 .driver = {
1428 .name = "sof_sdw",
1429 .pm = &snd_soc_pm_ops,
1430 },
1431 .probe = mc_probe,
1432 .remove = mc_remove,
1433 .id_table = mc_id_table,
1434 };
1435
1436 module_platform_driver(sof_sdw_driver);
1437
1438 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1439 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1440 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1441 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1442 MODULE_LICENSE("GPL v2");
1443 MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
1444 MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
1445