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