1
2
3
4
5
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
17unsigned long sof_sdw_quirk = SOF_RT711_JD_SRC_JD1;
18
19#define INC_ID(BE, CPU, LINK) do { (BE)++; (CPU)++; (LINK)++; } while (0)
20
21static int sof_sdw_quirk_cb(const struct dmi_system_id *id)
22{
23 sof_sdw_quirk = (unsigned long)id->driver_data;
24 return 1;
25}
26
27static const struct dmi_system_id sof_sdw_quirk_table[] = {
28 {
29 .callback = sof_sdw_quirk_cb,
30 .matches = {
31 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
32 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "09C6")
33 },
34 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
35 SOF_RT715_DAI_ID_FIX),
36 },
37 {
38
39 .callback = sof_sdw_quirk_cb,
40 .matches = {
41 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
42 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0983")
43 },
44 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
45 SOF_RT715_DAI_ID_FIX),
46 },
47 {
48 .callback = sof_sdw_quirk_cb,
49 .matches = {
50 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
51 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"),
52 },
53 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
54 SOF_RT715_DAI_ID_FIX |
55 SOF_SDW_FOUR_SPK),
56 },
57 {
58 .callback = sof_sdw_quirk_cb,
59 .matches = {
60 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
61 DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"),
62 },
63 .driver_data = (void *)(SOF_RT711_JD_SRC_JD2 |
64 SOF_RT715_DAI_ID_FIX |
65 SOF_SDW_FOUR_SPK),
66 },
67 {
68 .callback = sof_sdw_quirk_cb,
69 .matches = {
70 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
71 DMI_MATCH(DMI_PRODUCT_NAME,
72 "Tiger Lake Client Platform"),
73 },
74 .driver_data = (void *)(SOF_RT711_JD_SRC_JD1 |
75 SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC |
76 SOF_SSP_PORT(SOF_I2S_SSP2)),
77 },
78 {
79 .callback = sof_sdw_quirk_cb,
80 .matches = {
81 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
82 DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"),
83 },
84 .driver_data = (void *)SOF_SDW_PCH_DMIC,
85 },
86 {
87 .callback = sof_sdw_quirk_cb,
88 .matches = {
89 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
90 DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"),
91 },
92 .driver_data = (void *)SOF_SDW_PCH_DMIC,
93 },
94 {
95 .callback = sof_sdw_quirk_cb,
96 .matches = {
97 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
98 DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"),
99 },
100 .driver_data = (void *)(SOF_SDW_TGL_HDMI | SOF_SDW_PCH_DMIC),
101 },
102
103 {}
104};
105
106static struct snd_soc_codec_conf codec_conf[] = {
107 {
108 .dlc = COMP_CODEC_CONF("sdw:0:25d:711:0"),
109 .name_prefix = "rt711",
110 },
111
112 {
113 .dlc = COMP_CODEC_CONF("i2c-10EC1308:00"),
114 .name_prefix = "rt1308-1",
115 },
116
117 {
118 .dlc = COMP_CODEC_CONF("sdw:1:25d:1308:0"),
119 .name_prefix = "rt1308-1",
120 },
121
122 {
123 .dlc = COMP_CODEC_CONF("sdw:1:25d:1308:0:0"),
124 .name_prefix = "rt1308-1",
125 },
126 {
127 .dlc = COMP_CODEC_CONF("sdw:1:25d:1308:0:2"),
128 .name_prefix = "rt1308-2",
129 },
130
131 {
132 .dlc = COMP_CODEC_CONF("sdw:2:25d:1308:0"),
133 .name_prefix = "rt1308-2",
134 },
135 {
136 .dlc = COMP_CODEC_CONF("sdw:3:25d:715:0"),
137 .name_prefix = "rt715",
138 },
139 {
140 .dlc = COMP_CODEC_CONF("sdw:0:25d:5682:0"),
141 .name_prefix = "rt5682",
142 },
143};
144
145static struct snd_soc_dai_link_component dmic_component[] = {
146 {
147 .name = "dmic-codec",
148 .dai_name = "dmic-hifi",
149 }
150};
151
152static struct snd_soc_dai_link_component platform_component[] = {
153 {
154
155 .name = "0000:00:1f.3"
156 }
157};
158
159
160static int sdw_startup(struct snd_pcm_substream *substream)
161{
162 return sdw_startup_stream(substream);
163}
164
165static void sdw_shutdown(struct snd_pcm_substream *substream)
166{
167 sdw_shutdown_stream(substream);
168}
169
170static const struct snd_soc_ops sdw_ops = {
171 .startup = sdw_startup,
172 .shutdown = sdw_shutdown,
173};
174
175static struct sof_sdw_codec_info codec_info_list[] = {
176 {
177 .id = 0x700,
178 .direction = {true, true},
179 .dai_name = "rt700-aif1",
180 .init = sof_sdw_rt700_init,
181 },
182 {
183 .id = 0x711,
184 .direction = {true, true},
185 .dai_name = "rt711-aif1",
186 .init = sof_sdw_rt711_init,
187 },
188 {
189 .id = 0x1308,
190 .acpi_id = "10EC1308",
191 .direction = {true, false},
192 .dai_name = "rt1308-aif",
193 .ops = &sof_sdw_rt1308_i2s_ops,
194 .init = sof_sdw_rt1308_init,
195 },
196 {
197 .id = 0x715,
198 .direction = {false, true},
199 .dai_name = "rt715-aif2",
200 .init = sof_sdw_rt715_init,
201 },
202 {
203 .id = 0x5682,
204 .direction = {true, true},
205 .dai_name = "rt5682-sdw",
206 .init = sof_sdw_rt5682_init,
207 },
208};
209
210static inline int find_codec_info_part(unsigned int part_id)
211{
212 int i;
213
214 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
215 if (part_id == codec_info_list[i].id)
216 break;
217
218 if (i == ARRAY_SIZE(codec_info_list))
219 return -EINVAL;
220
221 return i;
222}
223
224static inline int find_codec_info_acpi(const u8 *acpi_id)
225{
226 int i;
227
228 if (!acpi_id[0])
229 return -EINVAL;
230
231 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
232 if (!memcmp(codec_info_list[i].acpi_id, acpi_id,
233 ACPI_ID_LEN))
234 break;
235
236 if (i == ARRAY_SIZE(codec_info_list))
237 return -EINVAL;
238
239 return i;
240}
241
242
243
244
245
246
247static int get_sdw_dailink_info(const struct snd_soc_acpi_link_adr *links,
248 int *sdw_be_num, int *sdw_cpu_dai_num)
249{
250 const struct snd_soc_acpi_link_adr *link;
251 bool group_visited[SDW_MAX_GROUPS];
252 bool no_aggregation;
253 int i;
254
255 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
256 *sdw_cpu_dai_num = 0;
257 *sdw_be_num = 0;
258
259 if (!links)
260 return -EINVAL;
261
262 for (i = 0; i < SDW_MAX_GROUPS; i++)
263 group_visited[i] = false;
264
265 for (link = links; link->num_adr; link++) {
266 const struct snd_soc_acpi_endpoint *endpoint;
267 int part_id, codec_index;
268 int stream;
269 u64 adr;
270
271 adr = link->adr_d->adr;
272 part_id = SDW_PART_ID(adr);
273 codec_index = find_codec_info_part(part_id);
274 if (codec_index < 0)
275 return codec_index;
276
277 endpoint = link->adr_d->endpoints;
278
279
280 for_each_pcm_streams(stream) {
281 if (!codec_info_list[codec_index].direction[stream])
282 continue;
283
284 (*sdw_cpu_dai_num)++;
285
286
287 if (!endpoint->aggregated || no_aggregation ||
288 !group_visited[endpoint->group_id])
289 (*sdw_be_num)++;
290 }
291
292 if (endpoint->aggregated)
293 group_visited[endpoint->group_id] = true;
294 }
295
296 return 0;
297}
298
299static void init_dai_link(struct snd_soc_dai_link *dai_links, int be_id,
300 char *name, int playback, int capture,
301 struct snd_soc_dai_link_component *cpus,
302 int cpus_num,
303 struct snd_soc_dai_link_component *codecs,
304 int codecs_num,
305 int (*init)(struct snd_soc_pcm_runtime *rtd),
306 const struct snd_soc_ops *ops)
307{
308 dai_links->id = be_id;
309 dai_links->name = name;
310 dai_links->platforms = platform_component;
311 dai_links->num_platforms = ARRAY_SIZE(platform_component);
312 dai_links->nonatomic = true;
313 dai_links->no_pcm = 1;
314 dai_links->cpus = cpus;
315 dai_links->num_cpus = cpus_num;
316 dai_links->codecs = codecs;
317 dai_links->num_codecs = codecs_num;
318 dai_links->dpcm_playback = playback;
319 dai_links->dpcm_capture = capture;
320 dai_links->init = init;
321 dai_links->ops = ops;
322}
323
324static bool is_unique_device(const struct snd_soc_acpi_link_adr *link,
325 unsigned int sdw_version,
326 unsigned int mfg_id,
327 unsigned int part_id,
328 unsigned int class_id,
329 int index_in_link
330 )
331{
332 int i;
333
334 for (i = 0; i < link->num_adr; i++) {
335 unsigned int sdw1_version, mfg1_id, part1_id, class1_id;
336 u64 adr;
337
338
339 if (i == index_in_link)
340 continue;
341
342 adr = link->adr_d[i].adr;
343
344 sdw1_version = SDW_VERSION(adr);
345 mfg1_id = SDW_MFG_ID(adr);
346 part1_id = SDW_PART_ID(adr);
347 class1_id = SDW_CLASS_ID(adr);
348
349 if (sdw_version == sdw1_version &&
350 mfg_id == mfg1_id &&
351 part_id == part1_id &&
352 class_id == class1_id)
353 return false;
354 }
355
356 return true;
357}
358
359static int create_codec_dai_name(struct device *dev,
360 const struct snd_soc_acpi_link_adr *link,
361 struct snd_soc_dai_link_component *codec,
362 int offset)
363{
364 int i;
365
366 for (i = 0; i < link->num_adr; i++) {
367 unsigned int sdw_version, unique_id, mfg_id;
368 unsigned int link_id, part_id, class_id;
369 int codec_index, comp_index;
370 char *codec_str;
371 u64 adr;
372
373 adr = link->adr_d[i].adr;
374
375 sdw_version = SDW_VERSION(adr);
376 link_id = SDW_DISCO_LINK_ID(adr);
377 unique_id = SDW_UNIQUE_ID(adr);
378 mfg_id = SDW_MFG_ID(adr);
379 part_id = SDW_PART_ID(adr);
380 class_id = SDW_CLASS_ID(adr);
381
382 comp_index = i + offset;
383 if (is_unique_device(link, sdw_version, mfg_id, part_id,
384 class_id, i)) {
385 codec_str = "sdw:%x:%x:%x:%x";
386 codec[comp_index].name =
387 devm_kasprintf(dev, GFP_KERNEL, codec_str,
388 link_id, mfg_id, part_id,
389 class_id);
390 } else {
391 codec_str = "sdw:%x:%x:%x:%x:%x";
392 codec[comp_index].name =
393 devm_kasprintf(dev, GFP_KERNEL, codec_str,
394 link_id, mfg_id, part_id,
395 class_id, unique_id);
396 }
397
398 if (!codec[comp_index].name)
399 return -ENOMEM;
400
401 codec_index = find_codec_info_part(part_id);
402 if (codec_index < 0)
403 return codec_index;
404
405 codec[comp_index].dai_name =
406 codec_info_list[codec_index].dai_name;
407 }
408
409 return 0;
410}
411
412static int set_codec_init_func(const struct snd_soc_acpi_link_adr *link,
413 struct snd_soc_dai_link *dai_links,
414 bool playback, int group_id)
415{
416 int i;
417
418 do {
419
420
421
422
423
424 for (i = 0; i < link->num_adr; i++) {
425 unsigned int part_id;
426 int codec_index;
427
428 part_id = SDW_PART_ID(link->adr_d[i].adr);
429 codec_index = find_codec_info_part(part_id);
430
431 if (codec_index < 0)
432 return codec_index;
433
434 if (link->adr_d[i].endpoints->group_id != group_id)
435 continue;
436 if (codec_info_list[codec_index].init)
437 codec_info_list[codec_index].init(link,
438 dai_links,
439 &codec_info_list[codec_index],
440 playback);
441 }
442 link++;
443 } while (link->mask && group_id);
444
445 return 0;
446}
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link,
463 struct device *dev, int *cpu_dai_id, int *cpu_dai_num,
464 int *codec_num, int *group_id,
465 bool *group_generated)
466{
467 const struct snd_soc_acpi_adr_device *adr_d;
468 const struct snd_soc_acpi_link_adr *adr_next;
469 bool no_aggregation;
470 int index = 0;
471
472 no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION;
473 *codec_num = adr_link->num_adr;
474 adr_d = adr_link->adr_d;
475
476
477 if (!is_power_of_2(adr_link->mask))
478 return -EINVAL;
479
480 cpu_dai_id[index++] = ffs(adr_link->mask) - 1;
481 if (!adr_d->endpoints->aggregated || no_aggregation) {
482 *cpu_dai_num = 1;
483 *group_id = 0;
484 return 0;
485 }
486
487 *group_id = adr_d->endpoints->group_id;
488
489
490 for (adr_next = adr_link + 1; adr_next && adr_next->num_adr;
491 adr_next++) {
492 const struct snd_soc_acpi_endpoint *endpoint;
493
494 endpoint = adr_next->adr_d->endpoints;
495 if (!endpoint->aggregated ||
496 endpoint->group_id != *group_id)
497 continue;
498
499
500 if (!is_power_of_2(adr_next->mask))
501 return -EINVAL;
502
503 if (index >= SDW_MAX_CPU_DAIS) {
504 dev_err(dev, " cpu_dai_id array overflows");
505 return -EINVAL;
506 }
507
508 cpu_dai_id[index++] = ffs(adr_next->mask) - 1;
509 *codec_num += adr_next->num_adr;
510 }
511
512
513
514
515
516 group_generated[*group_id] = true;
517 *cpu_dai_num = index;
518
519 return 0;
520}
521
522static int create_sdw_dailink(struct device *dev, int *be_index,
523 struct snd_soc_dai_link *dai_links,
524 int sdw_be_num, int sdw_cpu_dai_num,
525 struct snd_soc_dai_link_component *cpus,
526 const struct snd_soc_acpi_link_adr *link,
527 int *cpu_id, bool *group_generated)
528{
529 const struct snd_soc_acpi_link_adr *link_next;
530 struct snd_soc_dai_link_component *codecs;
531 int cpu_dai_id[SDW_MAX_CPU_DAIS];
532 int cpu_dai_num, cpu_dai_index;
533 unsigned int part_id, group_id;
534 int codec_idx = 0;
535 int i = 0, j = 0;
536 int codec_index;
537 int codec_num;
538 int stream;
539 int ret;
540 int k;
541
542 ret = get_slave_info(link, dev, cpu_dai_id, &cpu_dai_num, &codec_num,
543 &group_id, group_generated);
544 if (ret)
545 return ret;
546
547 codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL);
548 if (!codecs)
549 return -ENOMEM;
550
551
552 for (link_next = link; link_next && link_next->num_adr &&
553 i < cpu_dai_num; link_next++) {
554 const struct snd_soc_acpi_endpoint *endpoints;
555
556 endpoints = link_next->adr_d->endpoints;
557 if (group_id && (!endpoints->aggregated ||
558 endpoints->group_id != group_id))
559 continue;
560
561
562 if (cpu_dai_id[i] != ffs(link_next->mask) - 1)
563 continue;
564
565 ret = create_codec_dai_name(dev, link_next, codecs, codec_idx);
566 if (ret < 0)
567 return ret;
568
569
570 i++;
571 codec_idx += link_next->num_adr;
572 }
573
574
575 part_id = SDW_PART_ID(link->adr_d[0].adr);
576 codec_index = find_codec_info_part(part_id);
577 if (codec_index < 0)
578 return codec_index;
579
580 cpu_dai_index = *cpu_id;
581 for_each_pcm_streams(stream) {
582 char *name, *cpu_name;
583 int playback, capture;
584 static const char * const sdw_stream_name[] = {
585 "SDW%d-Playback",
586 "SDW%d-Capture",
587 };
588
589 if (!codec_info_list[codec_index].direction[stream])
590 continue;
591
592
593 name = devm_kasprintf(dev, GFP_KERNEL,
594 sdw_stream_name[stream], cpu_dai_id[0]);
595 if (!name)
596 return -ENOMEM;
597
598
599
600
601
602 for (k = 0; k < cpu_dai_num; k++) {
603 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
604 "SDW%d Pin%d", cpu_dai_id[k],
605 j + SDW_INTEL_BIDIR_PDI_BASE);
606 if (!cpu_name)
607 return -ENOMEM;
608
609 if (cpu_dai_index >= sdw_cpu_dai_num) {
610 dev_err(dev, "invalid cpu dai index %d",
611 cpu_dai_index);
612 return -EINVAL;
613 }
614
615 cpus[cpu_dai_index++].dai_name = cpu_name;
616 }
617
618 if (*be_index >= sdw_be_num) {
619 dev_err(dev, " invalid be dai index %d", *be_index);
620 return -EINVAL;
621 }
622
623 if (*cpu_id >= sdw_cpu_dai_num) {
624 dev_err(dev, " invalid cpu dai index %d", *cpu_id);
625 return -EINVAL;
626 }
627
628 playback = (stream == SNDRV_PCM_STREAM_PLAYBACK);
629 capture = (stream == SNDRV_PCM_STREAM_CAPTURE);
630 init_dai_link(dai_links + *be_index, *be_index, name,
631 playback, capture,
632 cpus + *cpu_id, cpu_dai_num,
633 codecs, codec_num,
634 NULL, &sdw_ops);
635
636 ret = set_codec_init_func(link, dai_links + (*be_index)++,
637 playback, group_id);
638 if (ret < 0) {
639 dev_err(dev, "failed to init codec %d", codec_index);
640 return ret;
641 }
642
643 *cpu_id += cpu_dai_num;
644 j++;
645 }
646
647 return 0;
648}
649
650
651
652
653
654
655static inline int get_next_be_id(struct snd_soc_dai_link *links,
656 int be_id)
657{
658 return links[be_id - 1].id + 1;
659}
660
661static int sof_card_dai_links_create(struct device *dev,
662 struct snd_soc_acpi_mach *mach,
663 struct snd_soc_card *card)
664{
665 int ssp_num, sdw_be_num = 0, hdmi_num = 0, dmic_num;
666 struct snd_soc_dai_link_component *idisp_components;
667 struct snd_soc_dai_link_component *ssp_components;
668 struct snd_soc_acpi_mach_params *mach_params;
669 const struct snd_soc_acpi_link_adr *adr_link;
670 struct snd_soc_dai_link_component *cpus;
671 bool group_generated[SDW_MAX_GROUPS];
672 int ssp_codec_index, ssp_mask;
673 struct snd_soc_dai_link *links;
674 int num_links, link_id = 0;
675 char *name, *cpu_name;
676 int total_cpu_dai_num;
677 int sdw_cpu_dai_num;
678 int i, j, be_id = 0;
679 int cpu_id = 0;
680 int comp_num;
681 int ret;
682
683
684 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
685 codec_info_list[i].amp_num = 0;
686
687 hdmi_num = sof_sdw_quirk & SOF_SDW_TGL_HDMI ?
688 SOF_TGL_HDMI_COUNT : SOF_PRE_TGL_HDMI_COUNT;
689
690 ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk);
691
692
693
694
695
696
697 ssp_codec_index = find_codec_info_acpi(mach->id);
698 ssp_num = ssp_codec_index >= 0 ? hweight_long(ssp_mask) : 0;
699 comp_num = hdmi_num + ssp_num;
700
701 mach_params = &mach->mach_params;
702 ret = get_sdw_dailink_info(mach_params->links,
703 &sdw_be_num, &sdw_cpu_dai_num);
704 if (ret < 0) {
705 dev_err(dev, "failed to get sdw link info %d", ret);
706 return ret;
707 }
708
709
710 dmic_num = (sof_sdw_quirk & SOF_SDW_PCH_DMIC) ? 2 : 0;
711 comp_num += dmic_num;
712
713 dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d", sdw_be_num, ssp_num,
714 dmic_num, hdmi_num);
715
716
717 num_links = comp_num + sdw_be_num;
718 links = devm_kcalloc(dev, num_links, sizeof(*links), GFP_KERNEL);
719
720
721 total_cpu_dai_num = comp_num + sdw_cpu_dai_num;
722 cpus = devm_kcalloc(dev, total_cpu_dai_num, sizeof(*cpus),
723 GFP_KERNEL);
724
725 if (!links || !cpus)
726 return -ENOMEM;
727
728
729 if (!sdw_be_num)
730 goto SSP;
731
732 adr_link = mach_params->links;
733 if (!adr_link)
734 return -EINVAL;
735
736
737
738
739
740
741 for (i = 0; i < SDW_MAX_GROUPS; i++)
742 group_generated[i] = false;
743
744
745 for (; adr_link->num_adr; adr_link++) {
746 const struct snd_soc_acpi_endpoint *endpoint;
747
748 endpoint = adr_link->adr_d->endpoints;
749 if (endpoint->aggregated && !endpoint->group_id) {
750 dev_err(dev, "invalid group id on link %x",
751 adr_link->mask);
752 continue;
753 }
754
755
756 if (endpoint->aggregated &&
757 group_generated[endpoint->group_id])
758 continue;
759
760 ret = create_sdw_dailink(dev, &be_id, links, sdw_be_num,
761 sdw_cpu_dai_num, cpus, adr_link,
762 &cpu_id, group_generated);
763 if (ret < 0) {
764 dev_err(dev, "failed to create dai link %d", be_id);
765 return -ENOMEM;
766 }
767 }
768
769
770 link_id = be_id;
771
772
773 be_id = get_next_be_id(links, be_id);
774
775SSP:
776
777 if (!ssp_num)
778 goto DMIC;
779
780 for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) {
781 struct sof_sdw_codec_info *info;
782 int playback, capture;
783 char *codec_name;
784
785 if (!(ssp_mask & 0x1))
786 continue;
787
788 name = devm_kasprintf(dev, GFP_KERNEL,
789 "SSP%d-Codec", i);
790 if (!name)
791 return -ENOMEM;
792
793 cpu_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i);
794 if (!cpu_name)
795 return -ENOMEM;
796
797 ssp_components = devm_kzalloc(dev, sizeof(*ssp_components),
798 GFP_KERNEL);
799 if (!ssp_components)
800 return -ENOMEM;
801
802 info = &codec_info_list[ssp_codec_index];
803 codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d",
804 info->acpi_id, j++);
805 if (!codec_name)
806 return -ENOMEM;
807
808 ssp_components->name = codec_name;
809 ssp_components->dai_name = info->dai_name;
810 cpus[cpu_id].dai_name = cpu_name;
811
812 playback = info->direction[SNDRV_PCM_STREAM_PLAYBACK];
813 capture = info->direction[SNDRV_PCM_STREAM_CAPTURE];
814 init_dai_link(links + link_id, be_id, name,
815 playback, capture,
816 cpus + cpu_id, 1,
817 ssp_components, 1,
818 NULL, info->ops);
819
820 ret = info->init(NULL, links + link_id, info, 0);
821 if (ret < 0)
822 return ret;
823
824 INC_ID(be_id, cpu_id, link_id);
825 }
826
827DMIC:
828
829 if (dmic_num > 0) {
830 cpus[cpu_id].dai_name = "DMIC01 Pin";
831 init_dai_link(links + link_id, be_id, "dmic01",
832 0, 1,
833 cpus + cpu_id, 1,
834 dmic_component, 1,
835 sof_sdw_dmic_init, NULL);
836 INC_ID(be_id, cpu_id, link_id);
837
838 cpus[cpu_id].dai_name = "DMIC16k Pin";
839 init_dai_link(links + link_id, be_id, "dmic16k",
840 0, 1,
841 cpus + cpu_id, 1,
842 dmic_component, 1,
843
844 NULL, NULL);
845 INC_ID(be_id, cpu_id, link_id);
846 }
847
848
849 if (hdmi_num > 0) {
850 idisp_components = devm_kcalloc(dev, hdmi_num,
851 sizeof(*idisp_components),
852 GFP_KERNEL);
853 if (!idisp_components)
854 return -ENOMEM;
855 }
856
857 for (i = 0; i < hdmi_num; i++) {
858 name = devm_kasprintf(dev, GFP_KERNEL,
859 "iDisp%d", i + 1);
860 if (!name)
861 return -ENOMEM;
862
863 idisp_components[i].name = "ehdaudio0D2";
864 idisp_components[i].dai_name = devm_kasprintf(dev,
865 GFP_KERNEL,
866 "intel-hdmi-hifi%d",
867 i + 1);
868 if (!idisp_components[i].dai_name)
869 return -ENOMEM;
870
871 cpu_name = devm_kasprintf(dev, GFP_KERNEL,
872 "iDisp%d Pin", i + 1);
873 if (!cpu_name)
874 return -ENOMEM;
875
876 cpus[cpu_id].dai_name = cpu_name;
877 init_dai_link(links + link_id, be_id, name,
878 1, 0,
879 cpus + cpu_id, 1,
880 idisp_components + i, 1,
881 sof_sdw_hdmi_init, NULL);
882 INC_ID(be_id, cpu_id, link_id);
883 }
884
885 card->dai_link = links;
886 card->num_links = num_links;
887
888 return 0;
889}
890
891
892static const char sdw_card_long_name[] = "Intel Soundwire SOF";
893
894static struct snd_soc_card card_sof_sdw = {
895 .name = "soundwire",
896 .late_probe = sof_sdw_hdmi_card_late_probe,
897 .codec_conf = codec_conf,
898 .num_configs = ARRAY_SIZE(codec_conf),
899};
900
901static int mc_probe(struct platform_device *pdev)
902{
903 struct snd_soc_card *card = &card_sof_sdw;
904 struct snd_soc_acpi_mach *mach;
905 struct mc_private *ctx;
906 int amp_num = 0, i;
907 int ret;
908
909 dev_dbg(&pdev->dev, "Entry %s\n", __func__);
910
911 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
912 if (!ctx)
913 return -ENOMEM;
914
915 dmi_check_system(sof_sdw_quirk_table);
916
917 INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
918
919 card->dev = &pdev->dev;
920
921 mach = pdev->dev.platform_data;
922 ret = sof_card_dai_links_create(&pdev->dev, mach,
923 card);
924 if (ret < 0)
925 return ret;
926
927 ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv;
928
929 snd_soc_card_set_drvdata(card, ctx);
930
931
932
933
934
935
936 for (i = 0; i < ARRAY_SIZE(codec_info_list); i++)
937 amp_num += codec_info_list[i].amp_num;
938
939 card->components = devm_kasprintf(card->dev, GFP_KERNEL,
940 "cfg-spk:%d cfg-amp:%d",
941 (sof_sdw_quirk & SOF_SDW_FOUR_SPK)
942 ? 4 : 2, amp_num);
943 if (!card->components)
944 return -ENOMEM;
945
946 card->long_name = sdw_card_long_name;
947
948
949 ret = devm_snd_soc_register_card(&pdev->dev, card);
950 if (ret) {
951 dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
952 return ret;
953 }
954
955 platform_set_drvdata(pdev, card);
956
957 return ret;
958}
959
960static struct platform_driver sof_sdw_driver = {
961 .driver = {
962 .name = "sof_sdw",
963 .pm = &snd_soc_pm_ops,
964 },
965 .probe = mc_probe,
966};
967
968module_platform_driver(sof_sdw_driver);
969
970MODULE_DESCRIPTION("ASoC SoundWire Generic Machine driver");
971MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>");
972MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
973MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
974MODULE_LICENSE("GPL v2");
975MODULE_ALIAS("platform:sof_sdw");
976