1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright(c) 2024 Advanced Micro Devices, Inc.
5 * acp-sdw-legacy-mach - ASoC legacy Machine driver for AMD SoundWire platforms
8 #include <linux/bitmap.h>
9 #include <linux/device.h>
10 #include <linux/dmi.h>
11 #include <linux/module.h>
12 #include <linux/soundwire/sdw.h>
13 #include <linux/soundwire/sdw_type.h>
14 #include <sound/soc.h>
15 #include <sound/soc-acpi.h>
16 #include "soc_amd_sdw_common.h"
17 #include "../../codecs/rt711.h"
19 static unsigned long soc_sdw_quirk
= RT711_JD1
;
20 static int quirk_override
= -1;
21 module_param_named(quirk
, quirk_override
, int, 0444);
22 MODULE_PARM_DESC(quirk
, "Board-specific quirk override");
24 static void log_quirks(struct device
*dev
)
26 if (SOC_JACK_JDSRC(soc_sdw_quirk
))
27 dev_dbg(dev
, "quirk realtek,jack-detect-source %ld\n",
28 SOC_JACK_JDSRC(soc_sdw_quirk
));
29 if (soc_sdw_quirk
& ASOC_SDW_ACP_DMIC
)
30 dev_dbg(dev
, "quirk SOC_SDW_ACP_DMIC enabled\n");
33 static int soc_sdw_quirk_cb(const struct dmi_system_id
*id
)
35 soc_sdw_quirk
= (unsigned long)id
->driver_data
;
39 static const struct dmi_system_id soc_sdw_quirk_table
[] = {
41 .callback
= soc_sdw_quirk_cb
,
43 DMI_MATCH(DMI_SYS_VENDOR
, "AMD"),
44 DMI_MATCH(DMI_PRODUCT_NAME
, "Birman-PHX"),
46 .driver_data
= (void *)RT711_JD2
,
51 static const struct snd_soc_ops sdw_ops
= {
52 .startup
= asoc_sdw_startup
,
53 .prepare
= asoc_sdw_prepare
,
54 .trigger
= asoc_sdw_trigger
,
55 .hw_params
= asoc_sdw_hw_params
,
56 .hw_free
= asoc_sdw_hw_free
,
57 .shutdown
= asoc_sdw_shutdown
,
60 static const char * const type_strings
[] = {"SimpleJack", "SmartAmp", "SmartMic"};
62 static int create_sdw_dailink(struct snd_soc_card
*card
,
63 struct asoc_sdw_dailink
*soc_dai
,
64 struct snd_soc_dai_link
**dai_links
,
65 int *be_id
, struct snd_soc_codec_conf
**codec_conf
,
66 struct snd_soc_dai_link_component
*sdw_platform_component
)
68 struct device
*dev
= card
->dev
;
69 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
70 struct amd_mc_ctx
*amd_ctx
= (struct amd_mc_ctx
*)ctx
->private;
71 struct asoc_sdw_endpoint
*soc_end
;
76 list_for_each_entry(soc_end
, &soc_dai
->endpoints
, list
) {
77 if (soc_end
->name_prefix
) {
78 (*codec_conf
)->dlc
.name
= soc_end
->codec_name
;
79 (*codec_conf
)->name_prefix
= soc_end
->name_prefix
;
83 if (soc_end
->include_sidecar
) {
84 ret
= soc_end
->codec_info
->add_sidecar(card
, dai_links
, codec_conf
);
90 for_each_pcm_streams(stream
) {
91 static const char * const sdw_stream_name
[] = {
92 "SDW%d-PIN%d-PLAYBACK",
93 "SDW%d-PIN%d-CAPTURE",
94 "SDW%d-PIN%d-PLAYBACK-%s",
95 "SDW%d-PIN%d-CAPTURE-%s",
97 struct snd_soc_dai_link_ch_map
*codec_maps
;
98 struct snd_soc_dai_link_component
*codecs
;
99 struct snd_soc_dai_link_component
*cpus
;
100 int num_cpus
= hweight32(soc_dai
->link_mask
[stream
]);
101 int num_codecs
= soc_dai
->num_devs
[stream
];
102 int playback
, capture
;
106 if (!soc_dai
->num_devs
[stream
])
109 soc_end
= list_first_entry(&soc_dai
->endpoints
,
110 struct asoc_sdw_endpoint
, list
);
112 *be_id
= soc_end
->dai_info
->dailink
[stream
];
114 dev_err(dev
, "Invalid dailink id %d\n", *be_id
);
118 switch (amd_ctx
->acp_rev
) {
120 ret
= get_acp63_cpu_pin_id(ffs(soc_end
->link_mask
- 1),
121 *be_id
, &cpu_pin_id
, dev
);
128 /* create stream name according to first link id */
129 if (ctx
->append_dai_type
) {
130 name
= devm_kasprintf(dev
, GFP_KERNEL
,
131 sdw_stream_name
[stream
+ 2],
132 ffs(soc_end
->link_mask
) - 1,
134 type_strings
[soc_end
->dai_info
->dai_type
]);
136 name
= devm_kasprintf(dev
, GFP_KERNEL
,
137 sdw_stream_name
[stream
],
138 ffs(soc_end
->link_mask
) - 1,
144 cpus
= devm_kcalloc(dev
, num_cpus
, sizeof(*cpus
), GFP_KERNEL
);
148 codecs
= devm_kcalloc(dev
, num_codecs
, sizeof(*codecs
), GFP_KERNEL
);
152 codec_maps
= devm_kcalloc(dev
, num_codecs
, sizeof(*codec_maps
), GFP_KERNEL
);
156 list_for_each_entry(soc_end
, &soc_dai
->endpoints
, list
) {
157 if (!soc_end
->dai_info
->direction
[stream
])
160 int link_num
= ffs(soc_end
->link_mask
) - 1;
162 cpus
->dai_name
= devm_kasprintf(dev
, GFP_KERNEL
,
164 link_num
, cpu_pin_id
);
165 dev_dbg(dev
, "cpu->dai_name:%s\n", cpus
->dai_name
);
169 codec_maps
[j
].cpu
= 0;
170 codec_maps
[j
].codec
= j
;
172 codecs
[j
].name
= soc_end
->codec_name
;
173 codecs
[j
].dai_name
= soc_end
->dai_info
->dai_name
;
177 WARN_ON(j
!= num_codecs
);
179 playback
= (stream
== SNDRV_PCM_STREAM_PLAYBACK
);
180 capture
= (stream
== SNDRV_PCM_STREAM_CAPTURE
);
182 asoc_sdw_init_dai_link(dev
, *dai_links
, be_id
, name
, playback
, capture
,
183 cpus
, num_cpus
, sdw_platform_component
,
184 1, codecs
, num_codecs
,
185 0, asoc_sdw_rtd_init
, &sdw_ops
);
187 * SoundWire DAILINKs use 'stream' functions and Bank Switch operations
188 * based on wait_for_completion(), tag them as 'nonatomic'.
190 (*dai_links
)->nonatomic
= true;
191 (*dai_links
)->ch_maps
= codec_maps
;
193 list_for_each_entry(soc_end
, &soc_dai
->endpoints
, list
) {
194 if (soc_end
->dai_info
->init
)
195 soc_end
->dai_info
->init(card
, *dai_links
,
206 static int create_sdw_dailinks(struct snd_soc_card
*card
,
207 struct snd_soc_dai_link
**dai_links
, int *be_id
,
208 struct asoc_sdw_dailink
*soc_dais
,
209 struct snd_soc_codec_conf
**codec_conf
)
211 struct device
*dev
= card
->dev
;
212 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
213 struct amd_mc_ctx
*amd_ctx
= (struct amd_mc_ctx
*)ctx
->private;
214 struct snd_soc_dai_link_component
*sdw_platform_component
;
217 sdw_platform_component
= devm_kzalloc(dev
, sizeof(struct snd_soc_dai_link_component
),
219 if (!sdw_platform_component
)
222 switch (amd_ctx
->acp_rev
) {
224 sdw_platform_component
->name
= "amd_ps_sdw_dma.0";
230 /* generate DAI links by each sdw link */
231 while (soc_dais
->initialised
) {
234 ret
= create_sdw_dailink(card
, soc_dais
, dai_links
,
235 ¤t_be_id
, codec_conf
, sdw_platform_component
);
239 /* Update the be_id to match the highest ID used for SDW link */
240 if (*be_id
< current_be_id
)
241 *be_id
= current_be_id
;
249 static int create_dmic_dailinks(struct snd_soc_card
*card
,
250 struct snd_soc_dai_link
**dai_links
, int *be_id
, int no_pcm
)
252 struct device
*dev
= card
->dev
;
253 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
254 struct amd_mc_ctx
*amd_ctx
= (struct amd_mc_ctx
*)ctx
->private;
255 struct snd_soc_dai_link_component
*pdm_cpu
;
256 struct snd_soc_dai_link_component
*pdm_platform
;
259 pdm_cpu
= devm_kzalloc(dev
, sizeof(struct snd_soc_dai_link_component
), GFP_KERNEL
);
263 pdm_platform
= devm_kzalloc(dev
, sizeof(struct snd_soc_dai_link_component
), GFP_KERNEL
);
267 switch (amd_ctx
->acp_rev
) {
269 pdm_cpu
->name
= "acp_ps_pdm_dma.0";
270 pdm_platform
->name
= "acp_ps_pdm_dma.0";
276 *be_id
= ACP_DMIC_BE_ID
;
277 ret
= asoc_sdw_init_simple_dai_link(dev
, *dai_links
, be_id
, "acp-dmic-codec",
278 0, 1, // DMIC only supports capture
279 pdm_cpu
->name
, pdm_platform
->name
, 1,
280 "dmic-codec.0", "dmic-hifi", no_pcm
,
281 asoc_sdw_dmic_init
, NULL
);
290 static int soc_card_dai_links_create(struct snd_soc_card
*card
)
292 struct device
*dev
= card
->dev
;
293 struct snd_soc_acpi_mach
*mach
= dev_get_platdata(card
->dev
);
294 int sdw_be_num
= 0, dmic_num
= 0;
295 struct asoc_sdw_mc_private
*ctx
= snd_soc_card_get_drvdata(card
);
296 struct snd_soc_acpi_mach_params
*mach_params
= &mach
->mach_params
;
297 struct asoc_sdw_endpoint
*soc_ends
__free(kfree
) = NULL
;
298 struct asoc_sdw_dailink
*soc_dais
__free(kfree
) = NULL
;
299 struct snd_soc_codec_conf
*codec_conf
;
300 struct snd_soc_dai_link
*dai_links
;
307 ret
= asoc_sdw_count_sdw_endpoints(card
, &num_devs
, &num_ends
);
309 dev_err(dev
, "failed to count devices/endpoints: %d\n", ret
);
313 /* One per DAI link, worst case is a DAI link for every endpoint */
314 soc_dais
= kcalloc(num_ends
, sizeof(*soc_dais
), GFP_KERNEL
);
318 /* One per endpoint, ie. each DAI on each codec/amp */
319 soc_ends
= kcalloc(num_ends
, sizeof(*soc_ends
), GFP_KERNEL
);
323 ret
= asoc_sdw_parse_sdw_endpoints(card
, soc_dais
, soc_ends
, &num_devs
);
330 if (soc_sdw_quirk
& ASOC_SDW_ACP_DMIC
|| mach_params
->dmic_num
)
333 dev_dbg(dev
, "sdw %d, dmic %d", sdw_be_num
, dmic_num
);
335 codec_conf
= devm_kcalloc(dev
, num_devs
, sizeof(*codec_conf
), GFP_KERNEL
);
339 /* allocate BE dailinks */
340 num_links
= sdw_be_num
+ dmic_num
;
341 dai_links
= devm_kcalloc(dev
, num_links
, sizeof(*dai_links
), GFP_KERNEL
);
345 card
->codec_conf
= codec_conf
;
346 card
->num_configs
= num_devs
;
347 card
->dai_link
= dai_links
;
348 card
->num_links
= num_links
;
352 ret
= create_sdw_dailinks(card
, &dai_links
, &be_id
,
353 soc_dais
, &codec_conf
);
360 if (ctx
->ignore_internal_dmic
) {
361 dev_warn(dev
, "Ignoring ACP DMIC\n");
363 ret
= create_dmic_dailinks(card
, &dai_links
, &be_id
, 0);
369 WARN_ON(codec_conf
!= card
->codec_conf
+ card
->num_configs
);
370 WARN_ON(dai_links
!= card
->dai_link
+ card
->num_links
);
375 static int mc_probe(struct platform_device
*pdev
)
377 struct snd_soc_acpi_mach
*mach
= dev_get_platdata(&pdev
->dev
);
378 struct snd_soc_card
*card
;
379 struct amd_mc_ctx
*amd_ctx
;
380 struct asoc_sdw_mc_private
*ctx
;
384 amd_ctx
= devm_kzalloc(&pdev
->dev
, sizeof(*amd_ctx
), GFP_KERNEL
);
388 amd_ctx
->acp_rev
= mach
->mach_params
.subsystem_rev
;
389 amd_ctx
->max_sdw_links
= ACP63_SDW_MAX_LINKS
;
390 ctx
= devm_kzalloc(&pdev
->dev
, sizeof(*ctx
), GFP_KERNEL
);
393 ctx
->codec_info_list_count
= asoc_sdw_get_codec_info_list_count();
394 ctx
->private = amd_ctx
;
396 card
->dev
= &pdev
->dev
;
397 card
->name
= "amd-soundwire";
398 card
->owner
= THIS_MODULE
;
399 card
->late_probe
= asoc_sdw_card_late_probe
;
401 snd_soc_card_set_drvdata(card
, ctx
);
403 dmi_check_system(soc_sdw_quirk_table
);
405 if (quirk_override
!= -1) {
406 dev_info(card
->dev
, "Overriding quirk 0x%lx => 0x%x\n",
407 soc_sdw_quirk
, quirk_override
);
408 soc_sdw_quirk
= quirk_override
;
411 log_quirks(card
->dev
);
413 ctx
->mc_quirk
= soc_sdw_quirk
;
414 dev_dbg(card
->dev
, "legacy quirk 0x%lx\n", ctx
->mc_quirk
);
415 /* reset amp_num to ensure amp_num++ starts from 0 in each probe */
416 for (i
= 0; i
< ctx
->codec_info_list_count
; i
++)
417 codec_info_list
[i
].amp_num
= 0;
419 ret
= soc_card_dai_links_create(card
);
424 * the default amp_num is zero for each codec and
425 * amp_num will only be increased for active amp
426 * codecs on used platform
428 for (i
= 0; i
< ctx
->codec_info_list_count
; i
++)
429 amp_num
+= codec_info_list
[i
].amp_num
;
431 card
->components
= devm_kasprintf(card
->dev
, GFP_KERNEL
,
432 " cfg-amp:%d", amp_num
);
433 if (!card
->components
)
435 if (mach
->mach_params
.dmic_num
) {
436 card
->components
= devm_kasprintf(card
->dev
, GFP_KERNEL
,
437 "%s mic:dmic cfg-mics:%d",
439 mach
->mach_params
.dmic_num
);
440 if (!card
->components
)
444 /* Register the card */
445 ret
= devm_snd_soc_register_card(card
->dev
, card
);
447 dev_err_probe(card
->dev
, ret
, "snd_soc_register_card failed %d\n", ret
);
448 asoc_sdw_mc_dailink_exit_loop(card
);
452 platform_set_drvdata(pdev
, card
);
457 static void mc_remove(struct platform_device
*pdev
)
459 struct snd_soc_card
*card
= platform_get_drvdata(pdev
);
461 asoc_sdw_mc_dailink_exit_loop(card
);
464 static const struct platform_device_id mc_id_table
[] = {
468 MODULE_DEVICE_TABLE(platform
, mc_id_table
);
470 static struct platform_driver soc_sdw_driver
= {
473 .pm
= &snd_soc_pm_ops
,
477 .id_table
= mc_id_table
,
480 module_platform_driver(soc_sdw_driver
);
482 MODULE_DESCRIPTION("ASoC AMD SoundWire Legacy Generic Machine driver");
483 MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>");
484 MODULE_LICENSE("GPL");
485 MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
486 MODULE_IMPORT_NS("SND_SOC_AMD_SDW_MACH");