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