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