2 * Copyright (C) 2013 Freescale Semiconductor, Inc.
4 * The code contained herein is licensed under the GNU General Public
5 * License. You may obtain a copy of the GNU General Public License
6 * Version 2 or later at the following locations:
8 * http://www.opensource.org/licenses/gpl-license.html
9 * http://www.gnu.org/copyleft/gpl.html
12 #include <linux/module.h>
13 #include <linux/of_platform.h>
14 #include <sound/soc.h>
16 struct imx_spdif_data
{
17 struct snd_soc_dai_link dai
[2];
18 struct snd_soc_card card
;
19 struct platform_device
*txdev
;
20 struct platform_device
*rxdev
;
23 static int imx_spdif_audio_probe(struct platform_device
*pdev
)
25 struct device_node
*spdif_np
, *np
= pdev
->dev
.of_node
;
26 struct imx_spdif_data
*data
;
27 int ret
= 0, num_links
= 0;
29 spdif_np
= of_parse_phandle(np
, "spdif-controller", 0);
31 dev_err(&pdev
->dev
, "failed to find spdif-controller\n");
36 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
38 dev_err(&pdev
->dev
, "failed to allocate memory\n");
43 if (of_property_read_bool(np
, "spdif-out")) {
44 data
->dai
[num_links
].name
= "S/PDIF TX";
45 data
->dai
[num_links
].stream_name
= "S/PDIF PCM Playback";
46 data
->dai
[num_links
].codec_dai_name
= "dit-hifi";
47 data
->dai
[num_links
].codec_name
= "spdif-dit";
48 data
->dai
[num_links
].cpu_of_node
= spdif_np
;
49 data
->dai
[num_links
].platform_of_node
= spdif_np
;
52 data
->txdev
= platform_device_register_simple("spdif-dit", -1, NULL
, 0);
53 if (IS_ERR(data
->txdev
)) {
54 ret
= PTR_ERR(data
->txdev
);
55 dev_err(&pdev
->dev
, "register dit failed: %d\n", ret
);
60 if (of_property_read_bool(np
, "spdif-in")) {
61 data
->dai
[num_links
].name
= "S/PDIF RX";
62 data
->dai
[num_links
].stream_name
= "S/PDIF PCM Capture";
63 data
->dai
[num_links
].codec_dai_name
= "dir-hifi";
64 data
->dai
[num_links
].codec_name
= "spdif-dir";
65 data
->dai
[num_links
].cpu_of_node
= spdif_np
;
66 data
->dai
[num_links
].platform_of_node
= spdif_np
;
69 data
->rxdev
= platform_device_register_simple("spdif-dir", -1, NULL
, 0);
70 if (IS_ERR(data
->rxdev
)) {
71 ret
= PTR_ERR(data
->rxdev
);
72 dev_err(&pdev
->dev
, "register dir failed: %d\n", ret
);
78 dev_err(&pdev
->dev
, "no enabled S/PDIF DAI link\n");
82 data
->card
.dev
= &pdev
->dev
;
83 data
->card
.num_links
= num_links
;
84 data
->card
.dai_link
= data
->dai
;
86 ret
= snd_soc_of_parse_card_name(&data
->card
, "model");
90 ret
= snd_soc_register_card(&data
->card
);
92 dev_err(&pdev
->dev
, "snd_soc_register_card failed: %d\n", ret
);
96 platform_set_drvdata(pdev
, data
);
102 platform_device_unregister(data
->rxdev
);
105 platform_device_unregister(data
->txdev
);
108 of_node_put(spdif_np
);
113 static int imx_spdif_audio_remove(struct platform_device
*pdev
)
115 struct imx_spdif_data
*data
= platform_get_drvdata(pdev
);
118 platform_device_unregister(data
->rxdev
);
120 platform_device_unregister(data
->txdev
);
122 snd_soc_unregister_card(&data
->card
);
127 static const struct of_device_id imx_spdif_dt_ids
[] = {
128 { .compatible
= "fsl,imx-audio-spdif", },
131 MODULE_DEVICE_TABLE(of
, imx_spdif_dt_ids
);
133 static struct platform_driver imx_spdif_driver
= {
136 .owner
= THIS_MODULE
,
137 .of_match_table
= imx_spdif_dt_ids
,
139 .probe
= imx_spdif_audio_probe
,
140 .remove
= imx_spdif_audio_remove
,
143 module_platform_driver(imx_spdif_driver
);
145 MODULE_AUTHOR("Freescale Semiconductor, Inc.");
146 MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver");
147 MODULE_LICENSE("GPL v2");
148 MODULE_ALIAS("platform:imx-spdif");