xref: /openbmc/linux/sound/soc/fsl/imx-spdif.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
158dbd101SAndra Danciu // SPDX-License-Identifier: GPL-2.0+
258dbd101SAndra Danciu //
358dbd101SAndra Danciu // Copyright (C) 2013 Freescale Semiconductor, Inc.
42a956ec0SNicolin Chen 
52a956ec0SNicolin Chen #include <linux/module.h>
62a956ec0SNicolin Chen #include <linux/of_platform.h>
72a956ec0SNicolin Chen #include <sound/soc.h>
82a956ec0SNicolin Chen 
92a956ec0SNicolin Chen struct imx_spdif_data {
1014c3aa98SNicolin Chen 	struct snd_soc_dai_link dai;
112a956ec0SNicolin Chen 	struct snd_soc_card card;
122a956ec0SNicolin Chen };
132a956ec0SNicolin Chen 
imx_spdif_audio_probe(struct platform_device * pdev)142a956ec0SNicolin Chen static int imx_spdif_audio_probe(struct platform_device *pdev)
152a956ec0SNicolin Chen {
162a956ec0SNicolin Chen 	struct device_node *spdif_np, *np = pdev->dev.of_node;
172a956ec0SNicolin Chen 	struct imx_spdif_data *data;
188337ef4fSKuninori Morimoto 	struct snd_soc_dai_link_component *comp;
1914c3aa98SNicolin Chen 	int ret = 0;
202a956ec0SNicolin Chen 
212a956ec0SNicolin Chen 	spdif_np = of_parse_phandle(np, "spdif-controller", 0);
222a956ec0SNicolin Chen 	if (!spdif_np) {
232a956ec0SNicolin Chen 		dev_err(&pdev->dev, "failed to find spdif-controller\n");
242a956ec0SNicolin Chen 		ret = -EINVAL;
252a956ec0SNicolin Chen 		goto end;
262a956ec0SNicolin Chen 	}
272a956ec0SNicolin Chen 
282a956ec0SNicolin Chen 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
29*2324bc10SKuninori Morimoto 	comp = devm_kzalloc(&pdev->dev, sizeof(*comp), GFP_KERNEL);
308337ef4fSKuninori Morimoto 	if (!data || !comp) {
312a956ec0SNicolin Chen 		ret = -ENOMEM;
322a956ec0SNicolin Chen 		goto end;
332a956ec0SNicolin Chen 	}
342a956ec0SNicolin Chen 
35*2324bc10SKuninori Morimoto 	/*
36*2324bc10SKuninori Morimoto 	 * CPU == Platform
37*2324bc10SKuninori Morimoto 	 * platform is using soc-generic-dmaengine-pcm
38*2324bc10SKuninori Morimoto 	 */
39*2324bc10SKuninori Morimoto 	data->dai.cpus		=
40*2324bc10SKuninori Morimoto 	data->dai.platforms	= comp;
418337ef4fSKuninori Morimoto 	data->dai.codecs	= &asoc_dummy_dlc;
428337ef4fSKuninori Morimoto 
438337ef4fSKuninori Morimoto 	data->dai.num_cpus	= 1;
448337ef4fSKuninori Morimoto 	data->dai.num_codecs	= 1;
4509cda705SShengjiu Wang 	data->dai.num_platforms	= 1;
468337ef4fSKuninori Morimoto 
4714c3aa98SNicolin Chen 	data->dai.name = "S/PDIF PCM";
4814c3aa98SNicolin Chen 	data->dai.stream_name = "S/PDIF PCM";
498337ef4fSKuninori Morimoto 	data->dai.cpus->of_node = spdif_np;
508337ef4fSKuninori Morimoto 	data->dai.playback_only = true;
518337ef4fSKuninori Morimoto 	data->dai.capture_only = true;
5214c3aa98SNicolin Chen 
5314c3aa98SNicolin Chen 	if (of_property_read_bool(np, "spdif-out"))
542a956ec0SNicolin Chen 		data->dai.capture_only = false;
5514c3aa98SNicolin Chen 
5614c3aa98SNicolin Chen 	if (of_property_read_bool(np, "spdif-in"))
572a956ec0SNicolin Chen 		data->dai.playback_only = false;
5814c3aa98SNicolin Chen 
5914c3aa98SNicolin Chen 	if (data->dai.playback_only && data->dai.capture_only) {
602a956ec0SNicolin Chen 		dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n");
6114c3aa98SNicolin Chen 		goto end;
622a956ec0SNicolin Chen 	}
6314c3aa98SNicolin Chen 
642a956ec0SNicolin Chen 	data->card.dev = &pdev->dev;
652a956ec0SNicolin Chen 	data->card.dai_link = &data->dai;
662a956ec0SNicolin Chen 	data->card.num_links = 1;
6714c3aa98SNicolin Chen 	data->card.owner = THIS_MODULE;
6814c3aa98SNicolin Chen 
697a3a9070SFabio Estevam 	ret = snd_soc_of_parse_card_name(&data->card, "model");
702a956ec0SNicolin Chen 	if (ret)
712a956ec0SNicolin Chen 		goto end;
722a956ec0SNicolin Chen 
7314c3aa98SNicolin Chen 	ret = devm_snd_soc_register_card(&pdev->dev, &data->card);
742a956ec0SNicolin Chen 	if (ret)
75ff27d9b3SSachin Kamat 		dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n");
762e6f557cSKuninori Morimoto 
772e6f557cSKuninori Morimoto end:
782a956ec0SNicolin Chen 	of_node_put(spdif_np);
792a956ec0SNicolin Chen 
802a956ec0SNicolin Chen 	return ret;
812a956ec0SNicolin Chen }
822a956ec0SNicolin Chen 
832a956ec0SNicolin Chen static const struct of_device_id imx_spdif_dt_ids[] = {
842a956ec0SNicolin Chen 	{ .compatible = "fsl,imx-audio-spdif", },
852a956ec0SNicolin Chen 	{ /* sentinel */ }
862a956ec0SNicolin Chen };
872a956ec0SNicolin Chen MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids);
882a956ec0SNicolin Chen 
892a956ec0SNicolin Chen static struct platform_driver imx_spdif_driver = {
902a956ec0SNicolin Chen 	.driver = {
912a956ec0SNicolin Chen 		.name = "imx-spdif",
922a956ec0SNicolin Chen 		.pm = &snd_soc_pm_ops,
932a956ec0SNicolin Chen 		.of_match_table = imx_spdif_dt_ids,
9443ac9469SZidan Wang 	},
952a956ec0SNicolin Chen 	.probe = imx_spdif_audio_probe,
962a956ec0SNicolin Chen };
972a956ec0SNicolin Chen 
982a956ec0SNicolin Chen module_platform_driver(imx_spdif_driver);
992a956ec0SNicolin Chen 
1002a956ec0SNicolin Chen MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1012a956ec0SNicolin Chen MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
1022a956ec0SNicolin Chen MODULE_LICENSE("GPL v2");
1032a956ec0SNicolin Chen MODULE_ALIAS("platform:imx-spdif");
1042a956ec0SNicolin Chen