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