1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2020 Intel Corporation
3
4 /*
5 * sof_sdw - ASOC Machine driver for Intel SoundWire platforms
6 */
7
8 #include <linux/device.h>
9 #include <linux/dmi.h>
10 #include <linux/module.h>
11 #include <linux/soundwire/sdw.h>
12 #include <linux/soundwire/sdw_type.h>
13 #include <sound/soc.h>
14 #include <sound/soc-acpi.h>
15 #include "sof_sdw_common.h"
16
17 unsigned long sof_sdw_quirk = SOF_RT711_JD_SRC_JD1;
18 static int quirk_override = -1;
19 module_param_named(quirk, quirk_override, int, 0444);
20 MODULE_PARM_DESC(quirk, "Board-specific quirk override");
21
22 #define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0)
23
log_quirks(struct device * dev)24 static void log_quirks(struct device *dev)
25 {
26 if (SOF_RT711_JDSRC(sof_sdw_quirk))
27 dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n",
28 SOF_RT711_JDSRC(sof_sdw_quirk));
29 if (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
30 dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n");
31 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
32 dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n");
33 if (sof_sdw_quirk & SOF_SDW_PCH_DMIC)
34 dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n");
35 if (SOF_SSP_GET_PORT(sof_sdw_quirk))
36 dev_dbg(dev, "SSP port %ld\n",
37 SOF_SSP_GET_PORT(sof_sdw_quirk));
38 if (sof_sdw_quirk & SOF_RT715_DAI_ID_FIX)
39 dev_dbg(dev, "quirk SOF_RT715_DAI_ID_FIX enabled\n");
40 if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION)
41 dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n");
42 }
43
sof_sdw_quirk_cb(const struct dmi_system_id * id)44 static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
45 {
46 sof_sdw_quirk = (unsigned long)id->driver_data;
47 return 1;
48 }
49
50 static const struct dmi_system_id sof_sdw_quirk_table[] = {
51 /* CometLake devices */
52 {
53 .callback = sof_sdw_quirk_cb,
54 .matches = {
55 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
56 DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
57 },
58 .driver_data = (void *)SOF_SDW_PCH_DMIC,
59 },
60 {
61 .callback = sof_sdw_quirk_cb,
62 .matches = {
63 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
64 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
65 },
66 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
67 SOF_RT715_DAI_ID_FIX),
68 },
69 {
70 /* early version of SKU 09C6 */
71 .callback = sof_sdw_quirk_cb,
72 .matches = {
73 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
74 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
75 },
76 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
77 SOF_RT715_DAI_ID_FIX),
78 },
79 {
80 .callback = sof_sdw_quirk_cb,
81 .matches = {
82 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
83 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
84 },
85 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
86 SOF_RT715_DAI_ID_FIX |
87 SOF_SDW_FOUR_SPK),
88 },
89 {
90 .callback = sof_sdw_quirk_cb,
91 .matches = {
92 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
93 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
94 },
95 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
96 SOF_RT715_DAI_ID_FIX |
97 SOF_SDW_FOUR_SPK),
98 },
99 /* IceLake devices */
100 {
101 .callback = sof_sdw_quirk_cb,
102 .matches = {
103 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
104 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
105 },
106 .driver_data = (void *)SOF_SDW_PCH_DMIC,
107 },
108 /* TigerLake devices */
109 {
110 .callback = sof_sdw_quirk_cb,
111 .matches = {
112 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
113 DMI_MATCH(DMI_PRODUCT_NAME,
114 "Tiger Lake Client Platform"),
115 },
116 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
117 SOF_RT711_JD_SRC_JD1 |
118 SOF_SDW_PCH_DMIC |
119 SOF_SSP_PORT(SOF_I2S_SSP2)),
120 },
121 {
122 .callback = sof_sdw_quirk_cb,
123 .matches = {
124 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
125 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
126 },
127 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
128 SOF_RT711_JD_SRC_JD2 |
129 SOF_RT715_DAI_ID_FIX),
130 },
131 {
132 .callback = sof_sdw_quirk_cb,
133 .matches = {
134 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
135 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E")
136 },
137 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
138 SOF_RT711_JD_SRC_JD2 |
139 SOF_RT715_DAI_ID_FIX |
140 SOF_SDW_FOUR_SPK),
141 },
142 {
143 .callback = sof_sdw_quirk_cb,
144 .matches = {
145 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
146 DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
147 },
148 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
149 SOF_SDW_PCH_DMIC |
150 SOF_SDW_FOUR_SPK),
151 },
152 {
153 .callback = sof_sdw_quirk_cb,
154 .matches = {
155 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
156 DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"),
157 },
158 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
159 SOF_SDW_PCH_DMIC |
160 SOF_SDW_FOUR_SPK),
161 },
162 {
163 /*
164 * this entry covers multiple HP SKUs. The family name
165 * does not seem robust enough, so we use a partial
166 * match that ignores the product name suffix
167 * (e.g. 15-eb1xxx, 14t-ea000 or 13-aw2xxx)
168 */
169 .callback = sof_sdw_quirk_cb,
170 .matches = {
171 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
172 DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"),
173 },
174 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
175 SOF_SDW_PCH_DMIC |
176 SOF_RT711_JD_SRC_JD2),
177 },
178 /* TigerLake-SDCA devices */
179 {
180 .callback = sof_sdw_quirk_cb,
181 .matches = {
182 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
183 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32")
184 },
185 .driver_data = (void *)(SOF_SDW_TGL_HDMI |
186 SOF_RT711_JD_SRC_JD2 |
187 SOF_RT715_DAI_ID_FIX |
188 SOF_SDW_FOUR_SPK),
189 },
190 /* AlderLake devices */
191 {
192 .callback = sof_sdw_quirk_cb,
193 .matches = {
194 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
195 DMI_MATCH(DMI_PRODUCT_NAME, "Alder Lake Client Platform"),
196 },
197 .driver_data = (void *)(SOF_RT711_JD_SRC_JD1 |
198 SOF_SDW_TGL_HDMI |
199 SOF_RT715_DAI_ID_FIX |
200 SOF_SDW_PCH_DMIC),
201 },
202 {}
203 };
204
205 static struct snd_soc_dai_link_component dmic_component[] = {
206 {
207 .name = "dmic-codec",
208 .dai_name = "dmic-hifi",
209 }
210 };
211
212 static struct snd_soc_dai_link_component platform_component[] = {
213 {
214 /* name might be overridden during probe */
215 .name = "0000:00:1f.3"
216 }
217 };
218
219 /* these wrappers are only needed to avoid typecast compilation errors */
sdw_startup(struct snd_pcm_substream * substream)220 int sdw_startup(struct snd_pcm_substream *substream)
221 {
222 return sdw_startup_stream(substream);
223 }
224
sdw_prepare(struct snd_pcm_substream * substream)225 int sdw_prepare(struct snd_pcm_substream *substream)
226 {
227 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
228 struct sdw_stream_runtime *sdw_stream;
229 struct snd_soc_dai *dai;
230
231 /* Find stream from first CPU DAI */
232 dai = asoc_rtd_to_cpu(rtd, 0);
233
234 sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream);
235
236 if (IS_ERR(sdw_stream)) {
237 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
238 return PTR_ERR(sdw_stream);
239 }
240
241 return sdw_prepare_stream(sdw_stream);
242 }
243
sdw_trigger(struct snd_pcm_substream * substream,int cmd)244 int sdw_trigger(struct snd_pcm_substream *substream, int cmd)
245 {
246 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
247 struct sdw_stream_runtime *sdw_stream;
248 struct snd_soc_dai *dai;
249 int ret;
250
251 /* Find stream from first CPU DAI */
252 dai = asoc_rtd_to_cpu(rtd, 0);
253
254 sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream);
255
256 if (IS_ERR(sdw_stream)) {
257 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
258 return PTR_ERR(sdw_stream);
259 }
260
261 switch (cmd) {
262 case SNDRV_PCM_TRIGGER_START:
263 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
264 case SNDRV_PCM_TRIGGER_RESUME:
265 ret = sdw_enable_stream(sdw_stream);
266 break;
267
268 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
269 case SNDRV_PCM_TRIGGER_SUSPEND:
270 case SNDRV_PCM_TRIGGER_STOP:
271 ret = sdw_disable_stream(sdw_stream);
272 break;
273 default:
274 ret = -EINVAL;
275 break;
276 }
277
278 if (ret)
279 dev_err(rtd->dev, "%s trigger %d failed: %d", __func__, cmd, ret);
280
281 return ret;
282 }
283
sdw_hw_free(struct snd_pcm_substream * substream)284 int sdw_hw_free(struct snd_pcm_substream *substream)
285 {
286 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
287 struct sdw_stream_runtime *sdw_stream;
288 struct snd_soc_dai *dai;
289
290 /* Find stream from first CPU DAI */
291 dai = asoc_rtd_to_cpu(rtd, 0);
292
293 sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream);
294
295 if (IS_ERR(sdw_stream)) {
296 dev_err(rtd->dev, "no stream found for DAI %s", dai->name);
297 return PTR_ERR(sdw_stream);
298 }
299
300 return sdw_deprepare_stream(sdw_stream);
301 }
302
sdw_shutdown(struct snd_pcm_substream * substream)303 void sdw_shutdown(struct snd_pcm_substream *substream)
304 {
305 sdw_shutdown_stream(substream);
306 }
307
308 static const struct snd_soc_ops sdw_ops = {
309 .startup = sdw_startup,
310 .prepare = sdw_prepare,
311 .trigger = sdw_trigger,
312 .hw_free = sdw_hw_free,
313 .shutdown = sdw_shutdown,
314 };
315
316 static struct sof_sdw_codec_info codec_info_list[] = {
317 {
318 .part_id = 0x700,
319 .direction = {true, true},
320 .dai_name = "rt700-aif1",
321 .init = sof_sdw_rt700_init,
322 },
323 {
324 .part_id = 0x711,
325 .version_id = 3,
326 .direction = {true, true},
327 .dai_name = "rt711-sdca-aif1",
328 .init = sof_sdw_rt711_sdca_init,
329 .exit = sof_sdw_rt711_sdca_exit,
330 },
331 {
332 .part_id = 0x711,
333 .version_id = 2,
334 .direction = {true, true},
335 .dai_name = "rt711-aif1",
336 .init = sof_sdw_rt711_init,
337 .exit = sof_sdw_rt711_exit,
338 },
339 {
340 .part_id = 0x1308,
341 .acpi_id = "10EC1308",
342 .direction = {true, false},
343 .dai_name = "rt1308-aif",
344 .ops = &sof_sdw_rt1308_i2s_ops,
345 .init = sof_sdw_rt1308_init,
346 },
347 {
348 .part_id = 0x1316,
349 .direction = {true, true},
350 .dai_name = "rt1316-aif",
351 .init = sof_sdw_rt1316_init,
352 },
353 {
354 .part_id = 0x714,
355 .version_id = 3,
356 .direction = {false, true},
357 .ignore_pch_dmic = true,
358 .dai_name = "rt715-aif2",
359 .init = sof_sdw_rt715_sdca_init,
360 },
361 {
362 .part_id = 0x715,
363 .version_id = 3,
364 .direction = {false, true},
365 .ignore_pch_dmic = true,
366 .dai_name = "rt715-aif2",
367 .init = sof_sdw_rt715_sdca_init,
368 },
369 {
370 .part_id = 0x714,
371 .version_id = 2,
372 .direction = {false, true},
373 .ignore_pch_dmic = true,
374 .dai_name = "rt715-aif2",
375 .init = sof_sdw_rt715_init,
376 },
377 {
378 .part_id = 0x715,
379 .version_id = 2,
380 .direction = {false, true},
381 .ignore_pch_dmic = true,
382 .dai_name = "rt715-aif2",
383 .init = sof_sdw_rt715_init,
384 },
385 {
386 .part_id = 0x8373,
387 .direction = {true, true},
388 .dai_name = "max98373-aif1",
389 .init = sof_sdw_mx8373_init,
390 .codec_card_late_probe = sof_sdw_mx8373_late_probe,
391 },
392 {
393 .part_id = 0x5682,
394 .direction = {true, true},
395 .dai_name = "rt5682-sdw",
396 .init = sof_sdw_rt5682_init,
397 },
398 };
399
find_codec_info_part(u64 adr)400 static inline int find_codec_info_part(u64 adr)
401 {
402 unsigned int part_id, sdw_version;
403 int i;
404
405 part_id = SDW_PART_ID(adr);
406 sdw_version = SDW_VERSION(adr);
407 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
408 /*
409 * A codec info is for all sdw version with the part id if
410 * version_id is not specified in the codec info.
411 */
412 if (part_id == codec_info_list[i].part_id &&
413 (!codec_info_list[i].version_id ||
414 sdw_version == codec_info_list[i].version_id))
415 return i;
416
417 return -EINVAL;
418
419 }
420
find_codec_info_acpi(const u8 * acpi_id)421 static inline int find_codec_info_acpi(const u8 *acpi_id)
422 {
423 int i;
424
425 if (!acpi_id[0])
426 return -EINVAL;
427
428 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
429 if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
430 ACPI_ID_LEN))
431 break;
432
433 if (i == ARRAY_SIZE(codec_info_list))
434 return -EINVAL;
435
436 return i;
437 }
438
439 /*
440 * get BE dailink number and CPU DAI number based on sdw link adr.
441 * Since some sdw slaves may be aggregated, the CPU DAI number
442 * may be larger than the number of BE dailinks.
443 */
get_sdw_dailink_info(const struct snd_soc_acpi_link_adr * links,int * sdw_be_num,int * sdw_cpu_dai_num)444 static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links,
445 int *sdw_be_num, int *sdw_cpu_dai_num)
446 {
447 const struct snd_soc_acpi_link_adr *link;
448 bool group_visited[SDW_MAX_GROUPS];
449 bool no_aggregation;
450 int i;
451
452 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
453 *sdw_cpu_dai_num = 0;
454 *sdw_be_num = 0;
455
456 if (!links)
457 return -EINVAL;
458
459 for (i = 0; i < SDW_MAX_GROUPS; i++)
460 group_visited[i] = false;
461
462 for (link = links; link->num_adr; link++) {
463 const struct snd_soc_acpi_endpoint *endpoint;
464 int codec_index;
465 int stream;
466 u64 adr;
467
468 adr = link->adr_d->adr;
469 codec_index = find_codec_info_part(adr);
470 if (codec_index < 0)
471 return codec_index;
472
473 endpoint = link->adr_d->endpoints;
474
475 /* count DAI number for playback and capture */
476 for_each_pcm_streams(stream) {
477 if (!codec_info_list[codec_index].direction[stream])
478 continue;
479
480 (*sdw_cpu_dai_num)++;
481
482 /* count BE for each non-aggregated slave or group */
483 if (!endpoint->aggregated || no_aggregation ||
484 !group_visited[endpoint->group_id])
485 (*sdw_be_num)++;
486 }
487
488 if (endpoint->aggregated)
489 group_visited[endpoint->group_id] = true;
490 }
491
492 return 0;
493 }
494
init_dai_link(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 * codecs,int codecs_num,int (* init)(struct snd_soc_pcm_runtime * rtd),const struct snd_soc_ops * ops)495 static void init_dai_link(struct snd_soc_dai_link *dai_links, int be_id,
496 char *name, int playback, int capture,
497 struct snd_soc_dai_link_component *cpus,
498 int cpus_num,
499 struct snd_soc_dai_link_component *codecs,
500 int codecs_num,
501 int (*init)(struct snd_soc_pcm_runtime *rtd),
502 const struct snd_soc_ops *ops)
503 {
504 dai_links->id = be_id;
505 dai_links->name = name;
506 dai_links->platforms = platform_component;
507 dai_links->num_platforms = ARRAY_SIZE(platform_component);
508 dai_links->nonatomic = true;
509 dai_links->no_pcm = 1;
510 dai_links->cpus = cpus;
511 dai_links->num_cpus = cpus_num;
512 dai_links->codecs = codecs;
513 dai_links->num_codecs = codecs_num;
514 dai_links->dpcm_playback = playback;
515 dai_links->dpcm_capture = capture;
516 dai_links->init = init;
517 dai_links->ops = ops;
518 }
519
is_unique_device(const struct snd_soc_acpi_link_adr * link,unsigned int sdw_version,unsigned int mfg_id,unsigned int part_id,unsigned int class_id,int index_in_link)520 static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
521 unsigned int sdw_version,
522 unsigned int mfg_id,
523 unsigned int part_id,
524 unsigned int class_id,
525 int index_in_link
526 )
527 {
528 int i;
529
530 for (i = 0; i < link->num_adr; i++) {
531 unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
532 u64 adr;
533
534 /* skip itself */
535 if (i == index_in_link)
536 continue;
537
538 adr = link->adr_d[i].adr;
539
540 sdw1_version = SDW_VERSION(adr);
541 mfg1_id = SDW_MFG_ID(adr);
542 part1_id = SDW_PART_ID(adr);
543 class1_id = SDW_CLASS_ID(adr);
544
545 if (sdw_version == sdw1_version &&
546 mfg_id == mfg1_id &&
547 part_id == part1_id &&
548 class_id == class1_id)
549 return false;
550 }
551
552 return true;
553 }
554
create_codec_dai_name(struct device * dev,const struct snd_soc_acpi_link_adr * link,struct snd_soc_dai_link_component * codec,int offset,struct snd_soc_codec_conf * codec_conf,int codec_count,int * codec_conf_index)555 static int create_codec_dai_name(struct device *dev,
556 const struct snd_soc_acpi_link_adr *link,
557 struct snd_soc_dai_link_component *codec,
558 int offset,
559 struct snd_soc_codec_conf *codec_conf,
560 int codec_count,
561 int *codec_conf_index)
562 {
563 int i;
564
565 /* sanity check */
566 if (*codec_conf_index + link->num_adr > codec_count) {
567 dev_err(dev, "codec_conf: out-of-bounds access requested\n");
568 return -EINVAL;
569 }
570
571 for (i = 0; i < link->num_adr; i++) {
572 unsigned int sdw_version, unique_id, mfg_id;
573 unsigned int link_id, part_id, class_id;
574 int codec_index, comp_index;
575 char *codec_str;
576 u64 adr;
577
578 adr = link->adr_d[i].adr;
579
580 sdw_version = SDW_VERSION(adr);
581 link_id = SDW_DISCO_LINK_ID(adr);
582 unique_id = SDW_UNIQUE_ID(adr);
583 mfg_id = SDW_MFG_ID(adr);
584 part_id = SDW_PART_ID(adr);
585 class_id = SDW_CLASS_ID(adr);
586
587 comp_index = i + offset;
588 if (is_unique_device(link, sdw_version, mfg_id, part_id,
589 class_id, i)) {
590 codec_str = "sdw:%x:%x:%x:%x";
591 codec[comp_index].name =
592 devm_kasprintf(dev, GFP_KERNEL, codec_str,
593 link_id, mfg_id, part_id,
594 class_id);
595 } else {
596 codec_str = "sdw:%x:%x:%x:%x:%x";
597 codec[comp_index].name =
598 devm_kasprintf(dev, GFP_KERNEL, codec_str,
599 link_id, mfg_id, part_id,
600 class_id, unique_id);
601 }
602
603 if (!codec[comp_index].name)
604 return -ENOMEM;
605
606 codec_index = find_codec_info_part(adr);
607 if (codec_index < 0)
608 return codec_index;
609
610 codec[comp_index].dai_name =
611 codec_info_list[codec_index].dai_name;
612
613 codec_conf[*codec_conf_index].dlc = codec[comp_index];
614 codec_conf[*codec_conf_index].name_prefix = link->adr_d[i].name_prefix;
615
616 ++*codec_conf_index;
617 }
618
619 return 0;
620 }
621
set_codec_init_func(const struct snd_soc_acpi_link_adr * link,struct snd_soc_dai_link * dai_links,bool playback,int group_id)622 static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link,
623 struct snd_soc_dai_link *dai_links,
624 bool playback, int group_id)
625 {
626 int i;
627
628 do {
629 /*
630 * Initialize the codec. If codec is part of an aggregated
631 * group (group_id>0), initialize all codecs belonging to
632 * same group.
633 */
634 for (i = 0; i < link->num_adr; i++) {
635 int codec_index;
636
637 codec_index = find_codec_info_part(link->adr_d[i].adr);
638
639 if (codec_index < 0)
640 return codec_index;
641 /* The group_id is > 0 iff the codec is aggregated */
642 if (link->adr_d[i].endpoints->group_id != group_id)
643 continue;
644 if (codec_info_list[codec_index].init)
645 codec_info_list[codec_index].init(link,
646 dai_links,
647 &codec_info_list[codec_index],
648 playback);
649 }
650 link++;
651 } while (link->mask && group_id);
652
653 return 0;
654 }
655
656 /*
657 * check endpoint status in slaves and gather link ID for all slaves in
658 * the same group to generate different CPU DAI. Now only support
659 * one sdw link with all slaves set with only single group id.
660 *
661 * one slave on one sdw link with aggregated = 0
662 * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI
663 *
664 * two or more slaves on one sdw link with aggregated = 0
665 * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs
666 *
667 * multiple links with multiple slaves with aggregated = 1
668 * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs
669 */
get_slave_info(const struct snd_soc_acpi_link_adr * adr_link,struct device * dev,int * cpu_dai_id,int * cpu_dai_num,int * codec_num,int * group_id,bool * group_generated)670 static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
671 struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
672 int *codec_num, int *group_id,
673 bool *group_generated)
674 {
675 const struct snd_soc_acpi_adr_device *adr_d;
676 const struct snd_soc_acpi_link_adr *adr_next;
677 bool no_aggregation;
678 int index = 0;
679
680 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
681 *codec_num = adr_link->num_adr;
682 adr_d = adr_link->adr_d;
683
684 /* make sure the link mask has a single bit set */
685 if (!is_power_of_2(adr_link->mask))
686 return -EINVAL;
687
688 cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
689 if (!adr_d->endpoints->aggregated || no_aggregation) {
690 *cpu_dai_num = 1;
691 *group_id = 0;
692 return 0;
693 }
694
695 *group_id = adr_d->endpoints->group_id;
696
697 /* gather other link ID of slaves in the same group */
698 for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
699 adr_next++) {
700 const struct snd_soc_acpi_endpoint *endpoint;
701
702 endpoint = adr_next->adr_d->endpoints;
703 if (!endpoint->aggregated ||
704 endpoint->group_id != *group_id)
705 continue;
706
707 /* make sure the link mask has a single bit set */
708 if (!is_power_of_2(adr_next->mask))
709 return -EINVAL;
710
711 if (index >= SDW_MAX_CPU_DAIS) {
712 dev_err(dev, " cpu_dai_id array overflows");
713 return -EINVAL;
714 }
715
716 cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
717 *codec_num += adr_next->num_adr;
718 }
719
720 /*
721 * indicate CPU DAIs for this group have been generated
722 * to avoid generating CPU DAIs for this group again.
723 */
724 group_generated[*group_id] = true;
725 *cpu_dai_num = index;
726
727 return 0;
728 }
729
create_sdw_dailink(struct device * dev,int * be_index,struct snd_soc_dai_link * dai_links,int sdw_be_num,int sdw_cpu_dai_num,struct snd_soc_dai_link_component * cpus,const struct snd_soc_acpi_link_adr * link,int * cpu_id,bool * group_generated,struct snd_soc_codec_conf * codec_conf,int codec_count,int * codec_conf_index,bool * ignore_pch_dmic)730 static int create_sdw_dailink(struct device *dev, int *be_index,
731 struct snd_soc_dai_link *dai_links,
732 int sdw_be_num, int sdw_cpu_dai_num,
733 struct snd_soc_dai_link_component *cpus,
734 const struct snd_soc_acpi_link_adr *link,
735 int *cpu_id, bool *group_generated,
736 struct snd_soc_codec_conf *codec_conf,
737 int codec_count,
738 int *codec_conf_index,
739 bool *ignore_pch_dmic)
740 {
741 const struct snd_soc_acpi_link_adr *link_next;
742 struct snd_soc_dai_link_component *codecs;
743 int cpu_dai_id[SDW_MAX_CPU_DAIS];
744 int cpu_dai_num, cpu_dai_index;
745 unsigned int group_id;
746 int codec_idx = 0;
747 int i = 0, j = 0;
748 int codec_index;
749 int codec_num;
750 int stream;
751 int ret;
752 int k;
753
754 ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
755 &group_id, group_generated);
756 if (ret)
757 return ret;
758
759 codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
760 if (!codecs)
761 return -ENOMEM;
762
763 /* generate codec name on different links in the same group */
764 for (link_next = link; link_next && link_next->num_adr &&
765 i < cpu_dai_num; link_next++) {
766 const struct snd_soc_acpi_endpoint *endpoints;
767
768 endpoints = link_next->adr_d->endpoints;
769 if (group_id && (!endpoints->aggregated ||
770 endpoints->group_id != group_id))
771 continue;
772
773 /* skip the link excluded by this processed group */
774 if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
775 continue;
776
777 ret = create_codec_dai_name(dev, link_next, codecs, codec_idx,
778 codec_conf, codec_count, codec_conf_index);
779 if (ret < 0)
780 return ret;
781
782 /* check next link to create codec dai in the processed group */
783 i++;
784 codec_idx += link_next->num_adr;
785 }
786
787 /* find codec info to create BE DAI */
788 codec_index = find_codec_info_part(link->adr_d[0].adr);
789 if (codec_index < 0)
790 return codec_index;
791
792 if (codec_info_list[codec_index].ignore_pch_dmic)
793 *ignore_pch_dmic = true;
794
795 cpu_dai_index = *cpu_id;
796 for_each_pcm_streams(stream) {
797 char *name, *cpu_name;
798 int playback, capture;
799 static const char * const sdw_stream_name[] = {
800 "SDW%d-Playback",
801 "SDW%d-Capture",
802 };
803
804 if (!codec_info_list[codec_index].direction[stream])
805 continue;
806
807 /* create stream name according to first link id */
808 name = devm_kasprintf(dev, GFP_KERNEL,
809 sdw_stream_name[stream], cpu_dai_id[0]);
810 if (!name)
811 return -ENOMEM;
812
813 /*
814 * generate CPU DAI name base on the sdw link ID and
815 * PIN ID with offset of 2 according to sdw dai driver.
816 */
817 for (k = 0; k < cpu_dai_num; k++) {
818 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
819 "SDW%d Pin%d", cpu_dai_id[k],
820 j + SDW_INTEL_BIDIR_PDI_BASE);
821 if (!cpu_name)
822 return -ENOMEM;
823
824 if (cpu_dai_index >= sdw_cpu_dai_num) {
825 dev_err(dev, "invalid cpu dai index %d",
826 cpu_dai_index);
827 return -EINVAL;
828 }
829
830 cpus[cpu_dai_index++].dai_name = cpu_name;
831 }
832
833 if (*be_index >= sdw_be_num) {
834 dev_err(dev, " invalid be dai index %d", *be_index);
835 return -EINVAL;
836 }
837
838 if (*cpu_id >= sdw_cpu_dai_num) {
839 dev_err(dev, " invalid cpu dai index %d", *cpu_id);
840 return -EINVAL;
841 }
842
843 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
844 capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
845 init_dai_link(dai_links + *be_index, *be_index, name,
846 playback, capture,
847 cpus + *cpu_id, cpu_dai_num,
848 codecs, codec_num,
849 NULL, &sdw_ops);
850 /*
851 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
852 * based on wait_for_completion(), tag them as 'nonatomic'.
853 */
854 dai_links[*be_index].nonatomic = true;
855
856 ret = set_codec_init_func(link, dai_links + (*be_index)++,
857 playback, group_id);
858 if (ret < 0) {
859 dev_err(dev, "failed to init codec %d", codec_index);
860 return ret;
861 }
862
863 *cpu_id += cpu_dai_num;
864 j++;
865 }
866
867 return 0;
868 }
869
870 /*
871 * DAI link ID of SSP & DMIC & HDMI are based on last
872 * link ID used by sdw link. Since be_id may be changed
873 * in init func of sdw codec, it is not equal to be_id
874 */
get_next_be_id(struct snd_soc_dai_link * links,int be_id)875 static inline int get_next_be_id(struct snd_soc_dai_link *links,
876 int be_id)
877 {
878 return links[be_id - 1].id + 1;
879 }
880
881 #define IDISP_CODEC_MASK 0x4
882
sof_card_codec_conf_alloc(struct device * dev,struct snd_soc_acpi_mach_params * mach_params,struct snd_soc_codec_conf ** codec_conf,int * codec_conf_count)883 static int sof_card_codec_conf_alloc(struct device *dev,
884 struct snd_soc_acpi_mach_params *mach_params,
885 struct snd_soc_codec_conf **codec_conf,
886 int *codec_conf_count)
887 {
888 const struct snd_soc_acpi_link_adr *adr_link;
889 struct snd_soc_codec_conf *c_conf;
890 int num_codecs = 0;
891 int i;
892
893 adr_link = mach_params->links;
894 if (!adr_link)
895 return -EINVAL;
896
897 /* generate DAI links by each sdw link */
898 for (; adr_link->num_adr; adr_link++) {
899 for (i = 0; i < adr_link->num_adr; i++) {
900 if (!adr_link->adr_d[i].name_prefix) {
901 dev_err(dev, "codec 0x%llx does not have a name prefix\n",
902 adr_link->adr_d[i].adr);
903 return -EINVAL;
904 }
905 }
906 num_codecs += adr_link->num_adr;
907 }
908
909 c_conf = devm_kzalloc(dev, num_codecs * sizeof(*c_conf), GFP_KERNEL);
910 if (!c_conf)
911 return -ENOMEM;
912
913 *codec_conf = c_conf;
914 *codec_conf_count = num_codecs;
915
916 return 0;
917 }
918
sof_card_dai_links_create(struct device * dev,struct snd_soc_acpi_mach * mach,struct snd_soc_card * card)919 static int sof_card_dai_links_create(struct device *dev,
920 struct snd_soc_acpi_mach *mach,
921 struct snd_soc_card *card)
922 {
923 int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
924 struct mc_private *ctx = snd_soc_card_get_drvdata(card);
925 struct snd_soc_dai_link_component *idisp_components;
926 struct snd_soc_dai_link_component *ssp_components;
927 struct snd_soc_acpi_mach_params *mach_params;
928 const struct snd_soc_acpi_link_adr *adr_link;
929 struct snd_soc_dai_link_component *cpus;
930 struct snd_soc_codec_conf *codec_conf;
931 bool ignore_pch_dmic = false;
932 int codec_conf_count;
933 int codec_conf_index = 0;
934 bool group_generated[SDW_MAX_GROUPS];
935 int ssp_codec_index, ssp_mask;
936 struct snd_soc_dai_link *links;
937 int num_links, link_id = 0;
938 char *name, *cpu_name;
939 int total_cpu_dai_num;
940 int sdw_cpu_dai_num;
941 int i, j, be_id = 0;
942 int cpu_id = 0;
943 int comp_num;
944 int ret;
945
946 mach_params = &mach->mach_params;
947
948 /* allocate codec conf, will be populated when dailinks are created */
949 ret = sof_card_codec_conf_alloc(dev, mach_params, &codec_conf, &codec_conf_count);
950 if (ret < 0)
951 return ret;
952
953 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
954 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
955 codec_info_list[i].amp_num = 0;
956
957 if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
958 hdmi_num = SOF_TGL_HDMI_COUNT;
959 else
960 hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
961
962 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
963 /*
964 * on generic tgl platform, I2S or sdw mode is supported
965 * based on board rework. A ACPI device is registered in
966 * system only when I2S mode is supported, not sdw mode.
967 * Here check ACPI ID to confirm I2S is supported.
968 */
969 ssp_codec_index = find_codec_info_acpi(mach->id);
970 ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
971 comp_num = hdmi_num + ssp_num;
972
973 ret = get_sdw_dailink_info(mach_params->links,
974 &sdw_be_num, &sdw_cpu_dai_num);
975 if (ret < 0) {
976 dev_err(dev, "failed to get sdw link info %d", ret);
977 return ret;
978 }
979
980 if (mach_params->codec_mask & IDISP_CODEC_MASK)
981 ctx->idisp_codec = true;
982
983 /* enable dmic01 & dmic16k */
984 dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) ? 2 : 0;
985 comp_num += dmic_num;
986
987 dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
988 dmic_num, ctx->idisp_codec ? hdmi_num : 0);
989
990 /* allocate BE dailinks */
991 num_links = comp_num + sdw_be_num;
992 links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
993
994 /* allocated CPU DAIs */
995 total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
996 cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
997 GFP_KERNEL);
998
999 if (!links || !cpus)
1000 return -ENOMEM;
1001
1002 /* SDW */
1003 if (!sdw_be_num)
1004 goto SSP;
1005
1006 adr_link = mach_params->links;
1007 if (!adr_link)
1008 return -EINVAL;
1009
1010 /*
1011 * SoundWire Slaves aggregated in the same group may be
1012 * located on different hardware links. Clear array to indicate
1013 * CPU DAIs for this group have not been generated.
1014 */
1015 for (i = 0; i < SDW_MAX_GROUPS; i++)
1016 group_generated[i] = false;
1017
1018 /* generate DAI links by each sdw link */
1019 for (; adr_link->num_adr; adr_link++) {
1020 const struct snd_soc_acpi_endpoint *endpoint;
1021
1022 endpoint = adr_link->adr_d->endpoints;
1023 if (endpoint->aggregated && !endpoint->group_id) {
1024 dev_err(dev, "invalid group id on link %x",
1025 adr_link->mask);
1026 continue;
1027 }
1028
1029 /* this group has been generated */
1030 if (endpoint->aggregated &&
1031 group_generated[endpoint->group_id])
1032 continue;
1033
1034 ret = create_sdw_dailink(dev, &be_id, links, sdw_be_num,
1035 sdw_cpu_dai_num, cpus, adr_link,
1036 &cpu_id, group_generated,
1037 codec_conf, codec_conf_count,
1038 &codec_conf_index,
1039 &ignore_pch_dmic);
1040 if (ret < 0) {
1041 dev_err(dev, "failed to create dai link %d", be_id);
1042 return -ENOMEM;
1043 }
1044 }
1045
1046 /* non-sdw DAI follows sdw DAI */
1047 link_id = be_id;
1048
1049 /* get BE ID for non-sdw DAI */
1050 be_id = get_next_be_id(links, be_id);
1051
1052 SSP:
1053 /* SSP */
1054 if (!ssp_num)
1055 goto DMIC;
1056
1057 for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
1058 struct sof_sdw_codec_info *info;
1059 int playback, capture;
1060 char *codec_name;
1061
1062 if (!(ssp_mask & 0x1))
1063 continue;
1064
1065 name = devm_kasprintf(dev, GFP_KERNEL,
1066 "SSP%d-Codec", i);
1067 if (!name)
1068 return -ENOMEM;
1069
1070 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
1071 if (!cpu_name)
1072 return -ENOMEM;
1073
1074 ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
1075 GFP_KERNEL);
1076 if (!ssp_components)
1077 return -ENOMEM;
1078
1079 info = &codec_info_list[ssp_codec_index];
1080 codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
1081 info->acpi_id, j++);
1082 if (!codec_name)
1083 return -ENOMEM;
1084
1085 ssp_components->name = codec_name;
1086 ssp_components->dai_name = info->dai_name;
1087 cpus[cpu_id].dai_name = cpu_name;
1088
1089 playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK];
1090 capture = info->direction[SNDRV_PCM_STREAM_CAPTURE];
1091 init_dai_link(links + link_id, be_id, name,
1092 playback, capture,
1093 cpus + cpu_id, 1,
1094 ssp_components, 1,
1095 NULL, info->ops);
1096
1097 ret = info->init(NULL, links + link_id, info, 0);
1098 if (ret < 0)
1099 return ret;
1100
1101 INC_ID(be_id, cpu_id, link_id);
1102 }
1103
1104 DMIC:
1105 /* dmic */
1106 if (dmic_num > 0) {
1107 if (ignore_pch_dmic) {
1108 dev_warn(dev, "Ignoring PCH DMIC\n");
1109 goto HDMI;
1110 }
1111 cpus[cpu_id].dai_name = "DMIC01 Pin";
1112 init_dai_link(links + link_id, be_id, "dmic01",
1113 0, 1, // DMIC only supports capture
1114 cpus + cpu_id, 1,
1115 dmic_component, 1,
1116 sof_sdw_dmic_init, NULL);
1117 INC_ID(be_id, cpu_id, link_id);
1118
1119 cpus[cpu_id].dai_name = "DMIC16k Pin";
1120 init_dai_link(links + link_id, be_id, "dmic16k",
1121 0, 1, // DMIC only supports capture
1122 cpus + cpu_id, 1,
1123 dmic_component, 1,
1124 /* don't call sof_sdw_dmic_init() twice */
1125 NULL, NULL);
1126 INC_ID(be_id, cpu_id, link_id);
1127 }
1128
1129 HDMI:
1130 /* HDMI */
1131 if (hdmi_num > 0) {
1132 idisp_components = devm_kcalloc(dev, hdmi_num,
1133 sizeof(*idisp_components),
1134 GFP_KERNEL);
1135 if (!idisp_components)
1136 return -ENOMEM;
1137 }
1138
1139 for (i = 0; i < hdmi_num; i++) {
1140 name = devm_kasprintf(dev, GFP_KERNEL,
1141 "iDisp%d", i + 1);
1142 if (!name)
1143 return -ENOMEM;
1144
1145 if (ctx->idisp_codec) {
1146 idisp_components[i].name = "ehdaudio0D2";
1147 idisp_components[i].dai_name = devm_kasprintf(dev,
1148 GFP_KERNEL,
1149 "intel-hdmi-hifi%d",
1150 i + 1);
1151 if (!idisp_components[i].dai_name)
1152 return -ENOMEM;
1153 } else {
1154 idisp_components[i].name = "snd-soc-dummy";
1155 idisp_components[i].dai_name = "snd-soc-dummy-dai";
1156 }
1157
1158 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
1159 "iDisp%d Pin", i + 1);
1160 if (!cpu_name)
1161 return -ENOMEM;
1162
1163 cpus[cpu_id].dai_name = cpu_name;
1164 init_dai_link(links + link_id, be_id, name,
1165 1, 0, // HDMI only supports playback
1166 cpus + cpu_id, 1,
1167 idisp_components + i, 1,
1168 sof_sdw_hdmi_init, NULL);
1169 INC_ID(be_id, cpu_id, link_id);
1170 }
1171
1172 card->dai_link = links;
1173 card->num_links = num_links;
1174
1175 card->codec_conf = codec_conf;
1176 card->num_configs = codec_conf_count;
1177
1178 return 0;
1179 }
1180
sof_sdw_card_late_probe(struct snd_soc_card * card)1181 static int sof_sdw_card_late_probe(struct snd_soc_card *card)
1182 {
1183 int i, ret;
1184
1185 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1186 if (!codec_info_list[i].late_probe)
1187 continue;
1188
1189 ret = codec_info_list[i].codec_card_late_probe(card);
1190 if (ret < 0)
1191 return ret;
1192 }
1193
1194 return sof_sdw_hdmi_card_late_probe(card);
1195 }
1196
1197 /* SoC card */
1198 static const char sdw_card_long_name[] = "Intel Soundwire SOF";
1199
1200 static struct snd_soc_card card_sof_sdw = {
1201 .name = "soundwire",
1202 .owner = THIS_MODULE,
1203 .late_probe = sof_sdw_card_late_probe,
1204 };
1205
mc_probe(struct platform_device * pdev)1206 static int mc_probe(struct platform_device *pdev)
1207 {
1208 struct snd_soc_card *card = &card_sof_sdw;
1209 struct snd_soc_acpi_mach *mach;
1210 struct mc_private *ctx;
1211 int amp_num = 0, i;
1212 int ret;
1213
1214 dev_dbg(&pdev->dev, "Entry %s\n", __func__);
1215
1216 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
1217 if (!ctx)
1218 return -ENOMEM;
1219
1220 dmi_check_system(sof_sdw_quirk_table);
1221
1222 if (quirk_override != -1) {
1223 dev_info(&pdev->dev, "Overriding quirk 0x%lx => 0x%x\n",
1224 sof_sdw_quirk, quirk_override);
1225 sof_sdw_quirk = quirk_override;
1226 }
1227 log_quirks(&pdev->dev);
1228
1229 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
1230
1231 card->dev = &pdev->dev;
1232 snd_soc_card_set_drvdata(card, ctx);
1233
1234 mach = pdev->dev.platform_data;
1235 ret = sof_card_dai_links_create(&pdev->dev, mach,
1236 card);
1237 if (ret < 0)
1238 return ret;
1239
1240 ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
1241
1242 /*
1243 * the default amp_num is zero for each codec and
1244 * amp_num will only be increased for active amp
1245 * codecs on used platform
1246 */
1247 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
1248 amp_num += codec_info_list[i].amp_num;
1249
1250 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
1251 "cfg-spk:%d cfg-amp:%d",
1252 (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
1253 ? 4 : 2, amp_num);
1254 if (!card->components)
1255 return -ENOMEM;
1256
1257 card->long_name = sdw_card_long_name;
1258
1259 /* Register the card */
1260 ret = devm_snd_soc_register_card(&pdev->dev, card);
1261 if (ret) {
1262 dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
1263 return ret;
1264 }
1265
1266 platform_set_drvdata(pdev, card);
1267
1268 return ret;
1269 }
1270
mc_remove(struct platform_device * pdev)1271 static int mc_remove(struct platform_device *pdev)
1272 {
1273 struct snd_soc_card *card = platform_get_drvdata(pdev);
1274 struct snd_soc_dai_link *link;
1275 int ret;
1276 int i, j;
1277
1278 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
1279 if (!codec_info_list[i].exit)
1280 continue;
1281 /*
1282 * We don't need to call .exit function if there is no matched
1283 * dai link found.
1284 */
1285 for_each_card_prelinks(card, j, link) {
1286 if (!strcmp(link->codecs[0].dai_name,
1287 codec_info_list[i].dai_name)) {
1288 ret = codec_info_list[i].exit(&pdev->dev, link);
1289 if (ret)
1290 dev_warn(&pdev->dev,
1291 "codec exit failed %d\n",
1292 ret);
1293 break;
1294 }
1295 }
1296 }
1297
1298 return 0;
1299 }
1300
1301 static struct platform_driver sof_sdw_driver = {
1302 .driver = {
1303 .name = "sof_sdw",
1304 .pm = &snd_soc_pm_ops,
1305 },
1306 .probe = mc_probe,
1307 .remove = mc_remove,
1308 };
1309
1310 module_platform_driver(sof_sdw_driver);
1311
1312 MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
1313 MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
1314 MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
1315 MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
1316 MODULE_LICENSE("GPL v2");
1317 MODULE_ALIAS("platform:sof_sdw");
1318