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