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