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