xref: /linux/sound/soc/sdw_utils/soc_sdw_utils.c (revision b5b00a57868b1eabdf90a29a51f0eb732c609f3a)
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 
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 
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 
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 
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 
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 
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 
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 */
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 
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 
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 
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 
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 
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 
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 
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 
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 */
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 
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 
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 
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 
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  */
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 
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 
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 
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  */
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 
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