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