1 // SPDX-License-Identifier: GPL-2.0-only
2 // This file incorporates work covered by the following copyright notice:
3 // Copyright (c) 2020 Intel Corporation
4 // Copyright(c) 2024 Advanced Micro Devices, Inc.
5 /*
6 * soc-sdw-utils.c - common SoundWire machine driver helper functions
7 */
8
9 #include <linux/device.h>
10 #include <linux/module.h>
11 #include <linux/soundwire/sdw.h>
12 #include <linux/soundwire/sdw_type.h>
13 #include <sound/sdca_function.h>
14 #include <sound/soc_sdw_utils.h>
15
16 static const struct snd_soc_dapm_widget generic_dmic_widgets[] = {
17 SND_SOC_DAPM_MIC("DMIC", NULL),
18 };
19
20 static const struct snd_soc_dapm_widget generic_jack_widgets[] = {
21 SND_SOC_DAPM_HP("Headphone", NULL),
22 SND_SOC_DAPM_MIC("Headset Mic", NULL),
23 };
24
25 static const struct snd_kcontrol_new generic_jack_controls[] = {
26 SOC_DAPM_PIN_SWITCH("Headphone"),
27 SOC_DAPM_PIN_SWITCH("Headset Mic"),
28 };
29
30 static const struct snd_soc_dapm_widget generic_spk_widgets[] = {
31 SND_SOC_DAPM_SPK("Speaker", NULL),
32 };
33
34 static const struct snd_kcontrol_new generic_spk_controls[] = {
35 SOC_DAPM_PIN_SWITCH("Speaker"),
36 };
37
38 static const struct snd_soc_dapm_widget lr_spk_widgets[] = {
39 SND_SOC_DAPM_SPK("Left Spk", NULL),
40 SND_SOC_DAPM_SPK("Right Spk", NULL),
41 };
42
43 static const struct snd_soc_dapm_widget lr_4spk_widgets[] = {
44 SND_SOC_DAPM_SPK("Left Spk", NULL),
45 SND_SOC_DAPM_SPK("Right Spk", NULL),
46 SND_SOC_DAPM_SPK("Left Spk2", NULL),
47 SND_SOC_DAPM_SPK("Right Spk2", NULL),
48 };
49
50 static const struct snd_kcontrol_new lr_spk_controls[] = {
51 SOC_DAPM_PIN_SWITCH("Left Spk"),
52 SOC_DAPM_PIN_SWITCH("Right Spk"),
53 };
54
55 static const struct snd_kcontrol_new lr_4spk_controls[] = {
56 SOC_DAPM_PIN_SWITCH("Left Spk"),
57 SOC_DAPM_PIN_SWITCH("Right Spk"),
58 SOC_DAPM_PIN_SWITCH("Left Spk2"),
59 SOC_DAPM_PIN_SWITCH("Right Spk2"),
60 };
61
62 static const struct snd_soc_dapm_widget rt700_widgets[] = {
63 SND_SOC_DAPM_HP("Headphones", NULL),
64 SND_SOC_DAPM_MIC("AMIC", NULL),
65 SND_SOC_DAPM_SPK("Speaker", NULL),
66 };
67
68 static const struct snd_kcontrol_new rt700_controls[] = {
69 SOC_DAPM_PIN_SWITCH("Headphones"),
70 SOC_DAPM_PIN_SWITCH("AMIC"),
71 SOC_DAPM_PIN_SWITCH("Speaker"),
72 };
73
74 struct asoc_sdw_codec_info codec_info_list[] = {
75 {
76 .vendor_id = 0x0102,
77 .part_id = 0x5572,
78 .name_prefix = "tac5572",
79 .dais = {
80 {
81 /* speaker */
82 .direction = {true, false},
83 .dai_name = "tac5xx2-aif1",
84 .component_name = "tac5572",
85 .dai_type = SOC_SDW_DAI_TYPE_AMP,
86 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
87 .init = asoc_sdw_ti_amp_init,
88 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init,
89 .controls = lr_spk_controls,
90 .num_controls = ARRAY_SIZE(lr_spk_controls),
91 .widgets = lr_spk_widgets,
92 .num_widgets = ARRAY_SIZE(lr_spk_widgets),
93 },
94 {
95 /* mic */
96 .direction = {false, true},
97 .dai_name = "tac5xx2-aif2",
98 .component_name = "tac5572",
99 .dai_type = SOC_SDW_DAI_TYPE_MIC,
100 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
101 .rtd_init = asoc_sdw_ti_dmic_rtd_init,
102 },
103 {
104 /* UAJ */
105 .direction = {true, true},
106 .dai_name = "tac5xx2-aif3",
107 .component_name = "tac5572",
108 .dai_type = SOC_SDW_DAI_TYPE_JACK,
109 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
110 .controls = generic_jack_controls,
111 .num_controls = ARRAY_SIZE(generic_jack_controls),
112 .widgets = generic_jack_widgets,
113 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
114 .rtd_init = asoc_sdw_ti_sdca_jack_rtd_init,
115 },
116 },
117 .dai_num = 3,
118 },
119 {
120 .vendor_id = 0x0102,
121 .part_id = 0x5672,
122 .name_prefix = "tac5672",
123 .dais = {
124 {
125 /* speaker with IV sense feedback */
126 .direction = {true, true},
127 .dai_name = "tac5xx2-aif1",
128 .component_name = "tac5672",
129 .dai_type = SOC_SDW_DAI_TYPE_AMP,
130 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
131 .init = asoc_sdw_ti_amp_init,
132 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init,
133 .controls = lr_spk_controls,
134 .num_controls = ARRAY_SIZE(lr_spk_controls),
135 .widgets = lr_spk_widgets,
136 .num_widgets = ARRAY_SIZE(lr_spk_widgets),
137 },
138 {
139 /* mic */
140 .direction = {false, true},
141 .dai_name = "tac5xx2-aif2",
142 .component_name = "tac5672",
143 .dai_type = SOC_SDW_DAI_TYPE_MIC,
144 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
145 .rtd_init = asoc_sdw_ti_dmic_rtd_init,
146 },
147 {
148 /* UAJ */
149 .direction = {true, true},
150 .dai_name = "tac5xx2-aif3",
151 .component_name = "tac5672",
152 .dai_type = SOC_SDW_DAI_TYPE_JACK,
153 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
154 .controls = generic_jack_controls,
155 .num_controls = ARRAY_SIZE(generic_jack_controls),
156 .widgets = generic_jack_widgets,
157 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
158 .rtd_init = asoc_sdw_ti_sdca_jack_rtd_init,
159 },
160 },
161 .dai_num = 3,
162 },
163 {
164 .vendor_id = 0x0102,
165 .part_id = 0x5682,
166 .name_prefix = "tac5682",
167 .dais = {
168 {
169 /* speaker with echo reference feedback */
170 .direction = {true, true},
171 .dai_name = "tac5xx2-aif1",
172 .component_name = "tac5682",
173 .dai_type = SOC_SDW_DAI_TYPE_AMP,
174 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
175 .init = asoc_sdw_ti_amp_init,
176 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init,
177 .controls = lr_spk_controls,
178 .num_controls = ARRAY_SIZE(lr_spk_controls),
179 .widgets = lr_spk_widgets,
180 .num_widgets = ARRAY_SIZE(lr_spk_widgets),
181 },
182 {
183 /* mic */
184 .direction = {false, true},
185 .dai_name = "tac5xx2-aif2",
186 .component_name = "tac5682",
187 .dai_type = SOC_SDW_DAI_TYPE_MIC,
188 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
189 .rtd_init = asoc_sdw_ti_dmic_rtd_init,
190 },
191 {
192 /* UAJ */
193 .direction = {true, true},
194 .dai_name = "tac5xx2-aif3",
195 .component_name = "tac5682",
196 .dai_type = SOC_SDW_DAI_TYPE_JACK,
197 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
198 .controls = generic_jack_controls,
199 .num_controls = ARRAY_SIZE(generic_jack_controls),
200 .widgets = generic_jack_widgets,
201 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
202 .rtd_init = asoc_sdw_ti_sdca_jack_rtd_init,
203 },
204 },
205 .dai_num = 3,
206 },
207 {
208 .vendor_id = 0x0102,
209 .part_id = 0x2883,
210 .name_prefix = "tas2883",
211 .dais = {
212 {
213 .direction = {true, false},
214 .dai_name = "tac5xx2-aif1",
215 .component_name = "tas2883",
216 .dai_type = SOC_SDW_DAI_TYPE_AMP,
217 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
218 .init = asoc_sdw_ti_amp_init,
219 .rtd_init = asoc_sdw_ti_tac5xx2_spk_rtd_init,
220 .controls = lr_spk_controls,
221 .num_controls = ARRAY_SIZE(lr_spk_controls),
222 .widgets = lr_spk_widgets,
223 .num_widgets = ARRAY_SIZE(lr_spk_widgets),
224 },
225 {
226 /* mic */
227 .direction = {false, true},
228 .dai_name = "tac5xx2-aif2",
229 .component_name = "tas2883",
230 .dai_type = SOC_SDW_DAI_TYPE_MIC,
231 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
232 .rtd_init = asoc_sdw_ti_dmic_rtd_init,
233 },
234 },
235 .dai_num = 2,
236 },
237 {
238 .vendor_id = 0x0102,
239 .part_id = 0x0000, /* TAS2783A */
240 .name_prefix = "tas2783",
241 .is_amp = true,
242 .dais = {
243 {
244 .direction = {true, true},
245 .dai_name = "tas2783-codec",
246 .component_name = "tas2783",
247 .dai_type = SOC_SDW_DAI_TYPE_AMP,
248 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
249 .init = asoc_sdw_ti_amp_init,
250 .rtd_init = asoc_sdw_ti_spk_rtd_init,
251 .controls = lr_4spk_controls,
252 .num_controls = ARRAY_SIZE(lr_4spk_controls),
253 .widgets = lr_4spk_widgets,
254 .num_widgets = ARRAY_SIZE(lr_4spk_widgets),
255 },
256 },
257 .dai_num = 1,
258 },
259 {
260 .vendor_id = 0x025d,
261 .part_id = 0x700,
262 .name_prefix = "rt700",
263 .dais = {
264 {
265 .direction = {true, true},
266 .dai_name = "rt700-aif1",
267 .dai_type = SOC_SDW_DAI_TYPE_JACK,
268 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
269 .rtd_init = asoc_sdw_rt700_rtd_init,
270 .controls = rt700_controls,
271 .num_controls = ARRAY_SIZE(rt700_controls),
272 .widgets = rt700_widgets,
273 .num_widgets = ARRAY_SIZE(rt700_widgets),
274 },
275 },
276 .dai_num = 1,
277 },
278 {
279 .vendor_id = 0x025d,
280 .part_id = 0x711,
281 .name_prefix = "rt711",
282 .version_id = 3,
283 .dais = {
284 {
285 .direction = {true, true},
286 .dai_name = "rt711-sdca-aif1",
287 .dai_type = SOC_SDW_DAI_TYPE_JACK,
288 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
289 .init = asoc_sdw_rt_sdca_jack_init,
290 .exit = asoc_sdw_rt_sdca_jack_exit,
291 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
292 .controls = generic_jack_controls,
293 .num_controls = ARRAY_SIZE(generic_jack_controls),
294 .widgets = generic_jack_widgets,
295 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
296 },
297 },
298 .dai_num = 1,
299 },
300 {
301 .vendor_id = 0x025d,
302 .part_id = 0x711,
303 .name_prefix = "rt711",
304 .version_id = 2,
305 .dais = {
306 {
307 .direction = {true, true},
308 .dai_name = "rt711-aif1",
309 .dai_type = SOC_SDW_DAI_TYPE_JACK,
310 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
311 .init = asoc_sdw_rt711_init,
312 .exit = asoc_sdw_rt711_exit,
313 .rtd_init = asoc_sdw_rt711_rtd_init,
314 .controls = generic_jack_controls,
315 .num_controls = ARRAY_SIZE(generic_jack_controls),
316 .widgets = generic_jack_widgets,
317 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
318 },
319 },
320 .dai_num = 1,
321 },
322 {
323 .vendor_id = 0x025d,
324 .part_id = 0x712,
325 .name_prefix = "rt712",
326 .version_id = 3,
327 .dais = {
328 {
329 .direction = {true, true},
330 .dai_name = "rt712-sdca-aif1",
331 .dai_type = SOC_SDW_DAI_TYPE_JACK,
332 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
333 .init = asoc_sdw_rt_sdca_jack_init,
334 .exit = asoc_sdw_rt_sdca_jack_exit,
335 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
336 .controls = generic_jack_controls,
337 .num_controls = ARRAY_SIZE(generic_jack_controls),
338 .widgets = generic_jack_widgets,
339 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
340 },
341 {
342 .direction = {true, false},
343 .dai_name = "rt712-sdca-aif2",
344 .component_name = "rt712",
345 .dai_type = SOC_SDW_DAI_TYPE_AMP,
346 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
347 .init = asoc_sdw_rt_amp_init,
348 .exit = asoc_sdw_rt_amp_exit,
349 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
350 .controls = generic_spk_controls,
351 .num_controls = ARRAY_SIZE(generic_spk_controls),
352 .widgets = generic_spk_widgets,
353 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
354 },
355 {
356 .direction = {false, true},
357 .dai_name = "rt712-sdca-aif3",
358 .dai_type = SOC_SDW_DAI_TYPE_MIC,
359 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
360 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
361 .quirk = SOC_SDW_CODEC_MIC,
362 .quirk_exclude = true,
363 },
364 },
365 .dai_num = 3,
366 },
367 {
368 .vendor_id = 0x025d,
369 .part_id = 0x1712,
370 .name_prefix = "rt712-dmic",
371 .version_id = 3,
372 .dais = {
373 {
374 .direction = {false, true},
375 .dai_name = "rt712-sdca-dmic-aif1",
376 .dai_type = SOC_SDW_DAI_TYPE_MIC,
377 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
378 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
379 },
380 },
381 .dai_num = 1,
382 },
383 {
384 .vendor_id = 0x025d,
385 .part_id = 0x713,
386 .name_prefix = "rt713",
387 .version_id = 3,
388 .dais = {
389 {
390 .direction = {true, true},
391 .dai_name = "rt712-sdca-aif1",
392 .dai_type = SOC_SDW_DAI_TYPE_JACK,
393 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
394 .init = asoc_sdw_rt_sdca_jack_init,
395 .exit = asoc_sdw_rt_sdca_jack_exit,
396 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
397 .controls = generic_jack_controls,
398 .num_controls = ARRAY_SIZE(generic_jack_controls),
399 .widgets = generic_jack_widgets,
400 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
401 },
402 {
403 .direction = {false, true},
404 .dai_name = "rt712-sdca-aif3",
405 .dai_type = SOC_SDW_DAI_TYPE_MIC,
406 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
407 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
408 },
409 },
410 .dai_num = 2,
411 },
412 {
413 .vendor_id = 0x025d,
414 .part_id = 0x1713,
415 .name_prefix = "rt713-dmic",
416 .version_id = 3,
417 .dais = {
418 {
419 .direction = {false, true},
420 .dai_name = "rt712-sdca-dmic-aif1",
421 .dai_type = SOC_SDW_DAI_TYPE_MIC,
422 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
423 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
424 },
425 },
426 .dai_num = 1,
427 },
428 {
429 .vendor_id = 0x025d,
430 .part_id = 0x1308,
431 .name_prefix = "rt1308",
432 .acpi_id = "10EC1308",
433 .is_amp = true,
434 .dais = {
435 {
436 .direction = {true, false},
437 .dai_name = "rt1308-aif",
438 .component_name = "rt1308",
439 .dai_type = SOC_SDW_DAI_TYPE_AMP,
440 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
441 .init = asoc_sdw_rt_amp_init,
442 .exit = asoc_sdw_rt_amp_exit,
443 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
444 .controls = generic_spk_controls,
445 .num_controls = ARRAY_SIZE(generic_spk_controls),
446 .widgets = generic_spk_widgets,
447 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
448 },
449 },
450 .dai_num = 1,
451 .ops = &soc_sdw_rt1308_i2s_ops,
452 },
453 {
454 .vendor_id = 0x025d,
455 .part_id = 0x1316,
456 .name_prefix = "rt1316",
457 .is_amp = true,
458 .dais = {
459 {
460 .direction = {true, true},
461 .dai_name = "rt1316-aif",
462 .component_name = "rt1316",
463 .dai_type = SOC_SDW_DAI_TYPE_AMP,
464 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
465 .init = asoc_sdw_rt_amp_init,
466 .exit = asoc_sdw_rt_amp_exit,
467 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
468 .controls = generic_spk_controls,
469 .num_controls = ARRAY_SIZE(generic_spk_controls),
470 .widgets = generic_spk_widgets,
471 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
472 },
473 },
474 .dai_num = 1,
475 },
476 {
477 .vendor_id = 0x025d,
478 .part_id = 0x1318,
479 .name_prefix = "rt1318",
480 .is_amp = true,
481 .dais = {
482 {
483 .direction = {true, true},
484 .dai_name = "rt1318-aif",
485 .component_name = "rt1318",
486 .dai_type = SOC_SDW_DAI_TYPE_AMP,
487 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
488 .init = asoc_sdw_rt_amp_init,
489 .exit = asoc_sdw_rt_amp_exit,
490 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
491 .controls = generic_spk_controls,
492 .num_controls = ARRAY_SIZE(generic_spk_controls),
493 .widgets = generic_spk_widgets,
494 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
495 },
496 },
497 .dai_num = 1,
498 },
499 {
500 .vendor_id = 0x025d,
501 .part_id = 0x1320,
502 .name_prefix = "rt1320",
503 .is_amp = true,
504 .dais = {
505 {
506 .direction = {true, false},
507 .dai_name = "rt1320-aif1",
508 .component_name = "rt1320",
509 .dai_type = SOC_SDW_DAI_TYPE_AMP,
510 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
511 .init = asoc_sdw_rt_amp_init,
512 .exit = asoc_sdw_rt_amp_exit,
513 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
514 .controls = generic_spk_controls,
515 .num_controls = ARRAY_SIZE(generic_spk_controls),
516 .widgets = generic_spk_widgets,
517 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
518 },
519 {
520 .direction = {false, true},
521 .dai_name = "rt1320-aif2",
522 .component_name = "rt1320",
523 .dai_type = SOC_SDW_DAI_TYPE_MIC,
524 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
525 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
526 .widgets = generic_dmic_widgets,
527 .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
528 },
529 },
530 .dai_num = 2,
531 },
532 {
533 .vendor_id = 0x025d,
534 .part_id = 0x1321,
535 .name_prefix = "rt1320",
536 .is_amp = true,
537 .dais = {
538 {
539 .direction = {true, false},
540 .dai_name = "rt1320-aif1",
541 .component_name = "rt1320",
542 .dai_type = SOC_SDW_DAI_TYPE_AMP,
543 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
544 .init = asoc_sdw_rt_amp_init,
545 .exit = asoc_sdw_rt_amp_exit,
546 .rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
547 .controls = generic_spk_controls,
548 .num_controls = ARRAY_SIZE(generic_spk_controls),
549 .widgets = generic_spk_widgets,
550 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
551 },
552 {
553 .direction = {false, true},
554 .dai_name = "rt1320-aif2",
555 .component_name = "rt1320",
556 .dai_type = SOC_SDW_DAI_TYPE_MIC,
557 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
558 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
559 .widgets = generic_dmic_widgets,
560 .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
561 },
562 },
563 .dai_num = 2,
564 },
565 {
566 .vendor_id = 0x025d,
567 .part_id = 0x714,
568 .name_prefix = "rt714",
569 .version_id = 3,
570 .ignore_internal_dmic = true,
571 .dais = {
572 {
573 .direction = {false, true},
574 .dai_name = "rt715-sdca-aif2",
575 .dai_type = SOC_SDW_DAI_TYPE_MIC,
576 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
577 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
578 },
579 },
580 .dai_num = 1,
581 },
582 {
583 .vendor_id = 0x025d,
584 .part_id = 0x715,
585 .name_prefix = "rt715",
586 .version_id = 3,
587 .ignore_internal_dmic = true,
588 .dais = {
589 {
590 .direction = {false, true},
591 .dai_name = "rt715-sdca-aif2",
592 .dai_type = SOC_SDW_DAI_TYPE_MIC,
593 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
594 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
595 },
596 },
597 .dai_num = 1,
598 },
599 {
600 .vendor_id = 0x025d,
601 .part_id = 0x714,
602 .name_prefix = "rt714",
603 .version_id = 2,
604 .ignore_internal_dmic = true,
605 .dais = {
606 {
607 .direction = {false, true},
608 .dai_name = "rt715-aif2",
609 .dai_type = SOC_SDW_DAI_TYPE_MIC,
610 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
611 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
612 },
613 },
614 .dai_num = 1,
615 },
616 {
617 .vendor_id = 0x025d,
618 .part_id = 0x715,
619 .name_prefix = "rt715",
620 .version_id = 2,
621 .ignore_internal_dmic = true,
622 .dais = {
623 {
624 .direction = {false, true},
625 .dai_name = "rt715-aif2",
626 .dai_type = SOC_SDW_DAI_TYPE_MIC,
627 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
628 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
629 },
630 },
631 .dai_num = 1,
632 },
633 {
634 .vendor_id = 0x025d,
635 .part_id = 0x721,
636 .name_prefix = "rt721",
637 .version_id = 3,
638 .dais = {
639 {
640 .direction = {true, true},
641 .dai_name = "rt721-sdca-aif1",
642 .dai_type = SOC_SDW_DAI_TYPE_JACK,
643 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
644 .init = asoc_sdw_rt_sdca_jack_init,
645 .exit = asoc_sdw_rt_sdca_jack_exit,
646 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
647 .controls = generic_jack_controls,
648 .num_controls = ARRAY_SIZE(generic_jack_controls),
649 .widgets = generic_jack_widgets,
650 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
651 },
652 {
653 .direction = {true, false},
654 .dai_name = "rt721-sdca-aif2",
655 .component_name = "rt721",
656 .dai_type = SOC_SDW_DAI_TYPE_AMP,
657 /* No feedback capability is provided by rt721-sdca codec driver*/
658 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
659 .init = asoc_sdw_rt_amp_init,
660 .exit = asoc_sdw_rt_amp_exit,
661 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
662 .controls = generic_spk_controls,
663 .num_controls = ARRAY_SIZE(generic_spk_controls),
664 .widgets = generic_spk_widgets,
665 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
666 },
667 {
668 .direction = {false, true},
669 .dai_name = "rt721-sdca-aif3",
670 .dai_type = SOC_SDW_DAI_TYPE_MIC,
671 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
672 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
673 .quirk = SOC_SDW_CODEC_MIC,
674 .quirk_exclude = true,
675 },
676 },
677 .dai_num = 3,
678 },
679 {
680 .vendor_id = 0x025d,
681 .part_id = 0x722,
682 .name_prefix = "rt722",
683 .version_id = 3,
684 .dais = {
685 {
686 .direction = {true, true},
687 .dai_name = "rt722-sdca-aif1",
688 .dai_type = SOC_SDW_DAI_TYPE_JACK,
689 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
690 .init = asoc_sdw_rt_sdca_jack_init,
691 .exit = asoc_sdw_rt_sdca_jack_exit,
692 .rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
693 .controls = generic_jack_controls,
694 .num_controls = ARRAY_SIZE(generic_jack_controls),
695 .widgets = generic_jack_widgets,
696 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
697 },
698 {
699 .direction = {true, false},
700 .dai_name = "rt722-sdca-aif2",
701 .component_name = "rt722",
702 .dai_type = SOC_SDW_DAI_TYPE_AMP,
703 /* No feedback capability is provided by rt722-sdca codec driver*/
704 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
705 .init = asoc_sdw_rt_amp_init,
706 .exit = asoc_sdw_rt_amp_exit,
707 .rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
708 .controls = generic_spk_controls,
709 .num_controls = ARRAY_SIZE(generic_spk_controls),
710 .widgets = generic_spk_widgets,
711 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
712 .quirk = SOC_SDW_CODEC_SPKR,
713 .quirk_exclude = true,
714 },
715 {
716 .direction = {false, true},
717 .dai_name = "rt722-sdca-aif3",
718 .dai_type = SOC_SDW_DAI_TYPE_MIC,
719 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
720 .rtd_init = asoc_sdw_rt_dmic_rtd_init,
721 .quirk = SOC_SDW_CODEC_MIC,
722 .quirk_exclude = true,
723 },
724 },
725 .dai_num = 3,
726 },
727 {
728 .vendor_id = 0x019f,
729 .part_id = 0x8373,
730 .name_prefix = "Left",
731 .is_amp = true,
732 .dais = {
733 {
734 .direction = {true, true},
735 .dai_name = "max98373-aif1",
736 .component_name = "mx8373",
737 .dai_type = SOC_SDW_DAI_TYPE_AMP,
738 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
739 .init = asoc_sdw_maxim_init,
740 .rtd_init = asoc_sdw_maxim_spk_rtd_init,
741 .controls = lr_spk_controls,
742 .num_controls = ARRAY_SIZE(lr_spk_controls),
743 .widgets = lr_spk_widgets,
744 .num_widgets = ARRAY_SIZE(lr_spk_widgets),
745 },
746 },
747 .dai_num = 1,
748 },
749 {
750 .vendor_id = 0x019f,
751 .part_id = 0x8363,
752 .name_prefix = "Left",
753 .is_amp = true,
754 .dais = {
755 {
756 .direction = {true, false},
757 .dai_name = "max98363-aif1",
758 .component_name = "mx8363",
759 .dai_type = SOC_SDW_DAI_TYPE_AMP,
760 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
761 .init = asoc_sdw_maxim_init,
762 .rtd_init = asoc_sdw_maxim_spk_rtd_init,
763 .controls = lr_spk_controls,
764 .num_controls = ARRAY_SIZE(lr_spk_controls),
765 .widgets = lr_spk_widgets,
766 .num_widgets = ARRAY_SIZE(lr_spk_widgets),
767 },
768 },
769 .dai_num = 1,
770 },
771 {
772 .vendor_id = 0x025d,
773 .part_id = 0x5682,
774 .name_prefix = "rt5682",
775 .dais = {
776 {
777 .direction = {true, true},
778 .dai_name = "rt5682-sdw",
779 .dai_type = SOC_SDW_DAI_TYPE_JACK,
780 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
781 .rtd_init = asoc_sdw_rt5682_rtd_init,
782 .controls = generic_jack_controls,
783 .num_controls = ARRAY_SIZE(generic_jack_controls),
784 .widgets = generic_jack_widgets,
785 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
786 },
787 },
788 .dai_num = 1,
789 },
790 {
791 .vendor_id = 0x01fa,
792 .part_id = 0x3556,
793 .name_prefix = "AMP",
794 .is_amp = true,
795 .dais = {
796 {
797 .direction = {true, false},
798 .dai_name = "cs35l56-sdw1",
799 .component_name = "cs35l56",
800 .dai_type = SOC_SDW_DAI_TYPE_AMP,
801 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
802 .init = asoc_sdw_cs_amp_init,
803 .rtd_init = asoc_sdw_cs_spk_rtd_init,
804 .controls = generic_spk_controls,
805 .num_controls = ARRAY_SIZE(generic_spk_controls),
806 .widgets = generic_spk_widgets,
807 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
808 },
809 {
810 .direction = {false, true},
811 .dai_name = "cs35l56-sdw1c",
812 .dai_type = SOC_SDW_DAI_TYPE_AMP,
813 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
814 },
815 },
816 .dai_num = 2,
817 },
818 {
819 .vendor_id = 0x01fa,
820 .part_id = 0x3557,
821 .name_prefix = "AMP",
822 .is_amp = true,
823 .dais = {
824 {
825 .direction = {true, false},
826 .dai_name = "cs35l56-sdw1",
827 .component_name = "cs35l56",
828 .dai_type = SOC_SDW_DAI_TYPE_AMP,
829 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
830 .init = asoc_sdw_cs_amp_init,
831 .rtd_init = asoc_sdw_cs_spk_rtd_init,
832 .controls = generic_spk_controls,
833 .num_controls = ARRAY_SIZE(generic_spk_controls),
834 .widgets = generic_spk_widgets,
835 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
836 },
837 {
838 .direction = {false, true},
839 .dai_name = "cs35l56-sdw1c",
840 .dai_type = SOC_SDW_DAI_TYPE_AMP,
841 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
842 },
843 },
844 .dai_num = 2,
845 },
846 {
847 .vendor_id = 0x01fa,
848 .part_id = 0x3562,
849 .name_prefix = "AMP",
850 .is_amp = true,
851 .dais = {
852 {
853 .direction = {true, false},
854 .dai_name = "cs35l56-sdw1",
855 .component_name = "cs35l56",
856 .dai_type = SOC_SDW_DAI_TYPE_AMP,
857 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
858 .init = asoc_sdw_cs_amp_init,
859 .rtd_init = asoc_sdw_cs_spk_rtd_init,
860 .controls = generic_spk_controls,
861 .num_controls = ARRAY_SIZE(generic_spk_controls),
862 .widgets = generic_spk_widgets,
863 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
864 },
865 {
866 .direction = {false, true},
867 .dai_name = "cs35l56-sdw1c",
868 .dai_type = SOC_SDW_DAI_TYPE_AMP,
869 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
870 },
871 },
872 .dai_num = 2,
873 },
874 {
875 .vendor_id = 0x01fa,
876 .part_id = 0x3563,
877 .name_prefix = "AMP",
878 .is_amp = true,
879 .dais = {
880 {
881 .direction = {true, false},
882 .dai_name = "cs35l56-sdw1",
883 .component_name = "cs35l56",
884 .dai_type = SOC_SDW_DAI_TYPE_AMP,
885 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
886 .init = asoc_sdw_cs_amp_init,
887 .rtd_init = asoc_sdw_cs_spk_rtd_init,
888 .controls = generic_spk_controls,
889 .num_controls = ARRAY_SIZE(generic_spk_controls),
890 .widgets = generic_spk_widgets,
891 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
892 },
893 {
894 .direction = {false, true},
895 .dai_name = "cs35l56-sdw1c",
896 .dai_type = SOC_SDW_DAI_TYPE_AMP,
897 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
898 },
899 },
900 .dai_num = 2,
901 },
902 {
903 .vendor_id = 0x01fa,
904 .part_id = 0x4242,
905 .name_prefix = "cs42l42",
906 .dais = {
907 {
908 .direction = {true, true},
909 .dai_name = "cs42l42-sdw",
910 .dai_type = SOC_SDW_DAI_TYPE_JACK,
911 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
912 .rtd_init = asoc_sdw_cs42l42_rtd_init,
913 .controls = generic_jack_controls,
914 .num_controls = ARRAY_SIZE(generic_jack_controls),
915 .widgets = generic_jack_widgets,
916 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
917 },
918 },
919 .dai_num = 1,
920 },
921 {
922 .vendor_id = 0x01fa,
923 .part_id = 0x4243,
924 .name_prefix = "cs42l43",
925 .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar,
926 .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar,
927 .dais = {
928 {
929 .direction = {true, false},
930 .codec_name = "cs42l43-codec",
931 .dai_name = "cs42l43-dp5",
932 .dai_type = SOC_SDW_DAI_TYPE_JACK,
933 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
934 .rtd_init = asoc_sdw_cs42l43_hs_rtd_init,
935 .controls = generic_jack_controls,
936 .num_controls = ARRAY_SIZE(generic_jack_controls),
937 .widgets = generic_jack_widgets,
938 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
939 },
940 {
941 .direction = {false, true},
942 .codec_name = "cs42l43-codec",
943 .dai_name = "cs42l43-dp1",
944 .dai_type = SOC_SDW_DAI_TYPE_MIC,
945 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
946 .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init,
947 .widgets = generic_dmic_widgets,
948 .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
949 .quirk = SOC_SDW_CODEC_MIC,
950 .quirk_exclude = true,
951 },
952 {
953 .direction = {false, true},
954 .codec_name = "cs42l43-codec",
955 .dai_name = "cs42l43-dp2",
956 .dai_type = SOC_SDW_DAI_TYPE_JACK,
957 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
958 },
959 {
960 .direction = {true, false},
961 .codec_name = "cs42l43-codec",
962 .component_name = "cs42l43-spk",
963 .dai_name = "cs42l43-dp6",
964 .dai_type = SOC_SDW_DAI_TYPE_AMP,
965 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
966 .init = asoc_sdw_cs42l43_spk_init,
967 .rtd_init = asoc_sdw_cs42l43_spk_rtd_init,
968 .controls = generic_spk_controls,
969 .num_controls = ARRAY_SIZE(generic_spk_controls),
970 .widgets = generic_spk_widgets,
971 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
972 .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS,
973 },
974 },
975 .dai_num = 4,
976 },
977 {
978 .vendor_id = 0x01fa,
979 .part_id = 0x2A3B,
980 .name_prefix = "cs42l43",
981 .count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar,
982 .add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar,
983 .dais = {
984 {
985 .direction = {true, false},
986 .codec_name = "cs42l43-codec",
987 .dai_name = "cs42l43-dp5",
988 .dai_type = SOC_SDW_DAI_TYPE_JACK,
989 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
990 .rtd_init = asoc_sdw_cs42l43_hs_rtd_init,
991 .controls = generic_jack_controls,
992 .num_controls = ARRAY_SIZE(generic_jack_controls),
993 .widgets = generic_jack_widgets,
994 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
995 },
996 {
997 .direction = {false, true},
998 .codec_name = "cs42l43-codec",
999 .dai_name = "cs42l43-dp1",
1000 .dai_type = SOC_SDW_DAI_TYPE_MIC,
1001 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
1002 .rtd_init = asoc_sdw_cs42l43_dmic_rtd_init,
1003 .widgets = generic_dmic_widgets,
1004 .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
1005 .quirk = SOC_SDW_CODEC_MIC,
1006 .quirk_exclude = true,
1007 },
1008 {
1009 .direction = {false, true},
1010 .codec_name = "cs42l43-codec",
1011 .dai_name = "cs42l43-dp2",
1012 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1013 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
1014 },
1015 {
1016 .direction = {true, false},
1017 .codec_name = "cs42l43-codec",
1018 .component_name = "cs42l43-spk",
1019 .dai_name = "cs42l43-dp6",
1020 .dai_type = SOC_SDW_DAI_TYPE_AMP,
1021 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
1022 .init = asoc_sdw_cs42l43_spk_init,
1023 .rtd_init = asoc_sdw_cs42l43_spk_rtd_init,
1024 .controls = generic_spk_controls,
1025 .num_controls = ARRAY_SIZE(generic_spk_controls),
1026 .widgets = generic_spk_widgets,
1027 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
1028 .quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS,
1029 },
1030 },
1031 .dai_num = 4,
1032 },
1033 {
1034 .vendor_id = 0x01fa,
1035 .part_id = 0x4245,
1036 .name_prefix = "cs42l45",
1037 .dais = {
1038 {
1039 .direction = {true, false},
1040 .codec_name = "snd_soc_sdca.UAJ",
1041 .dai_name = "IT 41",
1042 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1043 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
1044 .rtd_init = asoc_sdw_cs42l45_hs_rtd_init,
1045 },
1046 {
1047 .direction = {false, true},
1048 .codec_name = "snd_soc_sdca.SmartMic",
1049 .dai_name = "OT 113",
1050 .dai_type = SOC_SDW_DAI_TYPE_MIC,
1051 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
1052 .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init,
1053 },
1054 {
1055 .direction = {false, true},
1056 .codec_name = "snd_soc_sdca.UAJ",
1057 .dai_name = "OT 36",
1058 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1059 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
1060 },
1061 },
1062 .dai_num = 3,
1063 .auxs = {
1064 {
1065 .codec_name = "snd_soc_sdca.HID",
1066 },
1067 },
1068 .aux_num = 1,
1069 },
1070 {
1071 .vendor_id = 0x01fa,
1072 .part_id = 0x4249,
1073 .name_prefix = "cs42l45", /* Use same user-space as cs42l45 */
1074 .dais = {
1075 {
1076 .direction = {true, false},
1077 .codec_name = "snd_soc_sdca.UAJ",
1078 .dai_name = "IT 41",
1079 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1080 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
1081 .rtd_init = asoc_sdw_cs42l45_hs_rtd_init,
1082 },
1083 {
1084 .direction = {false, true},
1085 .codec_name = "snd_soc_sdca.SmartMic",
1086 .dai_name = "OT 113",
1087 .dai_type = SOC_SDW_DAI_TYPE_MIC,
1088 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
1089 .rtd_init = asoc_sdw_cs42l45_dmic_rtd_init,
1090 },
1091 {
1092 .direction = {false, true},
1093 .codec_name = "snd_soc_sdca.UAJ",
1094 .dai_name = "OT 36",
1095 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1096 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
1097 },
1098 },
1099 .dai_num = 3,
1100 .auxs = {
1101 {
1102 .codec_name = "snd_soc_sdca.HID",
1103 },
1104 },
1105 .aux_num = 1,
1106 },
1107 {
1108 .vendor_id = 0x01fa,
1109 .part_id = 0x4747,
1110 .name_prefix = "cs47l47",
1111 .dais = {
1112 {
1113 .direction = {true, false},
1114 .codec_name = "snd_soc_sdca.UAJ",
1115 .dai_name = "IT 41",
1116 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1117 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
1118 .rtd_init = asoc_sdw_cs47l47_hs_rtd_init,
1119 },
1120 {
1121 .direction = {false, true},
1122 .codec_name = "snd_soc_sdca.SmartMic",
1123 .dai_name = "OT 113",
1124 .dai_type = SOC_SDW_DAI_TYPE_MIC,
1125 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
1126 .rtd_init = asoc_sdw_cs47l47_dmic_rtd_init,
1127 },
1128 {
1129 .direction = {false, true},
1130 .codec_name = "snd_soc_sdca.UAJ",
1131 .dai_name = "OT 36",
1132 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1133 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
1134 },
1135 },
1136 .dai_num = 3,
1137 .auxs = {
1138 {
1139 .codec_name = "snd_soc_sdca.HID",
1140 },
1141 },
1142 .aux_num = 1,
1143 },
1144 {
1145 .vendor_id = 0x04b3,
1146 .part_id = 0x9356,
1147 .name_prefix = "es9356",
1148 .version_id = 3,
1149 .dais = {
1150 {
1151 .direction = {true, false},
1152 .dai_name = "es9356-sdp-aif1",
1153 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1154 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
1155 .init = asoc_sdw_es9356_init,
1156 .exit = asoc_sdw_es9356_exit,
1157 .rtd_init = asoc_sdw_es9356_rtd_init,
1158 .controls = generic_jack_controls,
1159 .num_controls = ARRAY_SIZE(generic_jack_controls),
1160 .widgets = generic_jack_widgets,
1161 .num_widgets = ARRAY_SIZE(generic_jack_widgets),
1162 },
1163 {
1164 .direction = {false, true},
1165 .dai_name = "es9356-sdp-aif4",
1166 .dai_type = SOC_SDW_DAI_TYPE_MIC,
1167 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
1168 .rtd_init = asoc_sdw_es9356_dmic_rtd_init,
1169 .widgets = generic_dmic_widgets,
1170 .num_widgets = ARRAY_SIZE(generic_dmic_widgets),
1171 },
1172 {
1173 .direction = {false, true},
1174 .dai_name = "es9356-sdp-aif2",
1175 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1176 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
1177 },
1178 {
1179 .direction = {true, false},
1180 .dai_name = "es9356-sdp-aif3",
1181 .component_name = "es9356",
1182 .dai_type = SOC_SDW_DAI_TYPE_AMP,
1183 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
1184 .init = asoc_sdw_es9356_amp_init,
1185 .rtd_init = asoc_sdw_es9356_spk_rtd_init,
1186 .controls = generic_spk_controls,
1187 .num_controls = ARRAY_SIZE(generic_spk_controls),
1188 .widgets = generic_spk_widgets,
1189 .num_widgets = ARRAY_SIZE(generic_spk_widgets),
1190 },
1191 },
1192 .dai_num = 4,
1193 },
1194 {
1195 .vendor_id = 0x0105,
1196 .part_id = 0xaaaa, /* generic codec mockup */
1197 .name_prefix = "sdw_mockup_mmulti-function",
1198 .version_id = 0,
1199 .dais = {
1200 {
1201 .direction = {true, true},
1202 .dai_name = "sdw-mockup-aif1",
1203 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1204 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
1205 },
1206 {
1207 .direction = {true, false},
1208 .dai_name = "sdw-mockup-aif1",
1209 .dai_type = SOC_SDW_DAI_TYPE_AMP,
1210 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
1211 },
1212 {
1213 .direction = {false, true},
1214 .dai_name = "sdw-mockup-aif1",
1215 .dai_type = SOC_SDW_DAI_TYPE_MIC,
1216 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
1217 },
1218 },
1219 .dai_num = 3,
1220 },
1221 {
1222 .vendor_id = 0x0105,
1223 .part_id = 0xaa55, /* headset codec mockup */
1224 .name_prefix = "sdw_mockup_headset0",
1225 .version_id = 0,
1226 .dais = {
1227 {
1228 .direction = {true, true},
1229 .dai_name = "sdw-mockup-aif1",
1230 .dai_type = SOC_SDW_DAI_TYPE_JACK,
1231 .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
1232 },
1233 },
1234 .dai_num = 1,
1235 },
1236 {
1237 .vendor_id = 0x0105,
1238 .part_id = 0x55aa, /* amplifier mockup */
1239 .name_prefix = "sdw_mockup_amp1",
1240 .is_amp = true,
1241 .version_id = 0,
1242 .dais = {
1243 {
1244 .direction = {true, true},
1245 .dai_name = "sdw-mockup-aif1",
1246 .dai_type = SOC_SDW_DAI_TYPE_AMP,
1247 .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
1248 },
1249 },
1250 .dai_num = 1,
1251 },
1252 {
1253 .vendor_id = 0x0105,
1254 .part_id = 0x5555,
1255 .name_prefix = "sdw_mockup_mic0",
1256 .version_id = 0,
1257 .dais = {
1258 {
1259 .dai_name = "sdw-mockup-aif1",
1260 .direction = {false, true},
1261 .dai_type = SOC_SDW_DAI_TYPE_MIC,
1262 .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
1263 },
1264 },
1265 .dai_num = 1,
1266 },
1267 };
1268 EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS");
1269
asoc_sdw_get_codec_info_list_count(void)1270 int asoc_sdw_get_codec_info_list_count(void)
1271 {
1272 return ARRAY_SIZE(codec_info_list);
1273 };
1274 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS");
1275
asoc_sdw_find_codec_info_part(const u64 adr)1276 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr)
1277 {
1278 unsigned int vendor_id, part_id, sdw_version;
1279 int i;
1280
1281 vendor_id = SDW_MFG_ID(adr);
1282 part_id = SDW_PART_ID(adr);
1283 sdw_version = SDW_VERSION(adr);
1284 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1285 /*
1286 * A codec info is for all sdw version with the part id if
1287 * version_id is not specified in the codec info.
1288 */
1289 if (part_id == codec_info_list[i].part_id &&
1290 vendor_id == codec_info_list[i].vendor_id &&
1291 (!codec_info_list[i].version_id ||
1292 sdw_version == codec_info_list[i].version_id))
1293 return &codec_info_list[i];
1294
1295 return NULL;
1296 }
1297 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS");
1298
asoc_sdw_find_codec_info_sdw_id(const struct sdw_slave_id * id)1299 static struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_sdw_id(const struct sdw_slave_id *id)
1300 {
1301 int i;
1302
1303 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1304 if (id->part_id == codec_info_list[i].part_id &&
1305 id->mfg_id == codec_info_list[i].vendor_id &&
1306 (!codec_info_list[i].version_id ||
1307 id->sdw_version == codec_info_list[i].version_id))
1308 return &codec_info_list[i];
1309
1310 return NULL;
1311 }
1312
asoc_sdw_find_codec_info_acpi(const u8 * acpi_id)1313 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id)
1314 {
1315 int i;
1316
1317 if (!acpi_id[0])
1318 return NULL;
1319
1320 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1321 if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
1322 return &codec_info_list[i];
1323
1324 return NULL;
1325 }
1326 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS");
1327
asoc_sdw_find_codec_info_dai(const char * dai_name,int * dai_index)1328 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index)
1329 {
1330 int i, j;
1331
1332 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1333 for (j = 0; j < codec_info_list[i].dai_num; j++) {
1334 if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) {
1335 *dai_index = j;
1336 return &codec_info_list[i];
1337 }
1338 }
1339 }
1340
1341 return NULL;
1342 }
1343 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS");
1344
asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info * codec_info,const char * dai_name)1345 static int asoc_sdw_find_codec_info_dai_index(const struct asoc_sdw_codec_info *codec_info,
1346 const char *dai_name)
1347 {
1348 int i;
1349
1350 for (i = 0; i < codec_info->dai_num; i++) {
1351 if (!strcmp(codec_info->dais[i].dai_name, dai_name))
1352 return i;
1353 }
1354
1355 return -ENOENT;
1356 }
1357
asoc_sdw_rtd_init(struct snd_soc_pcm_runtime * rtd)1358 int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
1359 {
1360 struct snd_soc_card *card = rtd->card;
1361 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1362 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
1363 struct asoc_sdw_codec_info *codec_info;
1364 struct snd_soc_dai *dai;
1365 struct sdw_slave *sdw_peripheral;
1366 const char *spk_components = NULL;
1367 int dai_index;
1368 int ret;
1369 int i;
1370
1371 for_each_rtd_codec_dais(rtd, i, dai) {
1372 if (is_sdw_slave(dai->component->dev))
1373 sdw_peripheral = dev_to_sdw_dev(dai->component->dev);
1374 else if (dai->component->dev->parent && is_sdw_slave(dai->component->dev->parent))
1375 sdw_peripheral = dev_to_sdw_dev(dai->component->dev->parent);
1376 else
1377 continue;
1378
1379 codec_info = asoc_sdw_find_codec_info_sdw_id(&sdw_peripheral->id);
1380 if (!codec_info)
1381 return -EINVAL;
1382
1383 dai_index = asoc_sdw_find_codec_info_dai_index(codec_info, dai->name);
1384 WARN_ON(dai_index < 0);
1385
1386 /*
1387 * A codec dai can be connected to different dai links for capture and playback,
1388 * but we only need to call the rtd_init function once.
1389 * The rtd_init for each codec dai is independent. So, the order of rtd_init
1390 * doesn't matter.
1391 */
1392 if (codec_info->dais[dai_index].rtd_init_done)
1393 continue;
1394
1395 dev_dbg(card->dev, "%#x/%s initializing for %s/%s\n",
1396 codec_info->part_id, codec_info->dais[dai_index].dai_name,
1397 dai->component->name, dai->name);
1398
1399 /*
1400 * Add card controls and dapm widgets for the first codec dai.
1401 * The controls and widgets will be used for all codec dais.
1402 */
1403
1404 if (i > 0)
1405 goto skip_add_controls_widgets;
1406
1407 if (codec_info->dais[dai_index].controls) {
1408 ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls,
1409 codec_info->dais[dai_index].num_controls);
1410 if (ret) {
1411 dev_err(card->dev, "%#x-%#x controls addition failed: %d\n",
1412 codec_info->vendor_id, codec_info->part_id, ret);
1413 return ret;
1414 }
1415 }
1416 if (codec_info->dais[dai_index].widgets) {
1417 ret = snd_soc_dapm_new_controls(dapm,
1418 codec_info->dais[dai_index].widgets,
1419 codec_info->dais[dai_index].num_widgets);
1420 if (ret) {
1421 dev_err(card->dev, "%#x-%#x widgets addition failed: %d\n",
1422 codec_info->vendor_id, codec_info->part_id, ret);
1423 return ret;
1424 }
1425 }
1426
1427 skip_add_controls_widgets:
1428 if (codec_info->dais[dai_index].rtd_init) {
1429 ret = codec_info->dais[dai_index].rtd_init(rtd, dai);
1430 if (ret)
1431 return ret;
1432 }
1433
1434 /* Generate the spk component string for card->components string */
1435 if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP &&
1436 codec_info->dais[dai_index].component_name) {
1437 const char *component;
1438
1439 /*
1440 * For the special case of cs42l43 with sidecar amps, use only
1441 * "cs35l56-bridge" as the component name in card->components
1442 */
1443 if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS &&
1444 !strcmp(codec_info->dais[dai_index].component_name, "cs42l43-spk"))
1445 component = "cs35l56-bridge";
1446 else
1447 component = codec_info->dais[dai_index].component_name;
1448
1449 if (!spk_components)
1450 spk_components =
1451 devm_kasprintf(card->dev, GFP_KERNEL, "%s", component);
1452 else
1453 /* Append component name to spk_components */
1454 spk_components =
1455 devm_kasprintf(card->dev, GFP_KERNEL,
1456 "%s+%s", spk_components, component);
1457
1458 if (!spk_components)
1459 return -ENOMEM;
1460 }
1461
1462 codec_info->dais[dai_index].rtd_init_done = true;
1463 }
1464
1465 if (spk_components) {
1466 /* Update card components for speaker components */
1467 card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s",
1468 card->components, spk_components);
1469 if (!card->components)
1470 return -ENOMEM;
1471 }
1472
1473 return 0;
1474 }
1475 EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS");
1476
1477 /* these wrappers are only needed to avoid typecast compilation errors */
asoc_sdw_startup(struct snd_pcm_substream * substream)1478 int asoc_sdw_startup(struct snd_pcm_substream *substream)
1479 {
1480 return sdw_startup_stream(substream);
1481 }
1482 EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS");
1483
asoc_sdw_prepare(struct snd_pcm_substream * substream)1484 int asoc_sdw_prepare(struct snd_pcm_substream *substream)
1485 {
1486 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
1487 struct sdw_stream_runtime *sdw_stream;
1488 struct snd_soc_dai *dai;
1489
1490 /* Find stream from first CPU DAI */
1491 dai = snd_soc_rtd_to_cpu(rtd, 0);
1492
1493 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
1494 if (IS_ERR(sdw_stream)) {
1495 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
1496 return PTR_ERR(sdw_stream);
1497 }
1498
1499 return sdw_prepare_stream(sdw_stream);
1500 }
1501 EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS");
1502
asoc_sdw_trigger(struct snd_pcm_substream * substream,int cmd)1503 int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
1504 {
1505 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
1506 struct sdw_stream_runtime *sdw_stream;
1507 struct snd_soc_dai *dai;
1508 int ret;
1509
1510 /* Find stream from first CPU DAI */
1511 dai = snd_soc_rtd_to_cpu(rtd, 0);
1512
1513 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
1514 if (IS_ERR(sdw_stream)) {
1515 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
1516 return PTR_ERR(sdw_stream);
1517 }
1518
1519 switch (cmd) {
1520 case SNDRV_PCM_TRIGGER_RESUME:
1521 /*
1522 * The peripherals lose their port configuration when the
1523 * controller is power-gated during system suspend, and an
1524 * application that restarts the stream with
1525 * SNDRV_PCM_IOCTL_RESUME - which platforms advertising
1526 * SNDRV_PCM_INFO_RESUME allow - never goes through
1527 * .prepare() again. Prepare the stream here so that the
1528 * ports are reprogrammed before they are enabled;
1529 * sdw_prepare_stream() reapplies the parameters without
1530 * recomputing them when the stream is disabled.
1531 */
1532 ret = sdw_prepare_stream(sdw_stream);
1533 if (ret)
1534 break;
1535 fallthrough;
1536 case SNDRV_PCM_TRIGGER_START:
1537 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1538 ret = sdw_enable_stream(sdw_stream);
1539 break;
1540
1541 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1542 case SNDRV_PCM_TRIGGER_SUSPEND:
1543 case SNDRV_PCM_TRIGGER_STOP:
1544 ret = sdw_disable_stream(sdw_stream);
1545 break;
1546 default:
1547 ret = -EINVAL;
1548 break;
1549 }
1550
1551 if (ret)
1552 dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
1553
1554 return ret;
1555 }
1556 EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS");
1557
asoc_sdw_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)1558 int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
1559 struct snd_pcm_hw_params *params)
1560 {
1561 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
1562 struct snd_soc_dai_link_ch_map *ch_maps;
1563 int ch = params_channels(params);
1564 unsigned int cpu_ch_mask, codec_ch_mask;
1565 int num_codecs;
1566 int step;
1567 int i;
1568
1569 if (!rtd->dai_link->ch_maps)
1570 return 0;
1571
1572 /* Identical data will be sent to all codecs in playback */
1573 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1574 cpu_ch_mask = GENMASK(ch - 1, 0);
1575 step = 0;
1576 codec_ch_mask = 0;
1577 } else {
1578 num_codecs = rtd->dai_link->num_codecs;
1579
1580 if (ch < num_codecs || ch % num_codecs != 0) {
1581 dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
1582 ch, num_codecs);
1583 return -EINVAL;
1584 }
1585
1586 cpu_ch_mask = GENMASK(ch / num_codecs - 1, 0);
1587 step = hweight_long(cpu_ch_mask);
1588 codec_ch_mask = cpu_ch_mask;
1589 }
1590
1591 /*
1592 * The captured data will be combined from each cpu DAI if the dai
1593 * link has more than one codec DAIs. Set codec channel mask and
1594 * ASoC will set the corresponding channel numbers for each cpu dai.
1595 *
1596 * sdw_stream_add_slave() assigns different payload offsets to each
1597 * codec in a capture stream, so that the same channels on each
1598 * codec map to different channels on the CPU.
1599 */
1600 for_each_link_ch_maps(rtd->dai_link, i, ch_maps) {
1601 ch_maps->cpu_ch_mask = cpu_ch_mask << (i * step);
1602 ch_maps->codec_ch_mask = codec_ch_mask;
1603 }
1604
1605 return 0;
1606 }
1607 EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS");
1608
asoc_sdw_hw_free(struct snd_pcm_substream * substream)1609 int asoc_sdw_hw_free(struct snd_pcm_substream *substream)
1610 {
1611 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
1612 struct sdw_stream_runtime *sdw_stream;
1613 struct snd_soc_dai *dai;
1614
1615 /* Find stream from first CPU DAI */
1616 dai = snd_soc_rtd_to_cpu(rtd, 0);
1617
1618 sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
1619 if (IS_ERR(sdw_stream)) {
1620 dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
1621 return PTR_ERR(sdw_stream);
1622 }
1623
1624 return sdw_deprepare_stream(sdw_stream);
1625 }
1626 EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS");
1627
asoc_sdw_shutdown(struct snd_pcm_substream * substream)1628 void asoc_sdw_shutdown(struct snd_pcm_substream *substream)
1629 {
1630 sdw_shutdown_stream(substream);
1631 }
1632 EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS");
1633
asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr * adr_link,unsigned int sdw_version,unsigned int mfg_id,unsigned int part_id,unsigned int class_id,int index_in_link)1634 static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
1635 unsigned int sdw_version,
1636 unsigned int mfg_id,
1637 unsigned int part_id,
1638 unsigned int class_id,
1639 int index_in_link)
1640 {
1641 int i;
1642
1643 for (i = 0; i < adr_link->num_adr; i++) {
1644 unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
1645 u64 adr;
1646
1647 /* skip itself */
1648 if (i == index_in_link)
1649 continue;
1650
1651 adr = adr_link->adr_d[i].adr;
1652
1653 sdw1_version = SDW_VERSION(adr);
1654 mfg1_id = SDW_MFG_ID(adr);
1655 part1_id = SDW_PART_ID(adr);
1656 class1_id = SDW_CLASS_ID(adr);
1657
1658 if (sdw_version == sdw1_version &&
1659 mfg_id == mfg1_id &&
1660 part_id == part1_id &&
1661 class_id == class1_id)
1662 return false;
1663 }
1664
1665 return true;
1666 }
1667
_asoc_sdw_get_codec_name(struct device * dev,const struct snd_soc_acpi_link_adr * adr_link,int adr_index)1668 static const char *_asoc_sdw_get_codec_name(struct device *dev,
1669 const struct snd_soc_acpi_link_adr *adr_link,
1670 int adr_index)
1671 {
1672 u64 adr = adr_link->adr_d[adr_index].adr;
1673 unsigned int sdw_version = SDW_VERSION(adr);
1674 unsigned int link_id = SDW_DISCO_LINK_ID(adr);
1675 unsigned int unique_id = SDW_UNIQUE_ID(adr);
1676 unsigned int mfg_id = SDW_MFG_ID(adr);
1677 unsigned int part_id = SDW_PART_ID(adr);
1678 unsigned int class_id = SDW_CLASS_ID(adr);
1679
1680 if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id,
1681 class_id, adr_index))
1682 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x",
1683 link_id, mfg_id, part_id, class_id);
1684
1685 return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x",
1686 link_id, mfg_id, part_id, class_id, unique_id);
1687 }
1688
asoc_sdw_get_codec_name(struct device * dev,const struct asoc_sdw_dai_info * dai_info,const struct snd_soc_acpi_link_adr * adr_link,int adr_index)1689 const char *asoc_sdw_get_codec_name(struct device *dev,
1690 const struct asoc_sdw_dai_info *dai_info,
1691 const struct snd_soc_acpi_link_adr *adr_link,
1692 int adr_index)
1693 {
1694 if (dai_info->codec_name) {
1695 struct snd_soc_component *component;
1696
1697 component = snd_soc_lookup_component_by_name(dai_info->codec_name);
1698 if (component) {
1699 dev_dbg(dev, "%s found component %s for codec_name %s\n",
1700 __func__, component->name, dai_info->codec_name);
1701 return devm_kstrdup(dev, component->name, GFP_KERNEL);
1702 } else {
1703 dev_dbg(dev, "%s component %s is not registered yet\n",
1704 __func__, dai_info->codec_name);
1705 return ERR_PTR(-EPROBE_DEFER);
1706 }
1707 }
1708
1709 return _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
1710 }
1711 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS");
1712
1713 /* helper to get the link that the codec DAI is used */
asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card * card,const char * dai_name)1714 struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card,
1715 const char *dai_name)
1716 {
1717 struct snd_soc_dai_link *dai_link;
1718 int i;
1719 int j;
1720
1721 for_each_card_prelinks(card, i, dai_link) {
1722 for (j = 0; j < dai_link->num_codecs; j++) {
1723 /* Check each codec in a link */
1724 if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
1725 return dai_link;
1726 }
1727 }
1728 return NULL;
1729 }
1730 EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS");
1731
asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card * card)1732 void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card)
1733 {
1734 struct snd_soc_dai_link *dai_link;
1735 struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1736 int ret;
1737 int i, j;
1738
1739 for (i = 0; i < ctx->codec_info_list_count; i++) {
1740 for (j = 0; j < codec_info_list[i].dai_num; j++) {
1741 codec_info_list[i].dais[j].rtd_init_done = false;
1742 /* Check each dai in codec_info_lis to see if it is used in the link */
1743 if (!codec_info_list[i].dais[j].exit)
1744 continue;
1745 /*
1746 * We don't need to call .exit function if there is no matched
1747 * dai link found.
1748 */
1749 dai_link = asoc_sdw_mc_find_codec_dai_used(card,
1750 codec_info_list[i].dais[j].dai_name);
1751 if (dai_link) {
1752 /* Do the .exit function if the codec dai is used in the link */
1753 ret = codec_info_list[i].dais[j].exit(card, dai_link);
1754 if (ret)
1755 dev_warn(card->dev,
1756 "codec exit failed %d\n",
1757 ret);
1758 break;
1759 }
1760 }
1761 }
1762 }
1763 EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS");
1764
asoc_sdw_card_late_probe(struct snd_soc_card * card)1765 int asoc_sdw_card_late_probe(struct snd_soc_card *card)
1766 {
1767 int ret = 0;
1768 int i;
1769
1770 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1771 if (codec_info_list[i].codec_card_late_probe) {
1772 ret = codec_info_list[i].codec_card_late_probe(card);
1773 if (ret < 0)
1774 return ret;
1775 }
1776 }
1777 return ret;
1778 }
1779 EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS");
1780
asoc_sdw_init_dai_link(struct device * dev,struct snd_soc_dai_link * dai_links,int * be_id,char * name,int playback,int capture,struct snd_soc_dai_link_component * cpus,int cpus_num,struct snd_soc_dai_link_component * platform_component,int num_platforms,struct snd_soc_dai_link_component * codecs,int codecs_num,int no_pcm,int (* init)(struct snd_soc_pcm_runtime * rtd),const struct snd_soc_ops * ops)1781 void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1782 int *be_id, char *name, int playback, int capture,
1783 struct snd_soc_dai_link_component *cpus, int cpus_num,
1784 struct snd_soc_dai_link_component *platform_component,
1785 int num_platforms, struct snd_soc_dai_link_component *codecs,
1786 int codecs_num, int no_pcm,
1787 int (*init)(struct snd_soc_pcm_runtime *rtd),
1788 const struct snd_soc_ops *ops)
1789 {
1790 dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id);
1791 dai_links->id = (*be_id)++;
1792 dai_links->name = name;
1793 dai_links->stream_name = name;
1794 dai_links->platforms = platform_component;
1795 dai_links->num_platforms = num_platforms;
1796 dai_links->no_pcm = no_pcm;
1797 dai_links->cpus = cpus;
1798 dai_links->num_cpus = cpus_num;
1799 dai_links->codecs = codecs;
1800 dai_links->num_codecs = codecs_num;
1801 dai_links->playback_only = playback && !capture;
1802 dai_links->capture_only = !playback && capture;
1803 dai_links->init = init;
1804 dai_links->ops = ops;
1805 }
1806 EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS");
1807
asoc_sdw_init_simple_dai_link(struct device * dev,struct snd_soc_dai_link * dai_links,int * be_id,char * name,int playback,int capture,const char * cpu_dai_name,const char * platform_comp_name,const char * codec_name,const char * codec_dai_name,int no_pcm,int (* init)(struct snd_soc_pcm_runtime * rtd),const struct snd_soc_ops * ops)1808 int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1809 int *be_id, char *name, int playback, int capture,
1810 const char *cpu_dai_name, const char *platform_comp_name,
1811 const char *codec_name, const char *codec_dai_name,
1812 int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd),
1813 const struct snd_soc_ops *ops)
1814 {
1815 struct snd_soc_dai_link_component *dlc;
1816
1817 /* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */
1818 dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL);
1819 if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name)
1820 return -ENOMEM;
1821
1822 dlc[0].dai_name = cpu_dai_name;
1823 dlc[1].name = platform_comp_name;
1824
1825 dlc[2].name = codec_name;
1826 dlc[2].dai_name = codec_dai_name;
1827
1828 asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture,
1829 &dlc[0], 1, &dlc[1], 1, &dlc[2], 1,
1830 no_pcm, init, ops);
1831
1832 return 0;
1833 }
1834 EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS");
1835
1836 /**
1837 * is_sdca_aux_dev_present - Check if an SDCA aux device is present on the SDW peripheral
1838 * @dev: Device pointer
1839 * @aux_codec_name: Aux codec name from the codec info (e.g. "snd_soc_sdca.HID.2")
1840 * @adr_link: ACPI link address
1841 * @adr_index: Index of the ACPI link address
1842 *
1843 * Return: 1 if the aux is present, 0 if the aux is not present, or negative error code.
1844 */
is_sdca_aux_dev_present(struct device * dev,const char * aux_codec_name,const struct snd_soc_acpi_link_adr * adr_link,int adr_index)1845 static int is_sdca_aux_dev_present(struct device *dev,
1846 const char *aux_codec_name,
1847 const struct snd_soc_acpi_link_adr *adr_link,
1848 int adr_index)
1849 {
1850 struct sdw_slave *slave;
1851 const char *sdw_codec_name;
1852 int i;
1853
1854 if (!aux_codec_name)
1855 return 0;
1856
1857 sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
1858 if (!sdw_codec_name)
1859 return -ENOMEM;
1860
1861 struct device *sdw_dev __free(put_device) =
1862 bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
1863 if (!sdw_dev) {
1864 dev_err(dev, "codec %s not found\n", sdw_codec_name);
1865 return -EINVAL;
1866 }
1867
1868 slave = dev_to_sdw_dev(sdw_dev);
1869
1870 if (!slave->sdca_data.interface_revision) {
1871 dev_warn(dev, "No SDCA properties, assuming aux '%s' present\n", aux_codec_name);
1872 return 1;
1873 }
1874
1875 for (i = 0; i < slave->sdca_data.num_functions; i++) {
1876 const char *fname = slave->sdca_data.function[i].name;
1877
1878 if (fname && strstr(aux_codec_name, fname))
1879 return 1;
1880 }
1881
1882 dev_dbg(dev, "SDCA function for aux '%s' NOT FOUND on slave, skipping\n", aux_codec_name);
1883
1884 return 0;
1885 }
1886
asoc_sdw_count_sdw_endpoints(struct snd_soc_card * card,int * num_devs,int * num_ends,int * num_aux)1887 int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card,
1888 int *num_devs, int *num_ends, int *num_aux)
1889 {
1890 struct device *dev = card->dev;
1891 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
1892 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1893 const struct snd_soc_acpi_link_adr *adr_link;
1894 int i, j, ret;
1895
1896 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
1897 *num_devs += adr_link->num_adr;
1898
1899 for (i = 0; i < adr_link->num_adr; i++) {
1900 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
1901 struct asoc_sdw_codec_info *codec_info;
1902
1903 *num_ends += adr_dev->num_endpoints;
1904
1905 codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
1906 if (!codec_info)
1907 return -EINVAL;
1908
1909 for (j = 0; j < codec_info->aux_num; j++) {
1910 ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name,
1911 adr_link, i);
1912 if (ret < 0)
1913 return ret;
1914 if (ret)
1915 (*num_aux)++;
1916 }
1917 }
1918 }
1919
1920 dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
1921
1922 return 0;
1923 }
1924 EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS");
1925
asoc_sdw_find_dailink(struct asoc_sdw_dailink * dailinks,const struct snd_soc_acpi_endpoint * new)1926 struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
1927 const struct snd_soc_acpi_endpoint *new)
1928 {
1929 while (dailinks->initialised) {
1930 if (new->aggregated && dailinks->group_id == new->group_id)
1931 return dailinks;
1932
1933 dailinks++;
1934 }
1935
1936 INIT_LIST_HEAD(&dailinks->endpoints);
1937 dailinks->group_id = new->group_id;
1938 dailinks->initialised = true;
1939
1940 return dailinks;
1941 }
1942 EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS");
1943
asoc_sdw_get_dai_type(u32 type)1944 int asoc_sdw_get_dai_type(u32 type)
1945 {
1946 switch (type) {
1947 case SDCA_FUNCTION_TYPE_SMART_AMP:
1948 case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
1949 case SDCA_FUNCTION_TYPE_COMPANION_AMP:
1950 return SOC_SDW_DAI_TYPE_AMP;
1951 case SDCA_FUNCTION_TYPE_SMART_MIC:
1952 case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
1953 case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
1954 return SOC_SDW_DAI_TYPE_MIC;
1955 case SDCA_FUNCTION_TYPE_UAJ:
1956 case SDCA_FUNCTION_TYPE_RJ:
1957 case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
1958 return SOC_SDW_DAI_TYPE_JACK;
1959 default:
1960 return -EINVAL;
1961 }
1962 }
1963 EXPORT_SYMBOL_NS(asoc_sdw_get_dai_type, "SND_SOC_SDW_UTILS");
1964
1965 /**
1966 * is_sdca_endpoint_present - Check if an SDCA endpoint is present on the SDW peripheral
1967 * @dev: Device pointer
1968 * @codec_info: Codec info pointer
1969 * @adr_link: ACPI link address
1970 * @adr_index: Index of the ACPI link address
1971 * @end_index: Index of the endpoint
1972 *
1973 * Return: 1 if the endpoint is present, 0 if the endpoint is not present, or negative error code.
1974 */
is_sdca_endpoint_present(struct device * dev,struct asoc_sdw_codec_info * codec_info,const struct snd_soc_acpi_link_adr * adr_link,int adr_index,int end_index)1975 static int is_sdca_endpoint_present(struct device *dev,
1976 struct asoc_sdw_codec_info *codec_info,
1977 const struct snd_soc_acpi_link_adr *adr_link,
1978 int adr_index, int end_index)
1979 {
1980 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index];
1981 const struct snd_soc_acpi_endpoint *adr_end;
1982 const struct asoc_sdw_dai_info *dai_info;
1983 struct sdw_slave *slave;
1984 const char *sdw_codec_name;
1985 int i;
1986
1987 adr_end = &adr_dev->endpoints[end_index];
1988 dai_info = &codec_info->dais[adr_end->num];
1989
1990 sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
1991 if (!sdw_codec_name)
1992 return -ENOMEM;
1993
1994 struct device *sdw_dev __free(put_device) =
1995 bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
1996 if (!sdw_dev) {
1997 dev_err(dev, "codec %s not found\n", sdw_codec_name);
1998 return -EINVAL;
1999 }
2000
2001 slave = dev_to_sdw_dev(sdw_dev);
2002
2003 /* Make sure BIOS provides SDCA properties */
2004 if (!slave->sdca_data.interface_revision) {
2005 dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n");
2006 return 1;
2007 }
2008
2009 for (i = 0; i < slave->sdca_data.num_functions; i++) {
2010 int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type);
2011
2012 if (dai_type == dai_info->dai_type) {
2013 dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n",
2014 dai_type, slave->sdca_data.function[i].name);
2015 return 1;
2016 }
2017 }
2018
2019 dev_dbg(&slave->dev,
2020 "SDCA device function for DAI type %d not supported, skip endpoint\n",
2021 dai_info->dai_type);
2022
2023 return 0;
2024 }
2025
asoc_sdw_parse_sdw_endpoints(struct device * dev,struct asoc_sdw_mc_private * ctx,struct snd_soc_aux_dev * soc_aux,struct asoc_sdw_dailink * soc_dais,struct asoc_sdw_endpoint * soc_ends,int * num_devs)2026 int asoc_sdw_parse_sdw_endpoints(struct device *dev,
2027 struct asoc_sdw_mc_private *ctx,
2028 struct snd_soc_aux_dev *soc_aux,
2029 struct asoc_sdw_dailink *soc_dais,
2030 struct asoc_sdw_endpoint *soc_ends,
2031 int *num_devs)
2032 {
2033 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
2034 struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
2035 const struct snd_soc_acpi_link_adr *adr_link;
2036 struct asoc_sdw_endpoint *soc_end = soc_ends;
2037 int num_dais = 0;
2038 int i, j;
2039 int ret;
2040
2041 for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
2042 int num_link_dailinks = 0;
2043
2044 if (!is_power_of_2(adr_link->mask)) {
2045 dev_err(dev, "link with multiple mask bits: 0x%x\n",
2046 adr_link->mask);
2047 return -EINVAL;
2048 }
2049
2050 for (i = 0; i < adr_link->num_adr; i++) {
2051 const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
2052 struct asoc_sdw_codec_info *codec_info;
2053 const char *codec_name;
2054 bool check_sdca = false;
2055
2056 if (!adr_dev->name_prefix) {
2057 dev_err(dev, "codec 0x%llx does not have a name prefix\n",
2058 adr_dev->adr);
2059 return -EINVAL;
2060 }
2061
2062 codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
2063 if (!codec_info)
2064 return -EINVAL;
2065
2066 for (j = 0; j < codec_info->aux_num; j++) {
2067 struct snd_soc_component *component;
2068
2069 ret = is_sdca_aux_dev_present(dev, codec_info->auxs[j].codec_name,
2070 adr_link, i);
2071 if (ret < 0)
2072 return ret;
2073
2074 if (ret == 0)
2075 continue;
2076
2077 component = snd_soc_lookup_component_by_name(codec_info->auxs[j].codec_name);
2078 if (component) {
2079 dev_dbg(dev, "%s found component %s for aux name %s\n",
2080 __func__, component->name,
2081 codec_info->auxs[j].codec_name);
2082 soc_aux->dlc.name = component->name;
2083 } else {
2084 dev_dbg(dev, "%s the aux component %s is not registered yet\n",
2085 __func__, codec_info->auxs[j].codec_name);
2086 return -EPROBE_DEFER;
2087 }
2088 soc_aux++;
2089 }
2090
2091 ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
2092
2093 if (codec_info->count_sidecar && codec_info->add_sidecar) {
2094 ret = codec_info->count_sidecar(ctx, &num_dais, num_devs);
2095 if (ret)
2096 return ret;
2097
2098 soc_end->include_sidecar = true;
2099 }
2100
2101 if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1)
2102 check_sdca = true;
2103
2104 for (j = 0; j < adr_dev->num_endpoints; j++) {
2105 const struct snd_soc_acpi_endpoint *adr_end;
2106 const struct asoc_sdw_dai_info *dai_info;
2107 struct asoc_sdw_dailink *soc_dai;
2108 int stream;
2109
2110 adr_end = &adr_dev->endpoints[j];
2111 dai_info = &codec_info->dais[adr_end->num];
2112 soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end);
2113
2114 /*
2115 * quirk should have higher priority than the sdca properties
2116 * in the BIOS. We can't always check the DAI quirk because we
2117 * will set the mc_quirk when the BIOS doesn't provide the right
2118 * information. The endpoint will be skipped if the dai_info->
2119 * quirk_exclude and mc_quirk are both not set if we always skip
2120 * the endpoint according to the quirk information. We need to
2121 * keep the endpoint if it is present in the BIOS. So, only
2122 * check the DAI quirk when the mc_quirk is set or SDCA endpoint
2123 * present check is not needed.
2124 */
2125 if (dai_info->quirk & ctx->mc_quirk || !check_sdca) {
2126 /*
2127 * Check the endpoint if a matching quirk is set or SDCA
2128 * endpoint check is not necessary
2129 */
2130 if (dai_info->quirk &&
2131 !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) {
2132 (*num_devs)--;
2133 continue;
2134 }
2135 } else {
2136 /* Check SDCA codec endpoint if there is no matching quirk */
2137 ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j);
2138 if (ret < 0)
2139 return ret;
2140
2141 /* The endpoint is not present, skip */
2142 if (!ret) {
2143 (*num_devs)--;
2144 continue;
2145 }
2146 }
2147
2148 dev_dbg(dev,
2149 "Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n",
2150 ffs(adr_link->mask) - 1, adr_dev->adr,
2151 adr_end->num, dai_info->dai_type,
2152 dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
2153 dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
2154 adr_end->aggregated ? "group" : "solo",
2155 adr_end->group_id);
2156
2157 if (adr_end->num >= codec_info->dai_num) {
2158 dev_err(dev,
2159 "%d is too many endpoints for codec: 0x%x\n",
2160 adr_end->num, codec_info->part_id);
2161 return -EINVAL;
2162 }
2163
2164 for_each_pcm_streams(stream) {
2165 if (dai_info->direction[stream] &&
2166 dai_info->dailink[stream] < 0) {
2167 dev_err(dev,
2168 "Invalid dailink id %d for codec: 0x%x\n",
2169 dai_info->dailink[stream],
2170 codec_info->part_id);
2171 return -EINVAL;
2172 }
2173
2174 if (dai_info->direction[stream]) {
2175 num_dais += !soc_dai->num_devs[stream];
2176 soc_dai->num_devs[stream]++;
2177 soc_dai->link_mask[stream] |= adr_link->mask;
2178 }
2179 }
2180
2181 num_link_dailinks += !!list_empty(&soc_dai->endpoints);
2182 list_add_tail(&soc_end->list, &soc_dai->endpoints);
2183
2184 codec_name = asoc_sdw_get_codec_name(dev, dai_info,
2185 adr_link, i);
2186 if (IS_ERR(codec_name))
2187 return PTR_ERR(codec_name);
2188 if (!codec_name)
2189 return -ENOMEM;
2190
2191 dev_dbg(dev, "Adding prefix %s for %s\n",
2192 adr_dev->name_prefix, codec_name);
2193
2194 soc_end->name_prefix = adr_dev->name_prefix;
2195
2196 soc_end->link_mask = adr_link->mask;
2197 soc_end->codec_name = codec_name;
2198 soc_end->codec_info = codec_info;
2199 soc_end->dai_info = dai_info;
2200 soc_end++;
2201 }
2202 }
2203
2204 ctx->append_dai_type |= (num_link_dailinks > 1);
2205 }
2206
2207 return num_dais;
2208 }
2209 EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS");
2210
2211 MODULE_LICENSE("GPL");
2212 MODULE_DESCRIPTION("SoundWire ASoC helpers");
2213