diff options
Diffstat (limited to 'sound/soc/mxs/mxs-pcm.c')
-rw-r--r-- | sound/soc/mxs/mxs-pcm.c | 139 |
1 files changed, 13 insertions, 126 deletions
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index 7bceb16d0fd9..b41fffc056fb 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c | |||
@@ -18,32 +18,24 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/clk.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/device.h> | 21 | #include <linux/device.h> |
24 | #include <linux/dma-mapping.h> | ||
25 | #include <linux/init.h> | 22 | #include <linux/init.h> |
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/module.h> | 23 | #include <linux/module.h> |
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/dmaengine.h> | ||
31 | 24 | ||
32 | #include <sound/core.h> | 25 | #include <sound/core.h> |
33 | #include <sound/initval.h> | ||
34 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
35 | #include <sound/pcm_params.h> | ||
36 | #include <sound/soc.h> | 27 | #include <sound/soc.h> |
37 | #include <sound/dmaengine_pcm.h> | 28 | #include <sound/dmaengine_pcm.h> |
38 | 29 | ||
39 | #include "mxs-pcm.h" | 30 | #include "mxs-pcm.h" |
40 | 31 | ||
41 | static struct snd_pcm_hardware snd_mxs_hardware = { | 32 | static const struct snd_pcm_hardware snd_mxs_hardware = { |
42 | .info = SNDRV_PCM_INFO_MMAP | | 33 | .info = SNDRV_PCM_INFO_MMAP | |
43 | SNDRV_PCM_INFO_MMAP_VALID | | 34 | SNDRV_PCM_INFO_MMAP_VALID | |
44 | SNDRV_PCM_INFO_PAUSE | | 35 | SNDRV_PCM_INFO_PAUSE | |
45 | SNDRV_PCM_INFO_RESUME | | 36 | SNDRV_PCM_INFO_RESUME | |
46 | SNDRV_PCM_INFO_INTERLEAVED, | 37 | SNDRV_PCM_INFO_INTERLEAVED | |
38 | SNDRV_PCM_INFO_HALF_DUPLEX, | ||
47 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 39 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
48 | SNDRV_PCM_FMTBIT_S20_3LE | | 40 | SNDRV_PCM_FMTBIT_S20_3LE | |
49 | SNDRV_PCM_FMTBIT_S24_LE, | 41 | SNDRV_PCM_FMTBIT_S24_LE, |
@@ -55,7 +47,6 @@ static struct snd_pcm_hardware snd_mxs_hardware = { | |||
55 | .periods_max = 52, | 47 | .periods_max = 52, |
56 | .buffer_bytes_max = 64 * 1024, | 48 | .buffer_bytes_max = 64 * 1024, |
57 | .fifo_size = 32, | 49 | .fifo_size = 32, |
58 | |||
59 | }; | 50 | }; |
60 | 51 | ||
61 | static bool filter(struct dma_chan *chan, void *param) | 52 | static bool filter(struct dma_chan *chan, void *param) |
@@ -73,129 +64,25 @@ static bool filter(struct dma_chan *chan, void *param) | |||
73 | return true; | 64 | return true; |
74 | } | 65 | } |
75 | 66 | ||
76 | static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream, | 67 | static const struct snd_dmaengine_pcm_config mxs_dmaengine_pcm_config = { |
77 | struct snd_pcm_hw_params *params) | 68 | .pcm_hardware = &snd_mxs_hardware, |
78 | { | 69 | .compat_filter_fn = filter, |
79 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 70 | .prealloc_buffer_size = 64 * 1024, |
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int snd_mxs_open(struct snd_pcm_substream *substream) | ||
85 | { | ||
86 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
87 | |||
88 | snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); | ||
89 | |||
90 | return snd_dmaengine_pcm_open_request_chan(substream, filter, | ||
91 | snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); | ||
92 | } | ||
93 | |||
94 | static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, | ||
95 | struct vm_area_struct *vma) | ||
96 | { | ||
97 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
98 | |||
99 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
100 | runtime->dma_area, | ||
101 | runtime->dma_addr, | ||
102 | runtime->dma_bytes); | ||
103 | } | ||
104 | |||
105 | static struct snd_pcm_ops mxs_pcm_ops = { | ||
106 | .open = snd_mxs_open, | ||
107 | .close = snd_dmaengine_pcm_close_release_chan, | ||
108 | .ioctl = snd_pcm_lib_ioctl, | ||
109 | .hw_params = snd_mxs_pcm_hw_params, | ||
110 | .trigger = snd_dmaengine_pcm_trigger, | ||
111 | .pointer = snd_dmaengine_pcm_pointer_no_residue, | ||
112 | .mmap = snd_mxs_pcm_mmap, | ||
113 | }; | ||
114 | |||
115 | static int mxs_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
116 | { | ||
117 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
118 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
119 | size_t size = snd_mxs_hardware.buffer_bytes_max; | ||
120 | |||
121 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
122 | buf->dev.dev = pcm->card->dev; | ||
123 | buf->private_data = NULL; | ||
124 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
125 | &buf->addr, GFP_KERNEL); | ||
126 | if (!buf->area) | ||
127 | return -ENOMEM; | ||
128 | buf->bytes = size; | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32); | ||
134 | static int mxs_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
135 | { | ||
136 | struct snd_card *card = rtd->card->snd_card; | ||
137 | struct snd_pcm *pcm = rtd->pcm; | ||
138 | int ret = 0; | ||
139 | |||
140 | if (!card->dev->dma_mask) | ||
141 | card->dev->dma_mask = &mxs_pcm_dmamask; | ||
142 | if (!card->dev->coherent_dma_mask) | ||
143 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | ||
144 | |||
145 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { | ||
146 | ret = mxs_pcm_preallocate_dma_buffer(pcm, | ||
147 | SNDRV_PCM_STREAM_PLAYBACK); | ||
148 | if (ret) | ||
149 | goto out; | ||
150 | } | ||
151 | |||
152 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
153 | ret = mxs_pcm_preallocate_dma_buffer(pcm, | ||
154 | SNDRV_PCM_STREAM_CAPTURE); | ||
155 | if (ret) | ||
156 | goto out; | ||
157 | } | ||
158 | |||
159 | out: | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | static void mxs_pcm_free(struct snd_pcm *pcm) | ||
164 | { | ||
165 | struct snd_pcm_substream *substream; | ||
166 | struct snd_dma_buffer *buf; | ||
167 | int stream; | ||
168 | |||
169 | for (stream = 0; stream < 2; stream++) { | ||
170 | substream = pcm->streams[stream].substream; | ||
171 | if (!substream) | ||
172 | continue; | ||
173 | |||
174 | buf = &substream->dma_buffer; | ||
175 | if (!buf->area) | ||
176 | continue; | ||
177 | |||
178 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
179 | buf->area, buf->addr); | ||
180 | buf->area = NULL; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static struct snd_soc_platform_driver mxs_soc_platform = { | ||
185 | .ops = &mxs_pcm_ops, | ||
186 | .pcm_new = mxs_pcm_new, | ||
187 | .pcm_free = mxs_pcm_free, | ||
188 | }; | 71 | }; |
189 | 72 | ||
190 | int mxs_pcm_platform_register(struct device *dev) | 73 | int mxs_pcm_platform_register(struct device *dev) |
191 | { | 74 | { |
192 | return snd_soc_register_platform(dev, &mxs_soc_platform); | 75 | return snd_dmaengine_pcm_register(dev, &mxs_dmaengine_pcm_config, |
76 | SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | | ||
77 | SND_DMAENGINE_PCM_FLAG_NO_DT | | ||
78 | SND_DMAENGINE_PCM_FLAG_COMPAT | | ||
79 | SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX); | ||
193 | } | 80 | } |
194 | EXPORT_SYMBOL_GPL(mxs_pcm_platform_register); | 81 | EXPORT_SYMBOL_GPL(mxs_pcm_platform_register); |
195 | 82 | ||
196 | void mxs_pcm_platform_unregister(struct device *dev) | 83 | void mxs_pcm_platform_unregister(struct device *dev) |
197 | { | 84 | { |
198 | snd_soc_unregister_platform(dev); | 85 | snd_dmaengine_pcm_unregister(dev); |
199 | } | 86 | } |
200 | EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister); | 87 | EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister); |
201 | 88 | ||