Merge tag 'sound-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[linux-block.git] / sound / soc / intel / boards / sof_sdw.c
CommitLineData
e149ca29 1// SPDX-License-Identifier: GPL-2.0-only
52db12d1
PLB
2// Copyright (c) 2020 Intel Corporation
3
4/*
5 * sof_sdw - ASOC Machine driver for Intel SoundWire platforms
6 */
7
8#include <linux/device.h>
9#include <linux/dmi.h>
10#include <linux/module.h>
11#include <linux/soundwire/sdw.h>
12#include <linux/soundwire/sdw_type.h>
13#include <sound/soc.h>
14#include <sound/soc-acpi.h>
15#include "sof_sdw_common.h"
8e6c00f1 16#include "../../codecs/rt711.h"
52db12d1 17
8e6c00f1 18unsigned long sof_sdw_quirk = RT711_JD1;
2555ebe9
PLB
19static int quirk_override = -1;
20module_param_named(quirk, quirk_override, int, 0444);
21MODULE_PARM_DESC(quirk, "Board-specific quirk override");
52db12d1
PLB
22
23#define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0)
24
2555ebe9
PLB
25static void log_quirks(struct device *dev)
26{
27 if (SOF_RT711_JDSRC(sof_sdw_quirk))
28 dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
29 SOF_RT711_JDSRC(sof_sdw_quirk));
30 if (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
31 dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\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 & SOF_SDW_PCH_DMIC)
35 dev_dbg(dev, "quirk SOF_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));
2555ebe9
PLB
39 if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
40 dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n");
41}
42
52db12d1
PLB
43static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
44{
45 sof_sdw_quirk = (unsigned long)id->driver_data;
46 return 1;
47}
48
49static const struct dmi_system_id sof_sdw_quirk_table[] = {
3d09cf8d 50 /* CometLake devices */
488cdbd8
PLB
51 {
52 .callback = sof_sdw_quirk_cb,
53 .matches = {
3d09cf8d
PLB
54 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
55 DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
9ad9bc59 56 },
3d09cf8d 57 .driver_data = (void *)SOF_SDW_PCH_DMIC,
9ad9bc59 58 },
52db12d1
PLB
59 {
60 .callback = sof_sdw_quirk_cb,
61 .matches = {
62 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
63 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
64 },
f8f83122 65 .driver_data = (void *)RT711_JD2,
52db12d1
PLB
66 },
67 {
68 /* early version of SKU 09C6 */
69 .callback = sof_sdw_quirk_cb,
70 .matches = {
71 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
72 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
73 },
f8f83122 74 .driver_data = (void *)RT711_JD2,
52db12d1
PLB
75 },
76 {
77 .callback = sof_sdw_quirk_cb,
78 .matches = {
79 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
80 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
81 },
8e6c00f1 82 .driver_data = (void *)(RT711_JD2 |
52db12d1
PLB
83 SOF_SDW_FOUR_SPK),
84 },
3d09cf8d 85 {
52db12d1
PLB
86 .callback = sof_sdw_quirk_cb,
87 .matches = {
88 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
89 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
90 },
8e6c00f1 91 .driver_data = (void *)(RT711_JD2 |
52db12d1
PLB
92 SOF_SDW_FOUR_SPK),
93 },
3d09cf8d
PLB
94 /* IceLake devices */
95 {
96 .callback = sof_sdw_quirk_cb,
97 .matches = {
98 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
99 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
100 },
101 .driver_data = (void *)SOF_SDW_PCH_DMIC,
102 },
103 /* TigerLake devices */
52db12d1
PLB
104 {
105 .callback = sof_sdw_quirk_cb,
106 .matches = {
107 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
108 DMI_MATCH(DMI_PRODUCT_NAME,
109 "Tiger Lake Client Platform"),
110 },
8caf37e2 111 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
8e6c00f1 112 RT711_JD1 |
8caf37e2
PLB
113 SOF_SDW_PCH_DMIC |
114 SOF_SSP_PORT(SOF_I2S_SSP2)),
52db12d1
PLB
115 },
116 {
117 .callback = sof_sdw_quirk_cb,
118 .matches = {
3d09cf8d
PLB
119 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
120 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
52db12d1 121 },
3d09cf8d 122 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
f8f83122 123 RT711_JD2),
52db12d1 124 },
1071f241
PLB
125 {
126 /* another SKU of Dell Latitude 9520 */
127 .callback = sof_sdw_quirk_cb,
128 .matches = {
129 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
130 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3F")
131 },
132 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
f8f83122 133 RT711_JD2),
1071f241 134 },
b8cab69b
PLB
135 {
136 /* Dell XPS 9710 */
137 .callback = sof_sdw_quirk_cb,
138 .matches = {
139 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
140 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D")
141 },
142 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
143 RT711_JD2 |
b8cab69b
PLB
144 SOF_SDW_FOUR_SPK),
145 },
52db12d1
PLB
146 {
147 .callback = sof_sdw_quirk_cb,
148 .matches = {
3d09cf8d
PLB
149 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
150 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
52db12d1 151 },
3d09cf8d 152 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
8e6c00f1 153 RT711_JD2 |
3d09cf8d 154 SOF_SDW_FOUR_SPK),
52db12d1 155 },
798313f2
NM
156 {
157 .callback = sof_sdw_quirk_cb,
158 .matches = {
159 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
160 DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
161 },
8caf37e2
PLB
162 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
163 SOF_SDW_PCH_DMIC |
19f1eace
YZ
164 SOF_SDW_FOUR_SPK |
165 SOF_BT_OFFLOAD_SSP(2) |
166 SOF_SSP_BT_OFFLOAD_PRESENT),
798313f2 167 },
626200df
RW
168 {
169 .callback = sof_sdw_quirk_cb,
170 .matches = {
171 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
172 DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
173 },
8caf37e2
PLB
174 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
175 SOF_SDW_PCH_DMIC |
626200df
RW
176 SOF_SDW_FOUR_SPK),
177 },
d92e279d
PLB
178 {
179 /*
180 * this entry covers multiple HP SKUs. The family name
181 * does not seem robust enough, so we use a partial
182 * match that ignores the product name suffix
183 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
184 */
185 .callback = sof_sdw_quirk_cb,
186 .matches = {
187 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
ce73ef6e 188 DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"),
d92e279d
PLB
189 },
190 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
191 SOF_SDW_PCH_DMIC |
0527b19f 192 RT711_JD1),
d92e279d 193 },
1bd80ff2
PLB
194 {
195 /* NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
196 .callback = sof_sdw_quirk_cb,
197 .matches = {
198 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
199 DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"),
200 },
201 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
202 SOF_SDW_PCH_DMIC |
203 RT711_JD1),
204 },
41deb2db
PLB
205 {
206 /* NUC15 LAPBC710 skews */
207 .callback = sof_sdw_quirk_cb,
208 .matches = {
209 DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"),
210 DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"),
211 },
212 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
213 SOF_SDW_PCH_DMIC |
214 RT711_JD1),
215 },
3c728b1b
EH
216 {
217 /* NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
218 .callback = sof_sdw_quirk_cb,
219 .matches = {
220 DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
221 DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
222 },
223 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
224 SOF_SDW_PCH_DMIC |
225 RT711_JD2_100K),
226 },
3d09cf8d
PLB
227 /* TigerLake-SDCA devices */
228 {
229 .callback = sof_sdw_quirk_cb,
230 .matches = {
231 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
232 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
233 },
234 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
8e6c00f1 235 RT711_JD2 |
3d09cf8d
PLB
236 SOF_SDW_FOUR_SPK),
237 },
64ba6d2c
PLB
238 {
239 .callback = sof_sdw_quirk_cb,
240 .matches = {
241 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
242 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A45")
243 },
244 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
f8f83122 245 RT711_JD2),
64ba6d2c 246 },
d25bbe80
VKG
247 /* AlderLake devices */
248 {
249 .callback = sof_sdw_quirk_cb,
250 .matches = {
251 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
252 DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
253 },
f28fbe57 254 .driver_data = (void *)(RT711_JD2_100K |
d25bbe80 255 SOF_SDW_TGL_HDMI |
03effde3
VKG
256 SOF_BT_OFFLOAD_SSP(2) |
257 SOF_SSP_BT_OFFLOAD_PRESENT),
258 },
259 {
260 .callback = sof_sdw_quirk_cb,
261 .matches = {
262 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
263 DMI_MATCH(DMI_PRODUCT_NAME, "Brya"),
264 },
265 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
266 SOF_SDW_PCH_DMIC |
267 SOF_SDW_FOUR_SPK |
268 SOF_BT_OFFLOAD_SSP(2) |
269 SOF_SSP_BT_OFFLOAD_PRESENT),
d25bbe80 270 },
4e68eef4
PLB
271 {
272 .callback = sof_sdw_quirk_cb,
273 .matches = {
274 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
275 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0")
276 },
277 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
278 RT711_JD2 |
279 SOF_SDW_FOUR_SPK),
280 },
8f4fa459
GS
281 {
282 .callback = sof_sdw_quirk_cb,
283 .matches = {
284 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
285 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
286 },
287 /* No Jack */
288 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
289 SOF_SDW_FOUR_SPK),
290 },
4a13c949
PLB
291 {
292 .callback = sof_sdw_quirk_cb,
293 .matches = {
294 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
295 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
296 },
297 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
298 RT711_JD2 |
299 SOF_SDW_FOUR_SPK),
300 },
cf304329
GS
301 {
302 .callback = sof_sdw_quirk_cb,
303 .matches = {
304 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
305 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
306 },
307 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
308 RT711_JD2 |
309 SOF_SDW_FOUR_SPK),
310 },
311 {
312 .callback = sof_sdw_quirk_cb,
313 .matches = {
314 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
315 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
316 },
317 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
318 RT711_JD2 |
319 SOF_SDW_FOUR_SPK),
320 },
6fef4c2f
GS
321 {
322 .callback = sof_sdw_quirk_cb,
323 .matches = {
324 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
325 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
326 },
f55af705
GS
327 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
328 RT711_JD2 |
329 SOF_SDW_FOUR_SPK),
330 },
331 {
332 .callback = sof_sdw_quirk_cb,
333 .matches = {
334 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
335 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
336 },
6fef4c2f
GS
337 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
338 RT711_JD2 |
339 SOF_SDW_FOUR_SPK),
340 },
6448d059
GS
341 {
342 .callback = sof_sdw_quirk_cb,
343 .matches = {
344 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
345 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
346 },
347 /* No Jack */
348 .driver_data = (void *)SOF_SDW_TGL_HDMI,
349 },
0c2ed4f0
GS
350 {
351 .callback = sof_sdw_quirk_cb,
352 .matches = {
353 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
354 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
355 },
356 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
357 RT711_JD2 |
358 SOF_SDW_FOUR_SPK),
359 },
f7bbdf5b
PLB
360 {
361 .callback = sof_sdw_quirk_cb,
362 .matches = {
363 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
364 DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
365 },
366 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
367 RT711_JD2),
368 },
d608bc44
GS
369 /* RaptorLake devices */
370 {
371 .callback = sof_sdw_quirk_cb,
372 .matches = {
373 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
374 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"),
375 },
376 /* No Jack */
377 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
378 SOF_SDW_FOUR_SPK),
379 },
d84e10da
GS
380 {
381 .callback = sof_sdw_quirk_cb,
382 .matches = {
383 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
384 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11")
385 },
386 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
387 RT711_JD2 |
388 SOF_SDW_FOUR_SPK),
389 },
880bf4b4
GS
390 {
391 .callback = sof_sdw_quirk_cb,
392 .matches = {
393 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
394 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40")
395 },
396 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
397 RT711_JD2 |
398 SOF_SDW_FOUR_SPK),
399 },
a9248c86
GS
400 {
401 .callback = sof_sdw_quirk_cb,
402 .matches = {
403 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
404 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F")
405 },
406 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
407 RT711_JD2 |
408 SOF_SDW_FOUR_SPK),
409 },
18489174
YZ
410 /* MeteorLake devices */
411 {
412 .callback = sof_sdw_quirk_cb,
413 .matches = {
414 DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_mtlrvp"),
415 },
416 .driver_data = (void *)(RT711_JD1 | SOF_SDW_TGL_HDMI),
417 },
52db12d1
PLB
418 {}
419};
420
52db12d1
PLB
421static struct snd_soc_dai_link_component dmic_component[] = {
422 {
423 .name = "dmic-codec",
424 .dai_name = "dmic-hifi",
425 }
426};
427
428static struct snd_soc_dai_link_component platform_component[] = {
429 {
430 /* name might be overridden during probe */
431 .name = "0000:00:1f.3"
432 }
433};
434
435/* these wrappers are only needed to avoid typecast compilation errors */
be82e888 436int sdw_startup(struct snd_pcm_substream *substream)
52db12d1
PLB
437{
438 return sdw_startup_stream(substream);
439}
440
7cc3b56f 441int sdw_prepare(struct snd_pcm_substream *substream)
06998d49
PLB
442{
443 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
444 struct sdw_stream_runtime *sdw_stream;
445 struct snd_soc_dai *dai;
446
447 /* Find stream from first CPU DAI */
448 dai = asoc_rtd_to_cpu(rtd, 0);
449
e8444560 450 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
06998d49
PLB
451
452 if (IS_ERR(sdw_stream)) {
453 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
454 return PTR_ERR(sdw_stream);
455 }
456
457 return sdw_prepare_stream(sdw_stream);
458}
459
7cc3b56f 460int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
ae3a3918
PLB
461{
462 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
463 struct sdw_stream_runtime *sdw_stream;
464 struct snd_soc_dai *dai;
465 int ret;
466
467 /* Find stream from first CPU DAI */
468 dai = asoc_rtd_to_cpu(rtd, 0);
469
e8444560 470 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
ae3a3918
PLB
471
472 if (IS_ERR(sdw_stream)) {
473 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
474 return PTR_ERR(sdw_stream);
475 }
476
477 switch (cmd) {
478 case SNDRV_PCM_TRIGGER_START:
479 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
480 case SNDRV_PCM_TRIGGER_RESUME:
481 ret = sdw_enable_stream(sdw_stream);
482 break;
483
484 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
485 case SNDRV_PCM_TRIGGER_SUSPEND:
486 case SNDRV_PCM_TRIGGER_STOP:
487 ret = sdw_disable_stream(sdw_stream);
488 break;
489 default:
490 ret = -EINVAL;
491 break;
492 }
493
494 if (ret)
495 dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
496
497 return ret;
498}
499
7cc3b56f 500int sdw_hw_free(struct snd_pcm_substream *substream)
06998d49
PLB
501{
502 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
503 struct sdw_stream_runtime *sdw_stream;
504 struct snd_soc_dai *dai;
505
506 /* Find stream from first CPU DAI */
507 dai = asoc_rtd_to_cpu(rtd, 0);
508
e8444560 509 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
06998d49
PLB
510
511 if (IS_ERR(sdw_stream)) {
512 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
513 return PTR_ERR(sdw_stream);
514 }
515
516 return sdw_deprepare_stream(sdw_stream);
517}
518
be82e888 519void sdw_shutdown(struct snd_pcm_substream *substream)
52db12d1
PLB
520{
521 sdw_shutdown_stream(substream);
522}
523
524static const struct snd_soc_ops sdw_ops = {
525 .startup = sdw_startup,
06998d49 526 .prepare = sdw_prepare,
ae3a3918 527 .trigger = sdw_trigger,
06998d49 528 .hw_free = sdw_hw_free,
52db12d1
PLB
529 .shutdown = sdw_shutdown,
530};
531
532static struct sof_sdw_codec_info codec_info_list[] = {
533 {
535df653 534 .part_id = 0x700,
52db12d1
PLB
535 .direction = {true, true},
536 .dai_name = "rt700-aif1",
537 .init = sof_sdw_rt700_init,
d471c034 538 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
52db12d1
PLB
539 },
540 {
535df653 541 .part_id = 0x711,
b75bea4b
BL
542 .version_id = 3,
543 .direction = {true, true},
544 .dai_name = "rt711-sdca-aif1",
545 .init = sof_sdw_rt711_sdca_init,
546 .exit = sof_sdw_rt711_sdca_exit,
d471c034 547 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
b75bea4b
BL
548 },
549 {
550 .part_id = 0x711,
551 .version_id = 2,
52db12d1
PLB
552 .direction = {true, true},
553 .dai_name = "rt711-aif1",
554 .init = sof_sdw_rt711_init,
cf0418cd 555 .exit = sof_sdw_rt711_exit,
d471c034 556 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
52db12d1
PLB
557 },
558 {
535df653 559 .part_id = 0x1308,
52db12d1
PLB
560 .acpi_id = "10EC1308",
561 .direction = {true, false},
562 .dai_name = "rt1308-aif",
563 .ops = &sof_sdw_rt1308_i2s_ops,
5c10da43
GS
564 .init = sof_sdw_rt_amp_init,
565 .exit = sof_sdw_rt_amp_exit,
d471c034 566 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
52db12d1 567 },
b75bea4b
BL
568 {
569 .part_id = 0x1316,
570 .direction = {true, true},
571 .dai_name = "rt1316-aif",
5c10da43
GS
572 .init = sof_sdw_rt_amp_init,
573 .exit = sof_sdw_rt_amp_exit,
d471c034 574 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
b75bea4b 575 },
8c4b3a8e
GS
576 {
577 .part_id = 0x1318,
578 .direction = {true, true},
579 .dai_name = "rt1318-aif",
5c10da43 580 .init = sof_sdw_rt_amp_init,
8c4b3a8e
GS
581 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
582 },
b75bea4b
BL
583 {
584 .part_id = 0x714,
df64b988 585 .version_id = 3,
b75bea4b 586 .direction = {false, true},
35564e2b 587 .ignore_pch_dmic = true,
b75bea4b
BL
588 .dai_name = "rt715-aif2",
589 .init = sof_sdw_rt715_sdca_init,
d471c034 590 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
b75bea4b 591 },
52db12d1 592 {
535df653 593 .part_id = 0x715,
df64b988
PLB
594 .version_id = 3,
595 .direction = {false, true},
35564e2b 596 .ignore_pch_dmic = true,
df64b988
PLB
597 .dai_name = "rt715-aif2",
598 .init = sof_sdw_rt715_sdca_init,
d471c034 599 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
df64b988
PLB
600 },
601 {
602 .part_id = 0x714,
603 .version_id = 2,
604 .direction = {false, true},
35564e2b 605 .ignore_pch_dmic = true,
df64b988
PLB
606 .dai_name = "rt715-aif2",
607 .init = sof_sdw_rt715_init,
d471c034 608 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
df64b988
PLB
609 },
610 {
611 .part_id = 0x715,
612 .version_id = 2,
52db12d1 613 .direction = {false, true},
35564e2b 614 .ignore_pch_dmic = true,
52db12d1
PLB
615 .dai_name = "rt715-aif2",
616 .init = sof_sdw_rt715_init,
d471c034 617 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
52db12d1 618 },
be82e888 619 {
535df653 620 .part_id = 0x8373,
be82e888
NM
621 .direction = {true, true},
622 .dai_name = "max98373-aif1",
623 .init = sof_sdw_mx8373_init,
d471c034 624 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
be82e888 625 },
798313f2 626 {
535df653 627 .part_id = 0x5682,
798313f2
NM
628 .direction = {true, true},
629 .dai_name = "rt5682-sdw",
630 .init = sof_sdw_rt5682_init,
d471c034 631 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
798313f2 632 },
0ccac3bc
PLB
633 {
634 .part_id = 0xaaaa, /* generic codec mockup */
635 .version_id = 0,
636 .direction = {true, true},
637 .dai_name = "sdw-mockup-aif1",
638 .init = NULL,
d471c034 639 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0ccac3bc
PLB
640 },
641 {
642 .part_id = 0xaa55, /* headset codec mockup */
643 .version_id = 0,
644 .direction = {true, true},
645 .dai_name = "sdw-mockup-aif1",
646 .init = NULL,
d471c034 647 .codec_type = SOF_SDW_CODEC_TYPE_JACK,
0ccac3bc
PLB
648 },
649 {
650 .part_id = 0x55aa, /* amplifier mockup */
651 .version_id = 0,
652 .direction = {true, false},
653 .dai_name = "sdw-mockup-aif1",
654 .init = NULL,
d471c034 655 .codec_type = SOF_SDW_CODEC_TYPE_AMP,
0ccac3bc
PLB
656 },
657 {
658 .part_id = 0x5555,
659 .version_id = 0,
660 .direction = {false, true},
661 .dai_name = "sdw-mockup-aif1",
d471c034 662 .codec_type = SOF_SDW_CODEC_TYPE_MIC,
0ccac3bc 663 },
52db12d1
PLB
664};
665
2e2d287b 666static inline int find_codec_info_part(u64 adr)
52db12d1 667{
2e2d287b 668 unsigned int part_id, sdw_version;
52db12d1
PLB
669 int i;
670
2e2d287b
BL
671 part_id = SDW_PART_ID(adr);
672 sdw_version = SDW_VERSION(adr);
52db12d1 673 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
2e2d287b
BL
674 /*
675 * A codec info is for all sdw version with the part id if
676 * version_id is not specified in the codec info.
677 */
535df653 678 if (part_id == codec_info_list[i].part_id &&
2e2d287b
BL
679 (!codec_info_list[i].version_id ||
680 sdw_version == codec_info_list[i].version_id))
681 return i;
52db12d1 682
2e2d287b 683 return -EINVAL;
52db12d1 684
52db12d1
PLB
685}
686
687static inline int find_codec_info_acpi(const u8 *acpi_id)
688{
689 int i;
690
691 if (!acpi_id[0])
692 return -EINVAL;
693
694 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
695 if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
696 ACPI_ID_LEN))
697 break;
698
699 if (i == ARRAY_SIZE(codec_info_list))
700 return -EINVAL;
701
702 return i;
703}
704
705/*
706 * get BE dailink number and CPU DAI number based on sdw link adr.
707 * Since some sdw slaves may be aggregated, the CPU DAI number
708 * may be larger than the number of BE dailinks.
709 */
296c789c 710static int get_sdw_dailink_info(struct device *dev, const struct snd_soc_acpi_link_adr *links,
52db12d1
PLB
711 int *sdw_be_num, int *sdw_cpu_dai_num)
712{
713 const struct snd_soc_acpi_link_adr *link;
296c789c 714 int _codec_type = SOF_SDW_CODEC_TYPE_JACK;
52db12d1
PLB
715 bool group_visited[SDW_MAX_GROUPS];
716 bool no_aggregation;
717 int i;
718
719 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
720 *sdw_cpu_dai_num = 0;
721 *sdw_be_num = 0;
722
723 if (!links)
724 return -EINVAL;
725
726 for (i = 0; i < SDW_MAX_GROUPS; i++)
727 group_visited[i] = false;
728
729 for (link = links; link->num_adr; link++) {
730 const struct snd_soc_acpi_endpoint *endpoint;
2e2d287b 731 int codec_index;
52db12d1
PLB
732 int stream;
733 u64 adr;
734
c8db7b50
BL
735 for (i = 0; i < link->num_adr; i++) {
736 adr = link->adr_d[i].adr;
737 codec_index = find_codec_info_part(adr);
738 if (codec_index < 0)
739 return codec_index;
52db12d1 740
c8db7b50
BL
741 if (codec_info_list[codec_index].codec_type < _codec_type)
742 dev_warn(dev,
743 "Unexpected address table ordering. Expected order: jack -> amp -> mic\n");
296c789c 744
c8db7b50 745 _codec_type = codec_info_list[codec_index].codec_type;
296c789c 746
c8db7b50 747 endpoint = link->adr_d[i].endpoints;
52db12d1 748
c8db7b50
BL
749 /* count DAI number for playback and capture */
750 for_each_pcm_streams(stream) {
751 if (!codec_info_list[codec_index].direction[stream])
752 continue;
52db12d1 753
c8db7b50 754 (*sdw_cpu_dai_num)++;
52db12d1 755
c8db7b50
BL
756 /* count BE for each non-aggregated slave or group */
757 if (!endpoint->aggregated || no_aggregation ||
758 !group_visited[endpoint->group_id])
759 (*sdw_be_num)++;
760 }
52db12d1 761
c8db7b50
BL
762 if (endpoint->aggregated)
763 group_visited[endpoint->group_id] = true;
764 }
52db12d1
PLB
765 }
766
767 return 0;
768}
769
3827b7ca
BL
770static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
771 int be_id, char *name, int playback, int capture,
772 struct snd_soc_dai_link_component *cpus, int cpus_num,
773 struct snd_soc_dai_link_component *codecs, int codecs_num,
52db12d1
PLB
774 int (*init)(struct snd_soc_pcm_runtime *rtd),
775 const struct snd_soc_ops *ops)
776{
3827b7ca 777 dev_dbg(dev, "create dai link %s, id %d\n", name, be_id);
52db12d1
PLB
778 dai_links->id = be_id;
779 dai_links->name = name;
780 dai_links->platforms = platform_component;
781 dai_links->num_platforms = ARRAY_SIZE(platform_component);
52db12d1
PLB
782 dai_links->no_pcm = 1;
783 dai_links->cpus = cpus;
784 dai_links->num_cpus = cpus_num;
785 dai_links->codecs = codecs;
786 dai_links->num_codecs = codecs_num;
787 dai_links->dpcm_playback = playback;
788 dai_links->dpcm_capture = capture;
789 dai_links->init = init;
790 dai_links->ops = ops;
791}
792
793static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
794 unsigned int sdw_version,
795 unsigned int mfg_id,
796 unsigned int part_id,
797 unsigned int class_id,
798 int index_in_link
799 )
800{
801 int i;
802
803 for (i = 0; i < link->num_adr; i++) {
804 unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
805 u64 adr;
806
807 /* skip itself */
808 if (i == index_in_link)
809 continue;
810
811 adr = link->adr_d[i].adr;
812
813 sdw1_version = SDW_VERSION(adr);
814 mfg1_id = SDW_MFG_ID(adr);
815 part1_id = SDW_PART_ID(adr);
816 class1_id = SDW_CLASS_ID(adr);
817
818 if (sdw_version == sdw1_version &&
819 mfg_id == mfg1_id &&
820 part_id == part1_id &&
821 class_id == class1_id)
822 return false;
823 }
824
825 return true;
826}
827
828static int create_codec_dai_name(struct device *dev,
829 const struct snd_soc_acpi_link_adr *link,
830 struct snd_soc_dai_link_component *codec,
23c8aa3e
PLB
831 int offset,
832 struct snd_soc_codec_conf *codec_conf,
833 int codec_count,
c8db7b50
BL
834 int *codec_conf_index,
835 int adr_index)
52db12d1 836{
c8db7b50 837 int _codec_index = -1;
52db12d1
PLB
838 int i;
839
23c8aa3e 840 /* sanity check */
c8db7b50 841 if (*codec_conf_index + link->num_adr - adr_index > codec_count) {
23c8aa3e
PLB
842 dev_err(dev, "codec_conf: out-of-bounds access requested\n");
843 return -EINVAL;
844 }
845
c8db7b50 846 for (i = adr_index; i < link->num_adr; i++) {
52db12d1
PLB
847 unsigned int sdw_version, unique_id, mfg_id;
848 unsigned int link_id, part_id, class_id;
849 int codec_index, comp_index;
850 char *codec_str;
851 u64 adr;
852
853 adr = link->adr_d[i].adr;
854
855 sdw_version = SDW_VERSION(adr);
856 link_id = SDW_DISCO_LINK_ID(adr);
857 unique_id = SDW_UNIQUE_ID(adr);
858 mfg_id = SDW_MFG_ID(adr);
859 part_id = SDW_PART_ID(adr);
860 class_id = SDW_CLASS_ID(adr);
861
c8db7b50 862 comp_index = i - adr_index + offset;
52db12d1
PLB
863 if (is_unique_device(link, sdw_version, mfg_id, part_id,
864 class_id, i)) {
9c294739 865 codec_str = "sdw:%01x:%04x:%04x:%02x";
52db12d1
PLB
866 codec[comp_index].name =
867 devm_kasprintf(dev, GFP_KERNEL, codec_str,
868 link_id, mfg_id, part_id,
869 class_id);
870 } else {
9c294739 871 codec_str = "sdw:%01x:%04x:%04x:%02x:%01x";
52db12d1
PLB
872 codec[comp_index].name =
873 devm_kasprintf(dev, GFP_KERNEL, codec_str,
874 link_id, mfg_id, part_id,
875 class_id, unique_id);
876 }
877
878 if (!codec[comp_index].name)
879 return -ENOMEM;
880
2e2d287b 881 codec_index = find_codec_info_part(adr);
52db12d1
PLB
882 if (codec_index < 0)
883 return codec_index;
c8db7b50
BL
884 if (_codec_index != -1 && codec_index != _codec_index) {
885 dev_dbg(dev, "Different devices on the same sdw link\n");
886 break;
887 }
888 _codec_index = codec_index;
52db12d1
PLB
889
890 codec[comp_index].dai_name =
891 codec_info_list[codec_index].dai_name;
23c8aa3e
PLB
892
893 codec_conf[*codec_conf_index].dlc = codec[comp_index];
894 codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
895
896 ++*codec_conf_index;
52db12d1
PLB
897 }
898
899 return 0;
900}
901
cdf99c9a
PLB
902static int set_codec_init_func(struct snd_soc_card *card,
903 const struct snd_soc_acpi_link_adr *link,
52db12d1 904 struct snd_soc_dai_link *dai_links,
5930d02c 905 bool playback, int group_id)
52db12d1
PLB
906{
907 int i;
908
5930d02c
BL
909 do {
910 /*
911 * Initialize the codec. If codec is part of an aggregated
912 * group (group_id>0), initialize all codecs belonging to
913 * same group.
914 */
915 for (i = 0; i < link->num_adr; i++) {
5930d02c 916 int codec_index;
52db12d1 917
2e2d287b 918 codec_index = find_codec_info_part(link->adr_d[i].adr);
52db12d1 919
5930d02c
BL
920 if (codec_index < 0)
921 return codec_index;
922 /* The group_id is > 0 iff the codec is aggregated */
923 if (link->adr_d[i].endpoints->group_id != group_id)
924 continue;
925 if (codec_info_list[codec_index].init)
cdf99c9a
PLB
926 codec_info_list[codec_index].init(card,
927 link,
5930d02c
BL
928 dai_links,
929 &codec_info_list[codec_index],
930 playback);
931 }
932 link++;
933 } while (link->mask && group_id);
52db12d1
PLB
934
935 return 0;
936}
937
938/*
939 * check endpoint status in slaves and gather link ID for all slaves in
940 * the same group to generate different CPU DAI. Now only support
941 * one sdw link with all slaves set with only single group id.
942 *
943 * one slave on one sdw link with aggregated = 0
944 * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI
945 *
946 * two or more slaves on one sdw link with aggregated = 0
947 * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs
948 *
949 * multiple links with multiple slaves with aggregated = 1
950 * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs
951 */
952static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
953 struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
0a1f3958 954 int *codec_num, unsigned int *group_id,
c8db7b50 955 bool *group_generated, int adr_index)
52db12d1
PLB
956{
957 const struct snd_soc_acpi_adr_device *adr_d;
958 const struct snd_soc_acpi_link_adr *adr_next;
959 bool no_aggregation;
960 int index = 0;
c8db7b50 961 int i;
52db12d1
PLB
962
963 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
c8db7b50 964 adr_d = &adr_link->adr_d[adr_index];
52db12d1
PLB
965
966 /* make sure the link mask has a single bit set */
967 if (!is_power_of_2(adr_link->mask))
968 return -EINVAL;
969
970 cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
971 if (!adr_d->endpoints->aggregated || no_aggregation) {
972 *cpu_dai_num = 1;
16373f30 973 *codec_num = 1;
52db12d1
PLB
974 *group_id = 0;
975 return 0;
976 }
977
978 *group_id = adr_d->endpoints->group_id;
979
c8db7b50
BL
980 /* Count endpoints with the same group_id in the adr_link */
981 *codec_num = 0;
982 for (i = 0; i < adr_link->num_adr; i++) {
983 if (adr_link->adr_d[i].endpoints->aggregated &&
984 adr_link->adr_d[i].endpoints->group_id == *group_id)
985 (*codec_num)++;
986 }
987
52db12d1
PLB
988 /* gather other link ID of slaves in the same group */
989 for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
990 adr_next++) {
991 const struct snd_soc_acpi_endpoint *endpoint;
992
993 endpoint = adr_next->adr_d->endpoints;
994 if (!endpoint->aggregated ||
995 endpoint->group_id != *group_id)
996 continue;
997
998 /* make sure the link mask has a single bit set */
999 if (!is_power_of_2(adr_next->mask))
1000 return -EINVAL;
1001
1002 if (index >= SDW_MAX_CPU_DAIS) {
1003 dev_err(dev, " cpu_dai_id array overflows");
1004 return -EINVAL;
1005 }
1006
1007 cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
c8db7b50
BL
1008 for (i = 0; i < adr_next->num_adr; i++) {
1009 if (adr_next->adr_d[i].endpoints->aggregated &&
1010 adr_next->adr_d[i].endpoints->group_id == *group_id)
1011 (*codec_num)++;
1012 }
52db12d1
PLB
1013 }
1014
1015 /*
1016 * indicate CPU DAIs for this group have been generated
1017 * to avoid generating CPU DAIs for this group again.
1018 */
1019 group_generated[*group_id] = true;
1020 *cpu_dai_num = index;
1021
1022 return 0;
1023}
1024
dc5a3e60
BL
1025static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"};
1026
cdf99c9a 1027static int create_sdw_dailink(struct snd_soc_card *card,
b63137cf 1028 struct device *dev, int *link_index,
52db12d1
PLB
1029 struct snd_soc_dai_link *dai_links,
1030 int sdw_be_num, int sdw_cpu_dai_num,
1031 struct snd_soc_dai_link_component *cpus,
1032 const struct snd_soc_acpi_link_adr *link,
23c8aa3e
PLB
1033 int *cpu_id, bool *group_generated,
1034 struct snd_soc_codec_conf *codec_conf,
d471c034 1035 int codec_count, int *link_id,
35564e2b 1036 int *codec_conf_index,
c8db7b50 1037 bool *ignore_pch_dmic,
dc5a3e60 1038 bool append_codec_type,
c8db7b50 1039 int adr_index)
52db12d1
PLB
1040{
1041 const struct snd_soc_acpi_link_adr *link_next;
1042 struct snd_soc_dai_link_component *codecs;
1043 int cpu_dai_id[SDW_MAX_CPU_DAIS];
1044 int cpu_dai_num, cpu_dai_index;
2e2d287b 1045 unsigned int group_id;
52db12d1
PLB
1046 int codec_idx = 0;
1047 int i = 0, j = 0;
1048 int codec_index;
1049 int codec_num;
1050 int stream;
1051 int ret;
1052 int k;
1053
1054 ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
c8db7b50 1055 &group_id, group_generated, adr_index);
52db12d1
PLB
1056 if (ret)
1057 return ret;
1058
1059 codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
1060 if (!codecs)
1061 return -ENOMEM;
1062
1063 /* generate codec name on different links in the same group */
1064 for (link_next = link; link_next && link_next->num_adr &&
1065 i < cpu_dai_num; link_next++) {
1066 const struct snd_soc_acpi_endpoint *endpoints;
1067
1068 endpoints = link_next->adr_d->endpoints;
1069 if (group_id && (!endpoints->aggregated ||
1070 endpoints->group_id != group_id))
1071 continue;
1072
1073 /* skip the link excluded by this processed group */
1074 if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
1075 continue;
1076
23c8aa3e 1077 ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
c8db7b50 1078 codec_conf, codec_count, codec_conf_index, adr_index);
52db12d1
PLB
1079 if (ret < 0)
1080 return ret;
1081
1082 /* check next link to create codec dai in the processed group */
1083 i++;
1084 codec_idx += link_next->num_adr;
1085 }
1086
1087 /* find codec info to create BE DAI */
c8db7b50 1088 codec_index = find_codec_info_part(link->adr_d[adr_index].adr);
52db12d1
PLB
1089 if (codec_index < 0)
1090 return codec_index;
1091
35564e2b
PLB
1092 if (codec_info_list[codec_index].ignore_pch_dmic)
1093 *ignore_pch_dmic = true;
1094
d471c034
BL
1095 /* Shift the first amplifier's *link_id to SDW_AMP_DAI_ID */
1096 if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_AMP &&
1097 *link_id < SDW_AMP_DAI_ID)
1098 *link_id = SDW_AMP_DAI_ID;
1099
bf605cb0
BL
1100 /*
1101 * DAI ID is fixed at SDW_DMIC_DAI_ID for MICs to
1102 * keep sdw DMIC and HDMI setting static in UCM
1103 */
1104 if (codec_info_list[codec_index].codec_type == SOF_SDW_CODEC_TYPE_MIC &&
1105 *link_id < SDW_DMIC_DAI_ID)
1106 *link_id = SDW_DMIC_DAI_ID;
1107
52db12d1
PLB
1108 cpu_dai_index = *cpu_id;
1109 for_each_pcm_streams(stream) {
1110 char *name, *cpu_name;
1111 int playback, capture;
1112 static const char * const sdw_stream_name[] = {
1113 "SDW%d-Playback",
1114 "SDW%d-Capture",
dc5a3e60
BL
1115 "SDW%d-Playback-%s",
1116 "SDW%d-Capture-%s",
52db12d1
PLB
1117 };
1118
1119 if (!codec_info_list[codec_index].direction[stream])
1120 continue;
1121
1122 /* create stream name according to first link id */
dc5a3e60
BL
1123 if (append_codec_type) {
1124 name = devm_kasprintf(dev, GFP_KERNEL,
1125 sdw_stream_name[stream + 2], cpu_dai_id[0],
1126 type_strings[codec_info_list[codec_index].codec_type]);
1127 } else {
1128 name = devm_kasprintf(dev, GFP_KERNEL,
1129 sdw_stream_name[stream], cpu_dai_id[0]);
1130 }
52db12d1
PLB
1131 if (!name)
1132 return -ENOMEM;
1133
1134 /*
1135 * generate CPU DAI name base on the sdw link ID and
1136 * PIN ID with offset of 2 according to sdw dai driver.
1137 */
1138 for (k = 0; k < cpu_dai_num; k++) {
1139 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1140 "SDW%d Pin%d", cpu_dai_id[k],
1141 j + SDW_INTEL_BIDIR_PDI_BASE);
1142 if (!cpu_name)
1143 return -ENOMEM;
1144
1145 if (cpu_dai_index >= sdw_cpu_dai_num) {
1146 dev_err(dev, "invalid cpu dai index %d",
1147 cpu_dai_index);
1148 return -EINVAL;
1149 }
1150
1151 cpus[cpu_dai_index++].dai_name = cpu_name;
1152 }
1153
b63137cf
BL
1154 /*
1155 * We create sdw dai links at first stage, so link index should
1156 * not be larger than sdw_be_num
1157 */
1158 if (*link_index >= sdw_be_num) {
1159 dev_err(dev, "invalid dai link index %d", *link_index);
52db12d1
PLB
1160 return -EINVAL;
1161 }
1162
1163 if (*cpu_id >= sdw_cpu_dai_num) {
1164 dev_err(dev, " invalid cpu dai index %d", *cpu_id);
1165 return -EINVAL;
1166 }
1167
1168 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
1169 capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
d471c034 1170 init_dai_link(dev, dai_links + *link_index, (*link_id)++, name,
52db12d1
PLB
1171 playback, capture,
1172 cpus + *cpu_id, cpu_dai_num,
1173 codecs, codec_num,
1174 NULL, &sdw_ops);
b63137cf 1175
58eafe1f
PLB
1176 /*
1177 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
1178 * based on wait_for_completion(), tag them as 'nonatomic'.
1179 */
b63137cf 1180 dai_links[*link_index].nonatomic = true;
52db12d1 1181
b63137cf 1182 ret = set_codec_init_func(card, link, dai_links + (*link_index)++,
5930d02c 1183 playback, group_id);
52db12d1
PLB
1184 if (ret < 0) {
1185 dev_err(dev, "failed to init codec %d", codec_index);
1186 return ret;
1187 }
1188
1189 *cpu_id += cpu_dai_num;
1190 j++;
1191 }
1192
1193 return 0;
1194}
1195
15ef2ea0
KV
1196#define IDISP_CODEC_MASK 0x4
1197
23c8aa3e
PLB
1198static int sof_card_codec_conf_alloc(struct device *dev,
1199 struct snd_soc_acpi_mach_params *mach_params,
1200 struct snd_soc_codec_conf **codec_conf,
1201 int *codec_conf_count)
1202{
1203 const struct snd_soc_acpi_link_adr *adr_link;
1204 struct snd_soc_codec_conf *c_conf;
1205 int num_codecs = 0;
1206 int i;
1207
1208 adr_link = mach_params->links;
1209 if (!adr_link)
1210 return -EINVAL;
1211
1212 /* generate DAI links by each sdw link */
1213 for (; adr_link->num_adr; adr_link++) {
1214 for (i = 0; i < adr_link->num_adr; i++) {
1215 if (!adr_link->adr_d[i].name_prefix) {
1216 dev_err(dev, "codec 0x%llx does not have a name prefix\n",
1217 adr_link->adr_d[i].adr);
1218 return -EINVAL;
1219 }
1220 }
1221 num_codecs += adr_link->num_adr;
1222 }
1223
1224 c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
1225 if (!c_conf)
1226 return -ENOMEM;
1227
1228 *codec_conf = c_conf;
1229 *codec_conf_count = num_codecs;
1230
1231 return 0;
1232}
1233
52db12d1
PLB
1234static int sof_card_dai_links_create(struct device *dev,
1235 struct snd_soc_acpi_mach *mach,
1236 struct snd_soc_card *card)
1237{
1238 int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
15ef2ea0 1239 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
52db12d1 1240 struct snd_soc_dai_link_component *idisp_components;
52db12d1
PLB
1241 struct snd_soc_dai_link_component *ssp_components;
1242 struct snd_soc_acpi_mach_params *mach_params;
1243 const struct snd_soc_acpi_link_adr *adr_link;
1244 struct snd_soc_dai_link_component *cpus;
23c8aa3e 1245 struct snd_soc_codec_conf *codec_conf;
dc5a3e60 1246 bool append_codec_type = false;
35564e2b 1247 bool ignore_pch_dmic = false;
23c8aa3e
PLB
1248 int codec_conf_count;
1249 int codec_conf_index = 0;
52db12d1
PLB
1250 bool group_generated[SDW_MAX_GROUPS];
1251 int ssp_codec_index, ssp_mask;
1252 struct snd_soc_dai_link *links;
b63137cf 1253 int num_links, link_index = 0;
52db12d1
PLB
1254 char *name, *cpu_name;
1255 int total_cpu_dai_num;
1256 int sdw_cpu_dai_num;
1257 int i, j, be_id = 0;
1258 int cpu_id = 0;
1259 int comp_num;
1260 int ret;
1261
23c8aa3e
PLB
1262 mach_params = &mach->mach_params;
1263
1264 /* allocate codec conf, will be populated when dailinks are created */
1265 ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
1266 if (ret < 0)
1267 return ret;
1268
52db12d1
PLB
1269 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
1270 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1271 codec_info_list[i].amp_num = 0;
1272
8208dd75
PLB
1273 if (mach_params->codec_mask & IDISP_CODEC_MASK) {
1274 ctx->idisp_codec = true;
1275
1276 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
1277 hdmi_num = SOF_TGL_HDMI_COUNT;
1278 else
1279 hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
1280 }
52db12d1
PLB
1281
1282 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
1283 /*
1284 * on generic tgl platform, I2S or sdw mode is supported
1285 * based on board rework. A ACPI device is registered in
1286 * system only when I2S mode is supported, not sdw mode.
1287 * Here check ACPI ID to confirm I2S is supported.
1288 */
1289 ssp_codec_index = find_codec_info_acpi(mach->id);
1290 ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
1291 comp_num = hdmi_num + ssp_num;
1292
296c789c 1293 ret = get_sdw_dailink_info(dev, mach_params->links,
52db12d1
PLB
1294 &sdw_be_num, &sdw_cpu_dai_num);
1295 if (ret < 0) {
1296 dev_err(dev, "failed to get sdw link info %d", ret);
1297 return ret;
1298 }
1299
1300 /* enable dmic01 & dmic16k */
f88dcb9b 1301 dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
52db12d1
PLB
1302 comp_num += dmic_num;
1303
19f1eace
YZ
1304 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT)
1305 comp_num++;
1306
52db12d1 1307 dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
15ef2ea0 1308 dmic_num, ctx->idisp_codec ? hdmi_num : 0);
52db12d1
PLB
1309
1310 /* allocate BE dailinks */
1311 num_links = comp_num + sdw_be_num;
1312 links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
1313
1314 /* allocated CPU DAIs */
1315 total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
1316 cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
1317 GFP_KERNEL);
1318
1319 if (!links || !cpus)
1320 return -ENOMEM;
1321
1322 /* SDW */
1323 if (!sdw_be_num)
1324 goto SSP;
1325
1326 adr_link = mach_params->links;
1327 if (!adr_link)
1328 return -EINVAL;
1329
1330 /*
1331 * SoundWire Slaves aggregated in the same group may be
1332 * located on different hardware links. Clear array to indicate
1333 * CPU DAIs for this group have not been generated.
1334 */
1335 for (i = 0; i < SDW_MAX_GROUPS; i++)
1336 group_generated[i] = false;
1337
52db12d1 1338 for (; adr_link->num_adr; adr_link++) {
dc5a3e60
BL
1339 /*
1340 * If there are two or more different devices on the same sdw link, we have to
1341 * append the codec type to the dai link name to prevent duplicated dai link name.
1342 * The same type devices on the same sdw link will be in the same
1343 * snd_soc_acpi_adr_device array. They won't be described in different adr_links.
1344 */
1345 for (i = 0; i < adr_link->num_adr; i++) {
1346 for (j = 0; j < i; j++) {
1347 if ((SDW_PART_ID(adr_link->adr_d[i].adr) !=
1348 SDW_PART_ID(adr_link->adr_d[j].adr)) ||
1349 (SDW_MFG_ID(adr_link->adr_d[i].adr) !=
1350 SDW_MFG_ID(adr_link->adr_d[i].adr))) {
1351 append_codec_type = true;
1352 goto out;
1353 }
1354 }
1355 }
1356 }
1357out:
1358
1359 /* generate DAI links by each sdw link */
1360 for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) {
c8db7b50
BL
1361 for (i = 0; i < adr_link->num_adr; i++) {
1362 const struct snd_soc_acpi_endpoint *endpoint;
52db12d1 1363
c8db7b50
BL
1364 endpoint = adr_link->adr_d[i].endpoints;
1365 if (endpoint->aggregated && !endpoint->group_id) {
1366 dev_err(dev, "invalid group id on link %x",
1367 adr_link->mask);
1368 continue;
1369 }
52db12d1 1370
c8db7b50
BL
1371 /* this group has been generated */
1372 if (endpoint->aggregated &&
1373 group_generated[endpoint->group_id])
1374 continue;
52db12d1 1375
c8db7b50
BL
1376 ret = create_sdw_dailink(card, dev, &link_index, links, sdw_be_num,
1377 sdw_cpu_dai_num, cpus, adr_link,
1378 &cpu_id, group_generated,
1379 codec_conf, codec_conf_count,
1380 &be_id, &codec_conf_index,
dc5a3e60 1381 &ignore_pch_dmic, append_codec_type, i);
c8db7b50
BL
1382 if (ret < 0) {
1383 dev_err(dev, "failed to create dai link %d", link_index);
1384 return ret;
1385 }
52db12d1
PLB
1386 }
1387 }
1388
52db12d1
PLB
1389SSP:
1390 /* SSP */
1391 if (!ssp_num)
1392 goto DMIC;
1393
1394 for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
1395 struct sof_sdw_codec_info *info;
1396 int playback, capture;
1397 char *codec_name;
1398
1399 if (!(ssp_mask & 0x1))
1400 continue;
1401
1402 name = devm_kasprintf(dev, GFP_KERNEL,
1403 "SSP%d-Codec", i);
1404 if (!name)
1405 return -ENOMEM;
1406
1407 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1408 if (!cpu_name)
1409 return -ENOMEM;
1410
1411 ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
1412 GFP_KERNEL);
1413 if (!ssp_components)
1414 return -ENOMEM;
1415
1416 info = &codec_info_list[ssp_codec_index];
1417 codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1418 info->acpi_id, j++);
1419 if (!codec_name)
1420 return -ENOMEM;
1421
1422 ssp_components->name = codec_name;
1423 ssp_components->dai_name = info->dai_name;
1424 cpus[cpu_id].dai_name = cpu_name;
1425
1426 playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK];
1427 capture = info->direction[SNDRV_PCM_STREAM_CAPTURE];
b63137cf 1428 init_dai_link(dev, links + link_index, be_id, name,
52db12d1
PLB
1429 playback, capture,
1430 cpus + cpu_id, 1,
1431 ssp_components, 1,
1432 NULL, info->ops);
1433
b63137cf 1434 ret = info->init(card, NULL, links + link_index, info, 0);
52db12d1
PLB
1435 if (ret < 0)
1436 return ret;
1437
b63137cf 1438 INC_ID(be_id, cpu_id, link_index);
52db12d1
PLB
1439 }
1440
1441DMIC:
1442 /* dmic */
1443 if (dmic_num > 0) {
35564e2b
PLB
1444 if (ignore_pch_dmic) {
1445 dev_warn(dev, "Ignoring PCH DMIC\n");
1446 goto HDMI;
1447 }
52db12d1 1448 cpus[cpu_id].dai_name = "DMIC01 Pin";
b63137cf 1449 init_dai_link(dev, links + link_index, be_id, "dmic01",
52db12d1
PLB
1450 0, 1, // DMIC only supports capture
1451 cpus + cpu_id, 1,
1452 dmic_component, 1,
1453 sof_sdw_dmic_init, NULL);
b63137cf 1454 INC_ID(be_id, cpu_id, link_index);
52db12d1
PLB
1455
1456 cpus[cpu_id].dai_name = "DMIC16k Pin";
b63137cf 1457 init_dai_link(dev, links + link_index, be_id, "dmic16k",
52db12d1
PLB
1458 0, 1, // DMIC only supports capture
1459 cpus + cpu_id, 1,
1460 dmic_component, 1,
1461 /* don't call sof_sdw_dmic_init() twice */
1462 NULL, NULL);
b63137cf 1463 INC_ID(be_id, cpu_id, link_index);
52db12d1
PLB
1464 }
1465
35564e2b 1466HDMI:
52db12d1
PLB
1467 /* HDMI */
1468 if (hdmi_num > 0) {
1469 idisp_components = devm_kcalloc(dev, hdmi_num,
1470 sizeof(*idisp_components),
1471 GFP_KERNEL);
1472 if (!idisp_components)
1473 return -ENOMEM;
1474 }
1475
1476 for (i = 0; i < hdmi_num; i++) {
1477 name = devm_kasprintf(dev, GFP_KERNEL,
1478 "iDisp%d", i + 1);
1479 if (!name)
1480 return -ENOMEM;
1481
15ef2ea0
KV
1482 if (ctx->idisp_codec) {
1483 idisp_components[i].name = "ehdaudio0D2";
1484 idisp_components[i].dai_name = devm_kasprintf(dev,
1485 GFP_KERNEL,
1486 "intel-hdmi-hifi%d",
1487 i + 1);
1488 if (!idisp_components[i].dai_name)
1489 return -ENOMEM;
1490 } else {
1491 idisp_components[i].name = "snd-soc-dummy";
1492 idisp_components[i].dai_name = "snd-soc-dummy-dai";
1493 }
52db12d1
PLB
1494
1495 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1496 "iDisp%d Pin", i + 1);
1497 if (!cpu_name)
1498 return -ENOMEM;
1499
1500 cpus[cpu_id].dai_name = cpu_name;
b63137cf 1501 init_dai_link(dev, links + link_index, be_id, name,
52db12d1
PLB
1502 1, 0, // HDMI only supports playback
1503 cpus + cpu_id, 1,
1504 idisp_components + i, 1,
1505 sof_sdw_hdmi_init, NULL);
b63137cf 1506 INC_ID(be_id, cpu_id, link_index);
52db12d1 1507 }
52db12d1 1508
19f1eace
YZ
1509 if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) {
1510 int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >>
1511 SOF_BT_OFFLOAD_SSP_SHIFT;
1512
1513 name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port);
1514 if (!name)
1515 return -ENOMEM;
1516
1517 ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
1518 GFP_KERNEL);
1519 if (!ssp_components)
1520 return -ENOMEM;
1521
1522 ssp_components->name = "snd-soc-dummy";
1523 ssp_components->dai_name = "snd-soc-dummy-dai";
1524
1525 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port);
1526 if (!cpu_name)
1527 return -ENOMEM;
1528
1529 cpus[cpu_id].dai_name = cpu_name;
b63137cf 1530 init_dai_link(dev, links + link_index, be_id, name, 1, 1,
19f1eace
YZ
1531 cpus + cpu_id, 1, ssp_components, 1, NULL, NULL);
1532 }
1533
52db12d1
PLB
1534 card->dai_link = links;
1535 card->num_links = num_links;
1536
23c8aa3e
PLB
1537 card->codec_conf = codec_conf;
1538 card->num_configs = codec_conf_count;
1539
52db12d1
PLB
1540 return 0;
1541}
1542
be3afa12 1543static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1544{
8208dd75
PLB
1545 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
1546 int ret = 0;
1547 int i;
be3afa12 1548
1549 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
06b830bd
YZ
1550 if (codec_info_list[i].codec_card_late_probe) {
1551 ret = codec_info_list[i].codec_card_late_probe(card);
be3afa12 1552
06b830bd
YZ
1553 if (ret < 0)
1554 return ret;
1555 }
be3afa12 1556 }
1557
8208dd75
PLB
1558 if (ctx->idisp_codec)
1559 ret = sof_sdw_hdmi_card_late_probe(card);
1560
1561 return ret;
be3afa12 1562}
1563
52db12d1
PLB
1564/* SoC card */
1565static const char sdw_card_long_name[] = "Intel Soundwire SOF";
1566
1567static struct snd_soc_card card_sof_sdw = {
1568 .name = "soundwire",
fb4b42f6 1569 .owner = THIS_MODULE,
be3afa12 1570 .late_probe = sof_sdw_card_late_probe,
52db12d1
PLB
1571};
1572
768ad6d8
PLB
1573static void mc_dailink_exit_loop(struct snd_soc_card *card)
1574{
1575 struct snd_soc_dai_link *link;
1576 int ret;
1577 int i, j;
1578
1579 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1580 if (!codec_info_list[i].exit)
1581 continue;
1582 /*
1583 * We don't need to call .exit function if there is no matched
1584 * dai link found.
1585 */
1586 for_each_card_prelinks(card, j, link) {
1587 if (!strcmp(link->codecs[0].dai_name,
1588 codec_info_list[i].dai_name)) {
1589 ret = codec_info_list[i].exit(card, link);
1590 if (ret)
1591 dev_warn(card->dev,
1592 "codec exit failed %d\n",
1593 ret);
1594 break;
1595 }
1596 }
1597 }
1598}
1599
52db12d1
PLB
1600static int mc_probe(struct platform_device *pdev)
1601{
1602 struct snd_soc_card *card = &card_sof_sdw;
1603 struct snd_soc_acpi_mach *mach;
1604 struct mc_private *ctx;
b1ca2f63 1605 int amp_num = 0, i;
52db12d1
PLB
1606 int ret;
1607
d2d19cb6 1608 dev_dbg(&pdev->dev, "Entry\n");
52db12d1
PLB
1609
1610 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1611 if (!ctx)
1612 return -ENOMEM;
1613
1614 dmi_check_system(sof_sdw_quirk_table);
1615
2555ebe9
PLB
1616 if (quirk_override != -1) {
1617 dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
1618 sof_sdw_quirk, quirk_override);
1619 sof_sdw_quirk = quirk_override;
1620 }
1621 log_quirks(&pdev->dev);
1622
52db12d1 1623 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
52db12d1
PLB
1624
1625 card->dev = &pdev->dev;
15ef2ea0 1626 snd_soc_card_set_drvdata(card, ctx);
52db12d1
PLB
1627
1628 mach = pdev->dev.platform_data;
1629 ret = sof_card_dai_links_create(&pdev->dev, mach,
1630 card);
1631 if (ret < 0)
1632 return ret;
1633
b1ca2f63 1634 /*
1635 * the default amp_num is zero for each codec and
1636 * amp_num will only be increased for active amp
1637 * codecs on used platform
1638 */
1639 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1640 amp_num += codec_info_list[i].amp_num;
1641
52db12d1 1642 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
9d05a1e5 1643 "cfg-spk:%d cfg-amp:%d",
b1ca2f63 1644 (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
1645 ? 4 : 2, amp_num);
52db12d1
PLB
1646 if (!card->components)
1647 return -ENOMEM;
1648
209b0b0d
PLB
1649 if (mach->mach_params.dmic_num) {
1650 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1651 "%s mic:dmic cfg-mics:%d",
1652 card->components,
1653 mach->mach_params.dmic_num);
1654 if (!card->components)
1655 return -ENOMEM;
1656 }
1657
52db12d1
PLB
1658 card->long_name = sdw_card_long_name;
1659
1660 /* Register the card */
1661 ret = devm_snd_soc_register_card(&pdev->dev, card);
1662 if (ret) {
1663 dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
768ad6d8 1664 mc_dailink_exit_loop(card);
52db12d1
PLB
1665 return ret;
1666 }
1667
1668 platform_set_drvdata(pdev, card);
1669
1670 return ret;
1671}
1672
51a4a7ec 1673static void mc_remove(struct platform_device *pdev)
75136503
BL
1674{
1675 struct snd_soc_card *card = platform_get_drvdata(pdev);
75136503 1676
768ad6d8 1677 mc_dailink_exit_loop(card);
75136503
BL
1678}
1679
52db12d1
PLB
1680static struct platform_driver sof_sdw_driver = {
1681 .driver = {
1682 .name = "sof_sdw",
1683 .pm = &snd_soc_pm_ops,
1684 },
1685 .probe = mc_probe,
51a4a7ec 1686 .remove_new = mc_remove,
52db12d1
PLB
1687};
1688
1689module_platform_driver(sof_sdw_driver);
1690
1691MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1692MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1693MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1694MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1695MODULE_LICENSE("GPL v2");
1696MODULE_ALIAS("platform:sof_sdw");
f6081af6 1697MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
9c5046e4 1698MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON);