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