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