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