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