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