aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/imx/imx-spdif.c
blob: f336545f9210f24c733348836835ee63324ce78e (plain)
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
/*
 * ASoC S/PDIF driver for IMX development boards
 *
 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
 *
 * based on stmp3780_devb_spdif.c
 *
 * Vladimir Barinov <vbarinov@embeddedalley.com>
 *
 * Copyright 2008 SigmaTel, Inc
 * Copyright 2008 Embedded Alley Solutions, Inc
 *
 * This file is licensed under the terms of the GNU General Public License
 * version 2.  This program  is licensed "as is" without any warranty of any
 * kind, whether express or implied.
 */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>

#include <asm/mach-types.h>
#include <asm/dma.h>
#include <mach/hardware.h>

#include "imx-ssi.h"
#include "../codecs/mxc_spdif.h"

/* imx digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link imx_spdif_dai_link = {
	.name = "IMX SPDIF",
	.stream_name = "IMX SPDIF",
	.codec_dai_name = "mxc-spdif",
	.codec_name = "mxc_spdif.0",
	.cpu_dai_name = "imx-spdif-dai.0",
	.platform_name = "imx-pcm-audio.2", /* imx-pcm-dma-mx2 */
};

static struct snd_soc_card snd_soc_card_imx_spdif = {
	.name = "imx-spdif",
	.dai_link = &imx_spdif_dai_link,
	.num_links = 1,
};

static int __devinit imx_spdif_audio_probe(struct platform_device *pdev)
{
	struct imx_ssi *ssi;
	int ret;

	ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
	if (!ssi)
		return -ENOMEM;

	dev_set_drvdata(&pdev->dev, ssi);

	ssi->soc_platform_pdev = platform_device_alloc("imx-pcm-audio", 2);
	if (!ssi->soc_platform_pdev) {
		pr_err("%s failed platform_device_alloc\n", __func__);
		return -ENOMEM;
	}

	/* It may seem weird to be using struct imx_ssi here because S/PDIF
	   doesn't use ssi.  We only use soc_platform_pdev in struct imx_ssi.
	   But we need it because imx-pcm-dma-mx2 initializes other fields. */
	platform_set_drvdata(ssi->soc_platform_pdev, ssi);

	ret = platform_device_add(ssi->soc_platform_pdev);
	if (ret) {
		dev_err(&pdev->dev, "failed to add platform device\n");
		platform_device_put(ssi->soc_platform_pdev);
		return ret;
	}

	return 0;
}

static int __devexit imx_spdif_audio_remove(struct platform_device *pdev)
{
	struct imx_ssi *ssi = platform_get_drvdata(pdev);

	platform_device_unregister(ssi->soc_platform_pdev);
	snd_soc_unregister_dai(&pdev->dev);
	kfree(ssi);

	return 0;
}

static struct platform_driver imx_spdif_audio_driver = {
	.probe = imx_spdif_audio_probe,
	.remove = __devexit_p(imx_spdif_audio_remove),
	.driver = {
		   .name = "imx-spdif-audio-device",
		   .owner = THIS_MODULE,
		   },
};

static struct platform_device *imx_spdif_snd_device;

static int __init imx_spdif_init(void)
{
	int ret = 0;

	ret = platform_driver_register(&imx_spdif_audio_driver);
	if (ret) {
		pr_err("%s - failed platform_driver_register\n", __func__);
		return -ENOMEM;
	}

	imx_spdif_snd_device = platform_device_alloc("soc-audio", 1);
	if (!imx_spdif_snd_device) {
		pr_err("%s - failed platform_device_alloc\n", __func__);
		return -ENOMEM;
	}

	platform_set_drvdata(imx_spdif_snd_device, &snd_soc_card_imx_spdif);

	ret = platform_device_add(imx_spdif_snd_device);
	if (ret) {
		pr_err("ASoC S/PDIF: Platform device allocation failed\n");
		platform_device_put(imx_spdif_snd_device);
	}

	return ret;
}

static void __exit imx_spdif_exit(void)
{
	platform_driver_unregister(&imx_spdif_audio_driver);
	platform_device_unregister(imx_spdif_snd_device);
}

module_init(imx_spdif_init);
module_exit(imx_spdif_exit);

MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("IMX EVK development board ASoC driver");
MODULE_LICENSE("GPL");