Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | /* * Copyright (C) 2013 Freescale Semiconductor, Inc. * * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html */ #include <linux/module.h> #include <linux/of_platform.h> #include <sound/soc.h> struct imx_spdif_data { struct snd_soc_dai_link dai[2]; struct snd_soc_card card; struct platform_device *txdev; struct platform_device *rxdev; }; static int imx_spdif_audio_probe(struct platform_device *pdev) { struct device_node *spdif_np, *np = pdev->dev.of_node; struct imx_spdif_data *data; int ret = 0, num_links = 0; spdif_np = of_parse_phandle(np, "spdif-controller", 0); if (!spdif_np) { dev_err(&pdev->dev, "failed to find spdif-controller\n"); ret = -EINVAL; goto end; } data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(&pdev->dev, "failed to allocate memory\n"); ret = -ENOMEM; goto end; } if (of_property_read_bool(np, "spdif-out")) { data->dai[num_links].name = "S/PDIF TX"; data->dai[num_links].stream_name = "S/PDIF PCM Playback"; data->dai[num_links].codec_dai_name = "dit-hifi"; data->dai[num_links].codec_name = "spdif-dit"; data->dai[num_links].cpu_of_node = spdif_np; data->dai[num_links].platform_of_node = spdif_np; num_links++; data->txdev = platform_device_register_simple("spdif-dit", -1, NULL, 0); if (IS_ERR(data->txdev)) { ret = PTR_ERR(data->txdev); dev_err(&pdev->dev, "register dit failed: %d\n", ret); goto end; } } if (of_property_read_bool(np, "spdif-in")) { data->dai[num_links].name = "S/PDIF RX"; data->dai[num_links].stream_name = "S/PDIF PCM Capture"; data->dai[num_links].codec_dai_name = "dir-hifi"; data->dai[num_links].codec_name = "spdif-dir"; data->dai[num_links].cpu_of_node = spdif_np; data->dai[num_links].platform_of_node = spdif_np; num_links++; data->rxdev = platform_device_register_simple("spdif-dir", -1, NULL, 0); if (IS_ERR(data->rxdev)) { ret = PTR_ERR(data->rxdev); dev_err(&pdev->dev, "register dir failed: %d\n", ret); goto error_dit; } } if (!num_links) { dev_err(&pdev->dev, "no enabled S/PDIF DAI link\n"); goto error_dir; } data->card.dev = &pdev->dev; data->card.num_links = num_links; data->card.dai_link = data->dai; ret = snd_soc_of_parse_card_name(&data->card, "model"); if (ret) goto error_dir; ret = snd_soc_register_card(&data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed: %d\n", ret); goto error_dir; } platform_set_drvdata(pdev, data); goto end; error_dir: if (data->rxdev) platform_device_unregister(data->rxdev); error_dit: if (data->txdev) platform_device_unregister(data->txdev); end: if (spdif_np) of_node_put(spdif_np); return ret; } static int imx_spdif_audio_remove(struct platform_device *pdev) { struct imx_spdif_data *data = platform_get_drvdata(pdev); if (data->rxdev) platform_device_unregister(data->rxdev); if (data->txdev) platform_device_unregister(data->txdev); snd_soc_unregister_card(&data->card); return 0; } static const struct of_device_id imx_spdif_dt_ids[] = { { .compatible = "fsl,imx-audio-spdif", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_spdif_dt_ids); static struct platform_driver imx_spdif_driver = { .driver = { .name = "imx-spdif", .owner = THIS_MODULE, .of_match_table = imx_spdif_dt_ids, }, .probe = imx_spdif_audio_probe, .remove = imx_spdif_audio_remove, }; module_platform_driver(imx_spdif_driver); MODULE_AUTHOR("Freescale Semiconductor, Inc."); MODULE_DESCRIPTION("Freescale i.MX S/PDIF machine driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:imx-spdif"); |