xref: /linux/sound/soc/sdw_utils/soc_sdw_utils.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
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 maxim_widgets[] = {
39 	SND_SOC_DAPM_SPK("Left Spk", NULL),
40 	SND_SOC_DAPM_SPK("Right Spk", NULL),
41 };
42 
43 static const struct snd_kcontrol_new maxim_controls[] = {
44 	SOC_DAPM_PIN_SWITCH("Left Spk"),
45 	SOC_DAPM_PIN_SWITCH("Right Spk"),
46 };
47 
48 static const struct snd_soc_dapm_widget rt700_widgets[] = {
49 	SND_SOC_DAPM_HP("Headphones", NULL),
50 	SND_SOC_DAPM_MIC("AMIC", NULL),
51 	SND_SOC_DAPM_SPK("Speaker", NULL),
52 };
53 
54 static const struct snd_kcontrol_new rt700_controls[] = {
55 	SOC_DAPM_PIN_SWITCH("Headphones"),
56 	SOC_DAPM_PIN_SWITCH("AMIC"),
57 	SOC_DAPM_PIN_SWITCH("Speaker"),
58 };
59 
60 struct asoc_sdw_codec_info codec_info_list[] = {
61 	{
62 		.part_id = 0x700,
63 		.dais = {
64 			{
65 				.direction = {true, true},
66 				.dai_name = "rt700-aif1",
67 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
68 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
69 				.rtd_init = asoc_sdw_rt700_rtd_init,
70 				.controls = rt700_controls,
71 				.num_controls = ARRAY_SIZE(rt700_controls),
72 				.widgets = rt700_widgets,
73 				.num_widgets = ARRAY_SIZE(rt700_widgets),
74 			},
75 		},
76 		.dai_num = 1,
77 	},
78 	{
79 		.part_id = 0x711,
80 		.version_id = 3,
81 		.dais = {
82 			{
83 				.direction = {true, true},
84 				.dai_name = "rt711-sdca-aif1",
85 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
86 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
87 				.init = asoc_sdw_rt_sdca_jack_init,
88 				.exit = asoc_sdw_rt_sdca_jack_exit,
89 				.rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
90 				.controls = generic_jack_controls,
91 				.num_controls = ARRAY_SIZE(generic_jack_controls),
92 				.widgets = generic_jack_widgets,
93 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
94 			},
95 		},
96 		.dai_num = 1,
97 	},
98 	{
99 		.part_id = 0x711,
100 		.version_id = 2,
101 		.dais = {
102 			{
103 				.direction = {true, true},
104 				.dai_name = "rt711-aif1",
105 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
106 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
107 				.init = asoc_sdw_rt711_init,
108 				.exit = asoc_sdw_rt711_exit,
109 				.rtd_init = asoc_sdw_rt711_rtd_init,
110 				.controls = generic_jack_controls,
111 				.num_controls = ARRAY_SIZE(generic_jack_controls),
112 				.widgets = generic_jack_widgets,
113 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
114 			},
115 		},
116 		.dai_num = 1,
117 	},
118 	{
119 		.part_id = 0x712,
120 		.version_id = 3,
121 		.dais =	{
122 			{
123 				.direction = {true, true},
124 				.dai_name = "rt712-sdca-aif1",
125 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
126 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
127 				.init = asoc_sdw_rt_sdca_jack_init,
128 				.exit = asoc_sdw_rt_sdca_jack_exit,
129 				.rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
130 				.controls = generic_jack_controls,
131 				.num_controls = ARRAY_SIZE(generic_jack_controls),
132 				.widgets = generic_jack_widgets,
133 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
134 			},
135 			{
136 				.direction = {true, false},
137 				.dai_name = "rt712-sdca-aif2",
138 				.component_name = "rt712",
139 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
140 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
141 				.init = asoc_sdw_rt_amp_init,
142 				.exit = asoc_sdw_rt_amp_exit,
143 				.rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
144 				.controls = generic_spk_controls,
145 				.num_controls = ARRAY_SIZE(generic_spk_controls),
146 				.widgets = generic_spk_widgets,
147 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
148 			},
149 			{
150 				.direction = {false, true},
151 				.dai_name = "rt712-sdca-aif3",
152 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
153 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
154 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
155 			},
156 		},
157 		.dai_num = 3,
158 	},
159 	{
160 		.part_id = 0x1712,
161 		.version_id = 3,
162 		.dais =	{
163 			{
164 				.direction = {false, true},
165 				.dai_name = "rt712-sdca-dmic-aif1",
166 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
167 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
168 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
169 			},
170 		},
171 		.dai_num = 1,
172 	},
173 	{
174 		.part_id = 0x713,
175 		.version_id = 3,
176 		.dais =	{
177 			{
178 				.direction = {true, true},
179 				.dai_name = "rt712-sdca-aif1",
180 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
181 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
182 				.init = asoc_sdw_rt_sdca_jack_init,
183 				.exit = asoc_sdw_rt_sdca_jack_exit,
184 				.rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
185 				.controls = generic_jack_controls,
186 				.num_controls = ARRAY_SIZE(generic_jack_controls),
187 				.widgets = generic_jack_widgets,
188 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
189 			},
190 			{
191 				.direction = {false, true},
192 				.dai_name = "rt712-sdca-aif3",
193 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
194 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
195 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
196 			},
197 		},
198 		.dai_num = 2,
199 	},
200 	{
201 		.part_id = 0x1713,
202 		.version_id = 3,
203 		.dais =	{
204 			{
205 				.direction = {false, true},
206 				.dai_name = "rt712-sdca-dmic-aif1",
207 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
208 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
209 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
210 			},
211 		},
212 		.dai_num = 1,
213 	},
214 	{
215 		.part_id = 0x1308,
216 		.acpi_id = "10EC1308",
217 		.dais = {
218 			{
219 				.direction = {true, false},
220 				.dai_name = "rt1308-aif",
221 				.component_name = "rt1308",
222 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
223 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
224 				.init = asoc_sdw_rt_amp_init,
225 				.exit = asoc_sdw_rt_amp_exit,
226 				.rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
227 				.controls = generic_spk_controls,
228 				.num_controls = ARRAY_SIZE(generic_spk_controls),
229 				.widgets = generic_spk_widgets,
230 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
231 			},
232 		},
233 		.dai_num = 1,
234 		.ops = &soc_sdw_rt1308_i2s_ops,
235 	},
236 	{
237 		.part_id = 0x1316,
238 		.dais = {
239 			{
240 				.direction = {true, true},
241 				.dai_name = "rt1316-aif",
242 				.component_name = "rt1316",
243 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
244 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
245 				.init = asoc_sdw_rt_amp_init,
246 				.exit = asoc_sdw_rt_amp_exit,
247 				.rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
248 				.controls = generic_spk_controls,
249 				.num_controls = ARRAY_SIZE(generic_spk_controls),
250 				.widgets = generic_spk_widgets,
251 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
252 			},
253 		},
254 		.dai_num = 1,
255 	},
256 	{
257 		.part_id = 0x1318,
258 		.dais = {
259 			{
260 				.direction = {true, true},
261 				.dai_name = "rt1318-aif",
262 				.component_name = "rt1318",
263 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
264 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
265 				.init = asoc_sdw_rt_amp_init,
266 				.exit = asoc_sdw_rt_amp_exit,
267 				.rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
268 				.controls = generic_spk_controls,
269 				.num_controls = ARRAY_SIZE(generic_spk_controls),
270 				.widgets = generic_spk_widgets,
271 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
272 			},
273 		},
274 		.dai_num = 1,
275 	},
276 	{
277 		.part_id = 0x1320,
278 		.dais = {
279 			{
280 				.direction = {true, false},
281 				.dai_name = "rt1320-aif1",
282 				.component_name = "rt1320",
283 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
284 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
285 				.init = asoc_sdw_rt_amp_init,
286 				.exit = asoc_sdw_rt_amp_exit,
287 				.rtd_init = asoc_sdw_rt_amp_spk_rtd_init,
288 				.controls = generic_spk_controls,
289 				.num_controls = ARRAY_SIZE(generic_spk_controls),
290 				.widgets = generic_spk_widgets,
291 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
292 			},
293 		},
294 		.dai_num = 1,
295 	},
296 	{
297 		.part_id = 0x714,
298 		.version_id = 3,
299 		.ignore_internal_dmic = true,
300 		.dais = {
301 			{
302 				.direction = {false, true},
303 				.dai_name = "rt715-sdca-aif2",
304 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
305 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
306 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
307 			},
308 		},
309 		.dai_num = 1,
310 	},
311 	{
312 		.part_id = 0x715,
313 		.version_id = 3,
314 		.ignore_internal_dmic = true,
315 		.dais = {
316 			{
317 				.direction = {false, true},
318 				.dai_name = "rt715-sdca-aif2",
319 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
320 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
321 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
322 			},
323 		},
324 		.dai_num = 1,
325 	},
326 	{
327 		.part_id = 0x714,
328 		.version_id = 2,
329 		.ignore_internal_dmic = true,
330 		.dais = {
331 			{
332 				.direction = {false, true},
333 				.dai_name = "rt715-aif2",
334 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
335 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
336 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
337 			},
338 		},
339 		.dai_num = 1,
340 	},
341 	{
342 		.part_id = 0x715,
343 		.version_id = 2,
344 		.ignore_internal_dmic = true,
345 		.dais = {
346 			{
347 				.direction = {false, true},
348 				.dai_name = "rt715-aif2",
349 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
350 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
351 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
352 			},
353 		},
354 		.dai_num = 1,
355 	},
356 	{
357 		.part_id = 0x721,
358 		.version_id = 3,
359 		.dais = {
360 			{
361 				.direction = {true, true},
362 				.dai_name = "rt721-sdca-aif1",
363 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
364 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
365 				.init = asoc_sdw_rt_sdca_jack_init,
366 				.exit = asoc_sdw_rt_sdca_jack_exit,
367 				.rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
368 				.controls = generic_jack_controls,
369 				.num_controls = ARRAY_SIZE(generic_jack_controls),
370 				.widgets = generic_jack_widgets,
371 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
372 			},
373 			{
374 				.direction = {true, false},
375 				.dai_name = "rt721-sdca-aif2",
376 				.component_name = "rt721",
377 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
378 				/* No feedback capability is provided by rt721-sdca codec driver*/
379 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
380 				.init = asoc_sdw_rt_amp_init,
381 				.exit = asoc_sdw_rt_amp_exit,
382 				.rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
383 				.controls = generic_spk_controls,
384 				.num_controls = ARRAY_SIZE(generic_spk_controls),
385 				.widgets = generic_spk_widgets,
386 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
387 			},
388 			{
389 				.direction = {false, true},
390 				.dai_name = "rt721-sdca-aif3",
391 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
392 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
393 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
394 			},
395 		},
396 		.dai_num = 3,
397 	},
398 	{
399 		.part_id = 0x722,
400 		.version_id = 3,
401 		.dais = {
402 			{
403 				.direction = {true, true},
404 				.dai_name = "rt722-sdca-aif1",
405 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
406 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
407 				.init = asoc_sdw_rt_sdca_jack_init,
408 				.exit = asoc_sdw_rt_sdca_jack_exit,
409 				.rtd_init = asoc_sdw_rt_sdca_jack_rtd_init,
410 				.controls = generic_jack_controls,
411 				.num_controls = ARRAY_SIZE(generic_jack_controls),
412 				.widgets = generic_jack_widgets,
413 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
414 			},
415 			{
416 				.direction = {true, false},
417 				.dai_name = "rt722-sdca-aif2",
418 				.component_name = "rt722",
419 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
420 				/* No feedback capability is provided by rt722-sdca codec driver*/
421 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
422 				.init = asoc_sdw_rt_amp_init,
423 				.exit = asoc_sdw_rt_amp_exit,
424 				.rtd_init = asoc_sdw_rt_mf_sdca_spk_rtd_init,
425 				.controls = generic_spk_controls,
426 				.num_controls = ARRAY_SIZE(generic_spk_controls),
427 				.widgets = generic_spk_widgets,
428 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
429 				.quirk = SOC_SDW_CODEC_SPKR,
430 				.quirk_exclude = true,
431 			},
432 			{
433 				.direction = {false, true},
434 				.dai_name = "rt722-sdca-aif3",
435 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
436 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
437 				.rtd_init = asoc_sdw_rt_dmic_rtd_init,
438 			},
439 		},
440 		.dai_num = 3,
441 	},
442 	{
443 		.part_id = 0x8373,
444 		.dais = {
445 			{
446 				.direction = {true, true},
447 				.dai_name = "max98373-aif1",
448 				.component_name = "mx8373",
449 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
450 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
451 				.init = asoc_sdw_maxim_init,
452 				.rtd_init = asoc_sdw_maxim_spk_rtd_init,
453 				.controls = maxim_controls,
454 				.num_controls = ARRAY_SIZE(maxim_controls),
455 				.widgets = maxim_widgets,
456 				.num_widgets = ARRAY_SIZE(maxim_widgets),
457 			},
458 		},
459 		.dai_num = 1,
460 	},
461 	{
462 		.part_id = 0x8363,
463 		.dais = {
464 			{
465 				.direction = {true, false},
466 				.dai_name = "max98363-aif1",
467 				.component_name = "mx8363",
468 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
469 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
470 				.init = asoc_sdw_maxim_init,
471 				.rtd_init = asoc_sdw_maxim_spk_rtd_init,
472 				.controls = maxim_controls,
473 				.num_controls = ARRAY_SIZE(maxim_controls),
474 				.widgets = maxim_widgets,
475 				.num_widgets = ARRAY_SIZE(maxim_widgets),
476 			},
477 		},
478 		.dai_num = 1,
479 	},
480 	{
481 		.part_id = 0x5682,
482 		.dais = {
483 			{
484 				.direction = {true, true},
485 				.dai_name = "rt5682-sdw",
486 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
487 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
488 				.rtd_init = asoc_sdw_rt5682_rtd_init,
489 				.controls = generic_jack_controls,
490 				.num_controls = ARRAY_SIZE(generic_jack_controls),
491 				.widgets = generic_jack_widgets,
492 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
493 			},
494 		},
495 		.dai_num = 1,
496 	},
497 	{
498 		.part_id = 0x3556,
499 		.dais = {
500 			{
501 				.direction = {true, false},
502 				.dai_name = "cs35l56-sdw1",
503 				.component_name = "cs35l56",
504 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
505 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
506 				.init = asoc_sdw_cs_amp_init,
507 				.rtd_init = asoc_sdw_cs_spk_rtd_init,
508 				.controls = generic_spk_controls,
509 				.num_controls = ARRAY_SIZE(generic_spk_controls),
510 				.widgets = generic_spk_widgets,
511 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
512 			},
513 			{
514 				.direction = {false, true},
515 				.dai_name = "cs35l56-sdw1c",
516 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
517 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
518 				.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
519 			},
520 		},
521 		.dai_num = 2,
522 	},
523 	{
524 		.part_id = 0x3563,
525 		.dais = {
526 			{
527 				.direction = {true, false},
528 				.dai_name = "cs35l56-sdw1",
529 				.component_name = "cs35l56",
530 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
531 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
532 				.init = asoc_sdw_cs_amp_init,
533 				.rtd_init = asoc_sdw_cs_spk_rtd_init,
534 				.controls = generic_spk_controls,
535 				.num_controls = ARRAY_SIZE(generic_spk_controls),
536 				.widgets = generic_spk_widgets,
537 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
538 			},
539 			{
540 				.direction = {false, true},
541 				.dai_name = "cs35l56-sdw1c",
542 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
543 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
544 				.rtd_init = asoc_sdw_cs_spk_feedback_rtd_init,
545 			},
546 		},
547 		.dai_num = 2,
548 	},
549 	{
550 		.part_id = 0x4242,
551 		.dais = {
552 			{
553 				.direction = {true, true},
554 				.dai_name = "cs42l42-sdw",
555 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
556 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
557 				.rtd_init = asoc_sdw_cs42l42_rtd_init,
558 				.controls = generic_jack_controls,
559 				.num_controls = ARRAY_SIZE(generic_jack_controls),
560 				.widgets = generic_jack_widgets,
561 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
562 			},
563 		},
564 		.dai_num = 1,
565 	},
566 	{
567 		.part_id = 0x4243,
568 		.codec_name = "cs42l43-codec",
569 		.count_sidecar = asoc_sdw_bridge_cs35l56_count_sidecar,
570 		.add_sidecar = asoc_sdw_bridge_cs35l56_add_sidecar,
571 		.dais = {
572 			{
573 				.direction = {true, false},
574 				.dai_name = "cs42l43-dp5",
575 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
576 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
577 				.rtd_init = asoc_sdw_cs42l43_hs_rtd_init,
578 				.controls = generic_jack_controls,
579 				.num_controls = ARRAY_SIZE(generic_jack_controls),
580 				.widgets = generic_jack_widgets,
581 				.num_widgets = ARRAY_SIZE(generic_jack_widgets),
582 			},
583 			{
584 				.direction = {false, true},
585 				.dai_name = "cs42l43-dp1",
586 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
587 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
588 				.rtd_init = asoc_sdw_cs42l43_dmic_rtd_init,
589 				.widgets = generic_dmic_widgets,
590 				.num_widgets = ARRAY_SIZE(generic_dmic_widgets),
591 				.quirk = SOC_SDW_CODEC_MIC,
592 				.quirk_exclude = true,
593 			},
594 			{
595 				.direction = {false, true},
596 				.dai_name = "cs42l43-dp2",
597 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
598 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
599 			},
600 			{
601 				.direction = {true, false},
602 				.dai_name = "cs42l43-dp6",
603 				.component_name = "cs42l43",
604 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
605 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
606 				.init = asoc_sdw_cs42l43_spk_init,
607 				.rtd_init = asoc_sdw_cs42l43_spk_rtd_init,
608 				.controls = generic_spk_controls,
609 				.num_controls = ARRAY_SIZE(generic_spk_controls),
610 				.widgets = generic_spk_widgets,
611 				.num_widgets = ARRAY_SIZE(generic_spk_widgets),
612 				.quirk = SOC_SDW_CODEC_SPKR | SOC_SDW_SIDECAR_AMPS,
613 			},
614 		},
615 		.dai_num = 4,
616 	},
617 	{
618 		.part_id = 0xaaaa, /* generic codec mockup */
619 		.version_id = 0,
620 		.dais = {
621 			{
622 				.direction = {true, true},
623 				.dai_name = "sdw-mockup-aif1",
624 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
625 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
626 			},
627 			{
628 				.direction = {true, false},
629 				.dai_name = "sdw-mockup-aif1",
630 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
631 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID},
632 			},
633 			{
634 				.direction = {false, true},
635 				.dai_name = "sdw-mockup-aif1",
636 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
637 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
638 			},
639 		},
640 		.dai_num = 3,
641 	},
642 	{
643 		.part_id = 0xaa55, /* headset codec mockup */
644 		.version_id = 0,
645 		.dais = {
646 			{
647 				.direction = {true, true},
648 				.dai_name = "sdw-mockup-aif1",
649 				.dai_type = SOC_SDW_DAI_TYPE_JACK,
650 				.dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID},
651 			},
652 		},
653 		.dai_num = 1,
654 	},
655 	{
656 		.part_id = 0x55aa, /* amplifier mockup */
657 		.version_id = 0,
658 		.dais = {
659 			{
660 				.direction = {true, true},
661 				.dai_name = "sdw-mockup-aif1",
662 				.dai_type = SOC_SDW_DAI_TYPE_AMP,
663 				.dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID},
664 			},
665 		},
666 		.dai_num = 1,
667 	},
668 	{
669 		.part_id = 0x5555,
670 		.version_id = 0,
671 		.dais = {
672 			{
673 				.dai_name = "sdw-mockup-aif1",
674 				.direction = {false, true},
675 				.dai_type = SOC_SDW_DAI_TYPE_MIC,
676 				.dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID},
677 			},
678 		},
679 		.dai_num = 1,
680 	},
681 };
682 EXPORT_SYMBOL_NS(codec_info_list, "SND_SOC_SDW_UTILS");
683 
asoc_sdw_get_codec_info_list_count(void)684 int asoc_sdw_get_codec_info_list_count(void)
685 {
686 	return ARRAY_SIZE(codec_info_list);
687 };
688 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_info_list_count, "SND_SOC_SDW_UTILS");
689 
asoc_sdw_find_codec_info_part(const u64 adr)690 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr)
691 {
692 	unsigned int part_id, sdw_version;
693 	int i;
694 
695 	part_id = SDW_PART_ID(adr);
696 	sdw_version = SDW_VERSION(adr);
697 	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
698 		/*
699 		 * A codec info is for all sdw version with the part id if
700 		 * version_id is not specified in the codec info.
701 		 */
702 		if (part_id == codec_info_list[i].part_id &&
703 		    (!codec_info_list[i].version_id ||
704 		     sdw_version == codec_info_list[i].version_id))
705 			return &codec_info_list[i];
706 
707 	return NULL;
708 }
709 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_part, "SND_SOC_SDW_UTILS");
710 
asoc_sdw_find_codec_info_acpi(const u8 * acpi_id)711 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id)
712 {
713 	int i;
714 
715 	if (!acpi_id[0])
716 		return NULL;
717 
718 	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
719 		if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN))
720 			return &codec_info_list[i];
721 
722 	return NULL;
723 }
724 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_acpi, "SND_SOC_SDW_UTILS");
725 
asoc_sdw_find_codec_info_dai(const char * dai_name,int * dai_index)726 struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name, int *dai_index)
727 {
728 	int i, j;
729 
730 	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
731 		for (j = 0; j < codec_info_list[i].dai_num; j++) {
732 			if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) {
733 				*dai_index = j;
734 				return &codec_info_list[i];
735 			}
736 		}
737 	}
738 
739 	return NULL;
740 }
741 EXPORT_SYMBOL_NS(asoc_sdw_find_codec_info_dai, "SND_SOC_SDW_UTILS");
742 
asoc_sdw_rtd_init(struct snd_soc_pcm_runtime * rtd)743 int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd)
744 {
745 	struct snd_soc_card *card = rtd->card;
746 	struct asoc_sdw_codec_info *codec_info;
747 	struct snd_soc_dai *dai;
748 	const char *spk_components="";
749 	int dai_index;
750 	int ret;
751 	int i;
752 
753 	for_each_rtd_codec_dais(rtd, i, dai) {
754 		codec_info = asoc_sdw_find_codec_info_dai(dai->name, &dai_index);
755 		if (!codec_info)
756 			return -EINVAL;
757 
758 		/*
759 		 * A codec dai can be connected to different dai links for capture and playback,
760 		 * but we only need to call the rtd_init function once.
761 		 * The rtd_init for each codec dai is independent. So, the order of rtd_init
762 		 * doesn't matter.
763 		 */
764 		if (codec_info->dais[dai_index].rtd_init_done)
765 			continue;
766 
767 		/*
768 		 * Add card controls and dapm widgets for the first codec dai.
769 		 * The controls and widgets will be used for all codec dais.
770 		 */
771 
772 		if (i > 0)
773 			goto skip_add_controls_widgets;
774 
775 		if (codec_info->dais[dai_index].controls) {
776 			ret = snd_soc_add_card_controls(card, codec_info->dais[dai_index].controls,
777 							codec_info->dais[dai_index].num_controls);
778 			if (ret) {
779 				dev_err(card->dev, "%#x controls addition failed: %d\n",
780 					codec_info->part_id, ret);
781 				return ret;
782 			}
783 		}
784 		if (codec_info->dais[dai_index].widgets) {
785 			ret = snd_soc_dapm_new_controls(&card->dapm,
786 							codec_info->dais[dai_index].widgets,
787 							codec_info->dais[dai_index].num_widgets);
788 			if (ret) {
789 				dev_err(card->dev, "%#x widgets addition failed: %d\n",
790 					codec_info->part_id, ret);
791 				return ret;
792 			}
793 		}
794 
795 skip_add_controls_widgets:
796 		if (codec_info->dais[dai_index].rtd_init) {
797 			ret = codec_info->dais[dai_index].rtd_init(rtd, dai);
798 			if (ret)
799 				return ret;
800 		}
801 
802 		/* Generate the spk component string for card->components string */
803 		if (codec_info->dais[dai_index].dai_type == SOC_SDW_DAI_TYPE_AMP &&
804 		    codec_info->dais[dai_index].component_name) {
805 			if (strlen (spk_components) == 0)
806 				spk_components =
807 					devm_kasprintf(card->dev, GFP_KERNEL, "%s",
808 						       codec_info->dais[dai_index].component_name);
809 			else
810 				/* Append component name to spk_components */
811 				spk_components =
812 					devm_kasprintf(card->dev, GFP_KERNEL,
813 						       "%s+%s", spk_components,
814 						       codec_info->dais[dai_index].component_name);
815 		}
816 
817 		codec_info->dais[dai_index].rtd_init_done = true;
818 
819 	}
820 
821 	if (strlen (spk_components) > 0) {
822 		/* Update card components for speaker components */
823 		card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s spk:%s",
824 						  card->components, spk_components);
825 		if (!card->components)
826 			return -ENOMEM;
827 	}
828 
829 	return 0;
830 }
831 EXPORT_SYMBOL_NS(asoc_sdw_rtd_init, "SND_SOC_SDW_UTILS");
832 
833 /* these wrappers are only needed to avoid typecast compilation errors */
asoc_sdw_startup(struct snd_pcm_substream * substream)834 int asoc_sdw_startup(struct snd_pcm_substream *substream)
835 {
836 	return sdw_startup_stream(substream);
837 }
838 EXPORT_SYMBOL_NS(asoc_sdw_startup, "SND_SOC_SDW_UTILS");
839 
asoc_sdw_prepare(struct snd_pcm_substream * substream)840 int asoc_sdw_prepare(struct snd_pcm_substream *substream)
841 {
842 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
843 	struct sdw_stream_runtime *sdw_stream;
844 	struct snd_soc_dai *dai;
845 
846 	/* Find stream from first CPU DAI */
847 	dai = snd_soc_rtd_to_cpu(rtd, 0);
848 
849 	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
850 	if (IS_ERR(sdw_stream)) {
851 		dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
852 		return PTR_ERR(sdw_stream);
853 	}
854 
855 	return sdw_prepare_stream(sdw_stream);
856 }
857 EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS");
858 
asoc_sdw_trigger(struct snd_pcm_substream * substream,int cmd)859 int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
860 {
861 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
862 	struct sdw_stream_runtime *sdw_stream;
863 	struct snd_soc_dai *dai;
864 	int ret;
865 
866 	/* Find stream from first CPU DAI */
867 	dai = snd_soc_rtd_to_cpu(rtd, 0);
868 
869 	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
870 	if (IS_ERR(sdw_stream)) {
871 		dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
872 		return PTR_ERR(sdw_stream);
873 	}
874 
875 	switch (cmd) {
876 	case SNDRV_PCM_TRIGGER_START:
877 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
878 	case SNDRV_PCM_TRIGGER_RESUME:
879 		ret = sdw_enable_stream(sdw_stream);
880 		break;
881 
882 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
883 	case SNDRV_PCM_TRIGGER_SUSPEND:
884 	case SNDRV_PCM_TRIGGER_STOP:
885 		ret = sdw_disable_stream(sdw_stream);
886 		break;
887 	default:
888 		ret = -EINVAL;
889 		break;
890 	}
891 
892 	if (ret)
893 		dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
894 
895 	return ret;
896 }
897 EXPORT_SYMBOL_NS(asoc_sdw_trigger, "SND_SOC_SDW_UTILS");
898 
asoc_sdw_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)899 int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
900 		       struct snd_pcm_hw_params *params)
901 {
902 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
903 	struct snd_soc_dai_link_ch_map *ch_maps;
904 	int ch = params_channels(params);
905 	unsigned int ch_mask;
906 	int num_codecs;
907 	int step;
908 	int i;
909 
910 	if (!rtd->dai_link->ch_maps)
911 		return 0;
912 
913 	/* Identical data will be sent to all codecs in playback */
914 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
915 		ch_mask = GENMASK(ch - 1, 0);
916 		step = 0;
917 	} else {
918 		num_codecs = rtd->dai_link->num_codecs;
919 
920 		if (ch < num_codecs || ch % num_codecs != 0) {
921 			dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
922 				ch, num_codecs);
923 			return -EINVAL;
924 		}
925 
926 		ch_mask = GENMASK(ch / num_codecs - 1, 0);
927 		step = hweight_long(ch_mask);
928 	}
929 
930 	/*
931 	 * The captured data will be combined from each cpu DAI if the dai
932 	 * link has more than one codec DAIs. Set codec channel mask and
933 	 * ASoC will set the corresponding channel numbers for each cpu dai.
934 	 */
935 	for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
936 		ch_maps->ch_mask = ch_mask << (i * step);
937 
938 	return 0;
939 }
940 EXPORT_SYMBOL_NS(asoc_sdw_hw_params, "SND_SOC_SDW_UTILS");
941 
asoc_sdw_hw_free(struct snd_pcm_substream * substream)942 int asoc_sdw_hw_free(struct snd_pcm_substream *substream)
943 {
944 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
945 	struct sdw_stream_runtime *sdw_stream;
946 	struct snd_soc_dai *dai;
947 
948 	/* Find stream from first CPU DAI */
949 	dai = snd_soc_rtd_to_cpu(rtd, 0);
950 
951 	sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
952 	if (IS_ERR(sdw_stream)) {
953 		dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
954 		return PTR_ERR(sdw_stream);
955 	}
956 
957 	return sdw_deprepare_stream(sdw_stream);
958 }
959 EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS");
960 
asoc_sdw_shutdown(struct snd_pcm_substream * substream)961 void asoc_sdw_shutdown(struct snd_pcm_substream *substream)
962 {
963 	sdw_shutdown_stream(substream);
964 }
965 EXPORT_SYMBOL_NS(asoc_sdw_shutdown, "SND_SOC_SDW_UTILS");
966 
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)967 static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_link,
968 				      unsigned int sdw_version,
969 				      unsigned int mfg_id,
970 				      unsigned int part_id,
971 				      unsigned int class_id,
972 				      int index_in_link)
973 {
974 	int i;
975 
976 	for (i = 0; i < adr_link->num_adr; i++) {
977 		unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
978 		u64 adr;
979 
980 		/* skip itself */
981 		if (i == index_in_link)
982 			continue;
983 
984 		adr = adr_link->adr_d[i].adr;
985 
986 		sdw1_version = SDW_VERSION(adr);
987 		mfg1_id = SDW_MFG_ID(adr);
988 		part1_id = SDW_PART_ID(adr);
989 		class1_id = SDW_CLASS_ID(adr);
990 
991 		if (sdw_version == sdw1_version &&
992 		    mfg_id == mfg1_id &&
993 		    part_id == part1_id &&
994 		    class_id == class1_id)
995 			return false;
996 	}
997 
998 	return true;
999 }
1000 
_asoc_sdw_get_codec_name(struct device * dev,const struct asoc_sdw_codec_info * codec_info,const struct snd_soc_acpi_link_adr * adr_link,int adr_index)1001 static const char *_asoc_sdw_get_codec_name(struct device *dev,
1002 					    const struct asoc_sdw_codec_info *codec_info,
1003 					    const struct snd_soc_acpi_link_adr *adr_link,
1004 					    int adr_index)
1005 {
1006 	u64 adr = adr_link->adr_d[adr_index].adr;
1007 	unsigned int sdw_version = SDW_VERSION(adr);
1008 	unsigned int link_id = SDW_DISCO_LINK_ID(adr);
1009 	unsigned int unique_id = SDW_UNIQUE_ID(adr);
1010 	unsigned int mfg_id = SDW_MFG_ID(adr);
1011 	unsigned int part_id = SDW_PART_ID(adr);
1012 	unsigned int class_id = SDW_CLASS_ID(adr);
1013 
1014 	if (asoc_sdw_is_unique_device(adr_link, sdw_version, mfg_id, part_id,
1015 				      class_id, adr_index))
1016 		return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x",
1017 				      link_id, mfg_id, part_id, class_id);
1018 
1019 	return devm_kasprintf(dev, GFP_KERNEL, "sdw:0:%01x:%04x:%04x:%02x:%01x",
1020 			      link_id, mfg_id, part_id, class_id, unique_id);
1021 }
1022 
asoc_sdw_get_codec_name(struct device * dev,const struct asoc_sdw_codec_info * codec_info,const struct snd_soc_acpi_link_adr * adr_link,int adr_index)1023 const char *asoc_sdw_get_codec_name(struct device *dev,
1024 				    const struct asoc_sdw_codec_info *codec_info,
1025 				    const struct snd_soc_acpi_link_adr *adr_link,
1026 				    int adr_index)
1027 {
1028 	if (codec_info->codec_name)
1029 		return devm_kstrdup(dev, codec_info->codec_name, GFP_KERNEL);
1030 
1031 	return _asoc_sdw_get_codec_name(dev, codec_info, adr_link, adr_index);
1032 }
1033 EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS");
1034 
1035 /* 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)1036 struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card,
1037 							 const char *dai_name)
1038 {
1039 	struct snd_soc_dai_link *dai_link;
1040 	int i;
1041 	int j;
1042 
1043 	for_each_card_prelinks(card, i, dai_link) {
1044 		for (j = 0; j < dai_link->num_codecs; j++) {
1045 			/* Check each codec in a link */
1046 			if (!strcmp(dai_link->codecs[j].dai_name, dai_name))
1047 				return dai_link;
1048 		}
1049 	}
1050 	return NULL;
1051 }
1052 EXPORT_SYMBOL_NS(asoc_sdw_mc_find_codec_dai_used, "SND_SOC_SDW_UTILS");
1053 
asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card * card)1054 void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card)
1055 {
1056 	struct snd_soc_dai_link *dai_link;
1057 	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1058 	int ret;
1059 	int i, j;
1060 
1061 	for (i = 0; i < ctx->codec_info_list_count; i++) {
1062 		for (j = 0; j < codec_info_list[i].dai_num; j++) {
1063 			codec_info_list[i].dais[j].rtd_init_done = false;
1064 			/* Check each dai in codec_info_lis to see if it is used in the link */
1065 			if (!codec_info_list[i].dais[j].exit)
1066 				continue;
1067 			/*
1068 			 * We don't need to call .exit function if there is no matched
1069 			 * dai link found.
1070 			 */
1071 			dai_link = asoc_sdw_mc_find_codec_dai_used(card,
1072 							  codec_info_list[i].dais[j].dai_name);
1073 			if (dai_link) {
1074 				/* Do the .exit function if the codec dai is used in the link */
1075 				ret = codec_info_list[i].dais[j].exit(card, dai_link);
1076 				if (ret)
1077 					dev_warn(card->dev,
1078 						 "codec exit failed %d\n",
1079 						 ret);
1080 				break;
1081 			}
1082 		}
1083 	}
1084 }
1085 EXPORT_SYMBOL_NS(asoc_sdw_mc_dailink_exit_loop, "SND_SOC_SDW_UTILS");
1086 
asoc_sdw_card_late_probe(struct snd_soc_card * card)1087 int asoc_sdw_card_late_probe(struct snd_soc_card *card)
1088 {
1089 	int ret = 0;
1090 	int i;
1091 
1092 	for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1093 		if (codec_info_list[i].codec_card_late_probe) {
1094 			ret = codec_info_list[i].codec_card_late_probe(card);
1095 			if (ret < 0)
1096 				return ret;
1097 		}
1098 	}
1099 	return ret;
1100 }
1101 EXPORT_SYMBOL_NS(asoc_sdw_card_late_probe, "SND_SOC_SDW_UTILS");
1102 
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)1103 void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1104 			    int *be_id, char *name, int playback, int capture,
1105 			    struct snd_soc_dai_link_component *cpus, int cpus_num,
1106 			    struct snd_soc_dai_link_component *platform_component,
1107 			    int num_platforms, struct snd_soc_dai_link_component *codecs,
1108 			    int codecs_num, int no_pcm,
1109 			    int (*init)(struct snd_soc_pcm_runtime *rtd),
1110 			    const struct snd_soc_ops *ops)
1111 {
1112 	dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id);
1113 	dai_links->id = (*be_id)++;
1114 	dai_links->name = name;
1115 	dai_links->stream_name = name;
1116 	dai_links->platforms = platform_component;
1117 	dai_links->num_platforms = num_platforms;
1118 	dai_links->no_pcm = no_pcm;
1119 	dai_links->cpus = cpus;
1120 	dai_links->num_cpus = cpus_num;
1121 	dai_links->codecs = codecs;
1122 	dai_links->num_codecs = codecs_num;
1123 	dai_links->playback_only =  playback && !capture;
1124 	dai_links->capture_only  = !playback &&  capture;
1125 	dai_links->init = init;
1126 	dai_links->ops = ops;
1127 }
1128 EXPORT_SYMBOL_NS(asoc_sdw_init_dai_link, "SND_SOC_SDW_UTILS");
1129 
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)1130 int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
1131 				  int *be_id, char *name, int playback, int capture,
1132 				  const char *cpu_dai_name, const char *platform_comp_name,
1133 				  const char *codec_name, const char *codec_dai_name,
1134 				  int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd),
1135 				  const struct snd_soc_ops *ops)
1136 {
1137 	struct snd_soc_dai_link_component *dlc;
1138 
1139 	/* Allocate three DLCs one for the CPU, one for platform and one for the CODEC */
1140 	dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL);
1141 	if (!dlc || !name || !cpu_dai_name || !platform_comp_name || !codec_name || !codec_dai_name)
1142 		return -ENOMEM;
1143 
1144 	dlc[0].dai_name = cpu_dai_name;
1145 	dlc[1].name = platform_comp_name;
1146 
1147 	dlc[2].name = codec_name;
1148 	dlc[2].dai_name = codec_dai_name;
1149 
1150 	asoc_sdw_init_dai_link(dev, dai_links, be_id, name, playback, capture,
1151 			       &dlc[0], 1, &dlc[1], 1, &dlc[2], 1,
1152 			       no_pcm, init, ops);
1153 
1154 	return 0;
1155 }
1156 EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS");
1157 
asoc_sdw_count_sdw_endpoints(struct snd_soc_card * card,int * num_devs,int * num_ends)1158 int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends)
1159 {
1160 	struct device *dev = card->dev;
1161 	struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
1162 	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1163 	const struct snd_soc_acpi_link_adr *adr_link;
1164 	int i;
1165 
1166 	for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
1167 		*num_devs += adr_link->num_adr;
1168 
1169 		for (i = 0; i < adr_link->num_adr; i++)
1170 			*num_ends += adr_link->adr_d[i].num_endpoints;
1171 	}
1172 
1173 	dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends);
1174 
1175 	return 0;
1176 }
1177 EXPORT_SYMBOL_NS(asoc_sdw_count_sdw_endpoints, "SND_SOC_SDW_UTILS");
1178 
asoc_sdw_find_dailink(struct asoc_sdw_dailink * dailinks,const struct snd_soc_acpi_endpoint * new)1179 struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
1180 					       const struct snd_soc_acpi_endpoint *new)
1181 {
1182 	while (dailinks->initialised) {
1183 		if (new->aggregated && dailinks->group_id == new->group_id)
1184 			return dailinks;
1185 
1186 		dailinks++;
1187 	}
1188 
1189 	INIT_LIST_HEAD(&dailinks->endpoints);
1190 	dailinks->group_id = new->group_id;
1191 	dailinks->initialised = true;
1192 
1193 	return dailinks;
1194 }
1195 EXPORT_SYMBOL_NS(asoc_sdw_find_dailink, "SND_SOC_SDW_UTILS");
1196 
asoc_sdw_get_dai_type(u32 type)1197 static int asoc_sdw_get_dai_type(u32 type)
1198 {
1199 	switch (type) {
1200 	case SDCA_FUNCTION_TYPE_SMART_AMP:
1201 	case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
1202 		return SOC_SDW_DAI_TYPE_AMP;
1203 	case SDCA_FUNCTION_TYPE_SMART_MIC:
1204 	case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
1205 	case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
1206 		return SOC_SDW_DAI_TYPE_MIC;
1207 	case SDCA_FUNCTION_TYPE_UAJ:
1208 	case SDCA_FUNCTION_TYPE_RJ:
1209 	case SDCA_FUNCTION_TYPE_SIMPLE_JACK:
1210 		return SOC_SDW_DAI_TYPE_JACK;
1211 	default:
1212 		return -EINVAL;
1213 	}
1214 }
1215 
1216 /*
1217  * Check if the SDCA endpoint is present by the SDW peripheral
1218  *
1219  * @dev: Device pointer
1220  * @codec_info: Codec info pointer
1221  * @adr_link: ACPI link address
1222  * @adr_index: Index of the ACPI link address
1223  * @end_index: Index of the endpoint
1224  *
1225  * Return: 1 if the endpoint is present,
1226  *	   0 if the endpoint is not present,
1227  *	   negative error code.
1228  */
1229 
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)1230 static int is_sdca_endpoint_present(struct device *dev,
1231 				    struct asoc_sdw_codec_info *codec_info,
1232 				    const struct snd_soc_acpi_link_adr *adr_link,
1233 				    int adr_index, int end_index)
1234 {
1235 	const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[adr_index];
1236 	const struct snd_soc_acpi_endpoint *adr_end;
1237 	const struct asoc_sdw_dai_info *dai_info;
1238 	struct snd_soc_dai_link_component *dlc;
1239 	struct snd_soc_dai *codec_dai;
1240 	struct sdw_slave *slave;
1241 	struct device *sdw_dev;
1242 	const char *sdw_codec_name;
1243 	int i;
1244 
1245 	dlc = kzalloc(sizeof(*dlc), GFP_KERNEL);
1246 	if (!dlc)
1247 		return -ENOMEM;
1248 
1249 	adr_end = &adr_dev->endpoints[end_index];
1250 	dai_info = &codec_info->dais[adr_end->num];
1251 
1252 	dlc->dai_name = dai_info->dai_name;
1253 	codec_dai = snd_soc_find_dai_with_mutex(dlc);
1254 	if (!codec_dai) {
1255 		dev_warn(dev, "codec dai %s not registered yet\n", dlc->dai_name);
1256 		kfree(dlc);
1257 		return -EPROBE_DEFER;
1258 	}
1259 	kfree(dlc);
1260 
1261 	sdw_codec_name = _asoc_sdw_get_codec_name(dev, codec_info,
1262 						  adr_link, adr_index);
1263 	if (!sdw_codec_name)
1264 		return -ENOMEM;
1265 
1266 	sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
1267 	if (!sdw_dev) {
1268 		dev_err(dev, "codec %s not found\n", sdw_codec_name);
1269 		return -EINVAL;
1270 	}
1271 
1272 	slave = dev_to_sdw_dev(sdw_dev);
1273 	if (!slave)
1274 		return -EINVAL;
1275 
1276 	/* Make sure BIOS provides SDCA properties */
1277 	if (!slave->sdca_data.interface_revision) {
1278 		dev_warn(&slave->dev, "SDCA properties not found in the BIOS\n");
1279 		return 1;
1280 	}
1281 
1282 	for (i = 0; i < slave->sdca_data.num_functions; i++) {
1283 		int dai_type = asoc_sdw_get_dai_type(slave->sdca_data.function[i].type);
1284 
1285 		if (dai_type == dai_info->dai_type) {
1286 			dev_dbg(&slave->dev, "DAI type %d sdca function %s found\n",
1287 				dai_type, slave->sdca_data.function[i].name);
1288 			return 1;
1289 		}
1290 	}
1291 
1292 	dev_dbg(&slave->dev,
1293 		"SDCA device function for DAI type %d not supported, skip endpoint\n",
1294 		dai_info->dai_type);
1295 
1296 	return 0;
1297 }
1298 
asoc_sdw_parse_sdw_endpoints(struct snd_soc_card * card,struct asoc_sdw_dailink * soc_dais,struct asoc_sdw_endpoint * soc_ends,int * num_devs)1299 int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
1300 				 struct asoc_sdw_dailink *soc_dais,
1301 				 struct asoc_sdw_endpoint *soc_ends,
1302 				 int *num_devs)
1303 {
1304 	struct device *dev = card->dev;
1305 	struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card);
1306 	struct snd_soc_acpi_mach *mach = dev_get_platdata(dev);
1307 	struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
1308 	const struct snd_soc_acpi_link_adr *adr_link;
1309 	struct asoc_sdw_endpoint *soc_end = soc_ends;
1310 	int num_dais = 0;
1311 	int i, j;
1312 	int ret;
1313 
1314 	for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) {
1315 		int num_link_dailinks = 0;
1316 
1317 		if (!is_power_of_2(adr_link->mask)) {
1318 			dev_err(dev, "link with multiple mask bits: 0x%x\n",
1319 				adr_link->mask);
1320 			return -EINVAL;
1321 		}
1322 
1323 		for (i = 0; i < adr_link->num_adr; i++) {
1324 			const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i];
1325 			struct asoc_sdw_codec_info *codec_info;
1326 			const char *codec_name;
1327 			bool check_sdca = false;
1328 
1329 			if (!adr_dev->name_prefix) {
1330 				dev_err(dev, "codec 0x%llx does not have a name prefix\n",
1331 					adr_dev->adr);
1332 				return -EINVAL;
1333 			}
1334 
1335 			codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr);
1336 			if (!codec_info)
1337 				return -EINVAL;
1338 
1339 			ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic;
1340 
1341 			codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i);
1342 			if (!codec_name)
1343 				return -ENOMEM;
1344 
1345 			dev_dbg(dev, "Adding prefix %s for %s\n",
1346 				adr_dev->name_prefix, codec_name);
1347 
1348 			soc_end->name_prefix = adr_dev->name_prefix;
1349 
1350 			if (codec_info->count_sidecar && codec_info->add_sidecar) {
1351 				ret = codec_info->count_sidecar(card, &num_dais, num_devs);
1352 				if (ret)
1353 					return ret;
1354 
1355 				soc_end->include_sidecar = true;
1356 			}
1357 
1358 			if (SDW_CLASS_ID(adr_dev->adr) && adr_dev->num_endpoints > 1)
1359 				check_sdca = true;
1360 
1361 			for (j = 0; j < adr_dev->num_endpoints; j++) {
1362 				const struct snd_soc_acpi_endpoint *adr_end;
1363 				const struct asoc_sdw_dai_info *dai_info;
1364 				struct asoc_sdw_dailink *soc_dai;
1365 				int stream;
1366 
1367 				adr_end = &adr_dev->endpoints[j];
1368 				dai_info = &codec_info->dais[adr_end->num];
1369 				soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end);
1370 
1371 				/*
1372 				 * quirk should have higher priority than the sdca properties
1373 				 * in the BIOS. We can't always check the DAI quirk because we
1374 				 * will set the mc_quirk when the BIOS doesn't provide the right
1375 				 * information. The endpoint will be skipped if the dai_info->
1376 				 * quirk_exclude and mc_quirk are both not set if we always skip
1377 				 * the endpoint according to the quirk information. We need to
1378 				 * keep the endpoint if it is present in the BIOS. So, only
1379 				 * check the DAI quirk when the mc_quirk is set or SDCA endpoint
1380 				 * present check is not needed.
1381 				 */
1382 				if (dai_info->quirk & ctx->mc_quirk || !check_sdca) {
1383 					/*
1384 					 * Check the endpoint if a matching quirk is set or SDCA
1385 					 * endpoint check is not necessary
1386 					 */
1387 					if (dai_info->quirk &&
1388 					    !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk)))
1389 						continue;
1390 				} else {
1391 					/* Check SDCA codec endpoint if there is no matching quirk */
1392 					ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j);
1393 					if (ret < 0)
1394 						return ret;
1395 
1396 					/* The endpoint is not present, skip */
1397 					if (!ret)
1398 						continue;
1399 				}
1400 
1401 				dev_dbg(dev,
1402 					"Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n",
1403 					ffs(adr_link->mask) - 1, adr_dev->adr,
1404 					adr_end->num, dai_info->dai_type,
1405 					dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
1406 					dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
1407 					adr_end->aggregated ? "group" : "solo",
1408 					adr_end->group_id);
1409 
1410 				if (adr_end->num >= codec_info->dai_num) {
1411 					dev_err(dev,
1412 						"%d is too many endpoints for codec: 0x%x\n",
1413 						adr_end->num, codec_info->part_id);
1414 					return -EINVAL;
1415 				}
1416 
1417 				for_each_pcm_streams(stream) {
1418 					if (dai_info->direction[stream] &&
1419 					    dai_info->dailink[stream] < 0) {
1420 						dev_err(dev,
1421 							"Invalid dailink id %d for codec: 0x%x\n",
1422 							dai_info->dailink[stream],
1423 							codec_info->part_id);
1424 						return -EINVAL;
1425 					}
1426 
1427 					if (dai_info->direction[stream]) {
1428 						num_dais += !soc_dai->num_devs[stream];
1429 						soc_dai->num_devs[stream]++;
1430 						soc_dai->link_mask[stream] |= adr_link->mask;
1431 					}
1432 				}
1433 
1434 				num_link_dailinks += !!list_empty(&soc_dai->endpoints);
1435 				list_add_tail(&soc_end->list, &soc_dai->endpoints);
1436 
1437 				soc_end->link_mask = adr_link->mask;
1438 				soc_end->codec_name = codec_name;
1439 				soc_end->codec_info = codec_info;
1440 				soc_end->dai_info = dai_info;
1441 				soc_end++;
1442 			}
1443 		}
1444 
1445 		ctx->append_dai_type |= (num_link_dailinks > 1);
1446 	}
1447 
1448 	return num_dais;
1449 }
1450 EXPORT_SYMBOL_NS(asoc_sdw_parse_sdw_endpoints, "SND_SOC_SDW_UTILS");
1451 
1452 MODULE_LICENSE("GPL");
1453 MODULE_DESCRIPTION("SoundWire ASoC helpers");
1454