1 /* 2 * Copyright (C) 2013 Freescale Semiconductor, Inc. 3 * 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: 7 * 8 * http://www.opensource.org/licenses/gpl-license.html 9 * http://www.gnu.org/copyleft/gpl.html 10 */ 11 12 #include <linux/module.h> 13 #include <linux/of_platform.h> 14 #include <sound/soc.h> 15 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; 21 }; 22 23 static int imx_spdif_audio_probe(struct platform_device *pdev) 24 { 25 struct device_node *spdif_np, *np = pdev->dev.of_node; 26 struct imx_spdif_data *data; 27 int ret = 0, num_links = 0; 28 29 spdif_np = of_parse_phandle(np, "spdif-controller", 0); 30 if (!spdif_np) { 31 dev_err(&pdev->dev, "failed to find spdif-controller\n"); 32 ret = -EINVAL; 33 goto end; 34 } 35 36 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 37 if (!data) { 38 dev_err(&pdev->dev, "failed to allocate memory\n"); 39 ret = -ENOMEM; 40 goto end; 41 } 42 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; 50 num_links++; 51 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); 56 goto end; 57 } 58 } 59 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; 67 num_links++; 68 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); 73 goto error_dit; 74 } 75 } 76 77 if (!num_links) { 78 dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n"); 79 goto error_dir; 80 } 81 82 data->card.dev = &pdev->dev; 83 data->card.num_links = num_links; 84 data->card.dai_link = data->dai; 85 86 ret = snd_soc_of_parse_card_name(&data->card, "model"); 87 if (ret) 88 goto error_dir; 89 90 ret = devm_snd_soc_register_card(&pdev->dev, &data->card); 91 if (ret) { 92 dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); 93 goto error_dir; 94 } 95 96 platform_set_drvdata(pdev, data); 97 98 goto end; 99 100 error_dir: 101 if (data->rxdev) 102 platform_device_unregister(data->rxdev); 103 error_dit: 104 if (data->txdev) 105 platform_device_unregister(data->txdev); 106 end: 107 if (spdif_np) 108 of_node_put(spdif_np); 109 110 return ret; 111 } 112 113 static int imx_spdif_audio_remove(struct platform_device *pdev) 114 { 115 struct imx_spdif_data *data = platform_get_drvdata(pdev); 116 117 if (data->rxdev) 118 platform_device_unregister(data->rxdev); 119 if (data->txdev) 120 platform_device_unregister(data->txdev); 121 122 return 0; 123 } 124 125 static const struct of_device_id imx_spdif_dt_ids[] = { 126 { .compatible = "fsl,imx-audio-spdif", }, 127 { /* sentinel */ } 128 }; 129 MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids); 130 131 static struct platform_driver imx_spdif_driver = { 132 .driver = { 133 .name = "imx-spdif", 134 .owner = THIS_MODULE, 135 .of_match_table = imx_spdif_dt_ids, 136 }, 137 .probe = imx_spdif_audio_probe, 138 .remove = imx_spdif_audio_remove, 139 }; 140 141 module_platform_driver(imx_spdif_driver); 142 143 MODULE_AUTHOR("Freescale Semiconductor, Inc."); 144 MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver"); 145 MODULE_LICENSE("GPL v2"); 146 MODULE_ALIAS("platform:imx-spdif"); 147