kirkwood-dma.c (e199e6136ce6b151e6638ae93dca60748424d900) kirkwood-dma.c (697378972d075e1b26ed2935bf44fb828c6191f5)
1/*
2 * kirkwood-dma.c
3 *
4 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
1/*
2 * kirkwood-dma.c
3 *
4 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
5 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/device.h>
15#include <linux/io.h>
16#include <linux/slab.h>
17#include <linux/interrupt.h>
18#include <linux/dma-mapping.h>
19#include <linux/mbus.h>
20#include <sound/soc.h>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 */
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/io.h>
17#include <linux/slab.h>
18#include <linux/interrupt.h>
19#include <linux/dma-mapping.h>
20#include <linux/mbus.h>
21#include <sound/soc.h>
21#include "kirkwood-dma.h"
22#include "kirkwood.h"
23
24#define KIRKWOOD_RATES \
25 (SNDRV_PCM_RATE_44100 | \
26 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
27#define KIRKWOOD_FORMATS \
28 (SNDRV_PCM_FMTBIT_S16_LE | \
29 SNDRV_PCM_FMTBIT_S24_LE | \

--- 88 unchanged lines hidden (view full) ---

118 }
119}
120
121static int kirkwood_dma_open(struct snd_pcm_substream *substream)
122{
123 int err;
124 struct snd_pcm_runtime *runtime = substream->runtime;
125 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
22#include "kirkwood.h"
23
24#define KIRKWOOD_RATES \
25 (SNDRV_PCM_RATE_44100 | \
26 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
27#define KIRKWOOD_FORMATS \
28 (SNDRV_PCM_FMTBIT_S16_LE | \
29 SNDRV_PCM_FMTBIT_S24_LE | \

--- 88 unchanged lines hidden (view full) ---

118 }
119}
120
121static int kirkwood_dma_open(struct snd_pcm_substream *substream)
122{
123 int err;
124 struct snd_pcm_runtime *runtime = substream->runtime;
125 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
126 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
126 struct snd_soc_platform *platform = soc_runtime->platform;
127 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
127 struct kirkwood_dma_data *priv;
128 struct kirkwood_dma_data *priv;
128 struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
129 struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
129 unsigned long addr;
130
131 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
132 snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
133
134 /* Ensure that all constraints linked to dma burst are fullfilled */
135 err = snd_pcm_hw_constraint_minmax(runtime,
136 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,

--- 9 unchanged lines hidden (view full) ---

146 return err;
147
148 err = snd_pcm_hw_constraint_step(substream->runtime, 0,
149 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
150 priv->burst);
151 if (err < 0)
152 return err;
153
130 unsigned long addr;
131
132 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
133 snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
134
135 /* Ensure that all constraints linked to dma burst are fullfilled */
136 err = snd_pcm_hw_constraint_minmax(runtime,
137 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,

--- 9 unchanged lines hidden (view full) ---

147 return err;
148
149 err = snd_pcm_hw_constraint_step(substream->runtime, 0,
150 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
151 priv->burst);
152 if (err < 0)
153 return err;
154
154 if (soc_runtime->dai->cpu_dai->private_data == NULL) {
155 if (prdata == NULL) {
155 prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
156 if (prdata == NULL)
157 return -ENOMEM;
158
159 prdata->data = priv;
160
161 err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
162 "kirkwood-i2s", prdata);
163 if (err) {
164 kfree(prdata);
165 return -EBUSY;
166 }
167
156 prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
157 if (prdata == NULL)
158 return -ENOMEM;
159
160 prdata->data = priv;
161
162 err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
163 "kirkwood-i2s", prdata);
164 if (err) {
165 kfree(prdata);
166 return -EBUSY;
167 }
168
168 soc_runtime->dai->cpu_dai->private_data = prdata;
169 snd_soc_platform_set_drvdata(platform, prdata);
169
170 /*
171 * Enable Error interrupts. We're only ack'ing them but
172 * it's usefull for diagnostics
173 */
174 writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
175 }
176

--- 9 unchanged lines hidden (view full) ---

186 }
187
188 return 0;
189}
190
191static int kirkwood_dma_close(struct snd_pcm_substream *substream)
192{
193 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
170
171 /*
172 * Enable Error interrupts. We're only ack'ing them but
173 * it's usefull for diagnostics
174 */
175 writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
176 }
177

--- 9 unchanged lines hidden (view full) ---

187 }
188
189 return 0;
190}
191
192static int kirkwood_dma_close(struct snd_pcm_substream *substream)
193{
194 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
194 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
195 struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
195 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
196 struct snd_soc_platform *platform = soc_runtime->platform;
197 struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
196 struct kirkwood_dma_data *priv;
197
198 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
199
200 if (!prdata || !priv)
201 return 0;
202
203 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
204 prdata->play_stream = NULL;
205 else
206 prdata->rec_stream = NULL;
207
208 if (!prdata->play_stream && !prdata->rec_stream) {
209 writel(0, priv->io + KIRKWOOD_ERR_MASK);
210 free_irq(priv->irq, prdata);
211 kfree(prdata);
198 struct kirkwood_dma_data *priv;
199
200 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
201
202 if (!prdata || !priv)
203 return 0;
204
205 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
206 prdata->play_stream = NULL;
207 else
208 prdata->rec_stream = NULL;
209
210 if (!prdata->play_stream && !prdata->rec_stream) {
211 writel(0, priv->io + KIRKWOOD_ERR_MASK);
212 free_irq(priv->irq, prdata);
213 kfree(prdata);
212 soc_runtime->dai->cpu_dai->private_data = NULL;
214 snd_soc_platform_set_drvdata(platform, NULL);
213 }
214
215 return 0;
216}
217
218static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream,
219 struct snd_pcm_hw_params *params)
220{

--- 10 unchanged lines hidden (view full) ---

231 snd_pcm_set_runtime_buffer(substream, NULL);
232 return 0;
233}
234
235static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
236{
237 struct snd_pcm_runtime *runtime = substream->runtime;
238 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
215 }
216
217 return 0;
218}
219
220static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream,
221 struct snd_pcm_hw_params *params)
222{

--- 10 unchanged lines hidden (view full) ---

233 snd_pcm_set_runtime_buffer(substream, NULL);
234 return 0;
235}
236
237static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
238{
239 struct snd_pcm_runtime *runtime = substream->runtime;
240 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
239 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
241 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
240 struct kirkwood_dma_data *priv;
241 unsigned long size, count;
242
243 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
244
245 /* compute buffer size in term of "words" as requested in specs */
246 size = frames_to_bytes(runtime, runtime->buffer_size);
247 size = (size>>2)-1;

--- 12 unchanged lines hidden (view full) ---

260
261 return 0;
262}
263
264static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
265 *substream)
266{
267 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
242 struct kirkwood_dma_data *priv;
243 unsigned long size, count;
244
245 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
246
247 /* compute buffer size in term of "words" as requested in specs */
248 size = frames_to_bytes(runtime, runtime->buffer_size);
249 size = (size>>2)-1;

--- 12 unchanged lines hidden (view full) ---

262
263 return 0;
264}
265
266static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
267 *substream)
268{
269 struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
268 struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
270 struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
269 struct kirkwood_dma_data *priv;
270 snd_pcm_uframes_t count;
271
272 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
273
274 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
275 count = bytes_to_frames(substream->runtime,
276 readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));

--- 38 unchanged lines hidden (view full) ---

315{
316 int ret;
317
318 if (!card->dev->dma_mask)
319 card->dev->dma_mask = &kirkwood_dma_dmamask;
320 if (!card->dev->coherent_dma_mask)
321 card->dev->coherent_dma_mask = 0xffffffff;
322
271 struct kirkwood_dma_data *priv;
272 snd_pcm_uframes_t count;
273
274 priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
275
276 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
277 count = bytes_to_frames(substream->runtime,
278 readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));

--- 38 unchanged lines hidden (view full) ---

317{
318 int ret;
319
320 if (!card->dev->dma_mask)
321 card->dev->dma_mask = &kirkwood_dma_dmamask;
322 if (!card->dev->coherent_dma_mask)
323 card->dev->coherent_dma_mask = 0xffffffff;
324
323 if (dai->playback.channels_min) {
325 if (dai->driver->playback.channels_min) {
324 ret = kirkwood_dma_preallocate_dma_buffer(pcm,
325 SNDRV_PCM_STREAM_PLAYBACK);
326 if (ret)
327 return ret;
328 }
329
326 ret = kirkwood_dma_preallocate_dma_buffer(pcm,
327 SNDRV_PCM_STREAM_PLAYBACK);
328 if (ret)
329 return ret;
330 }
331
330 if (dai->capture.channels_min) {
332 if (dai->driver->capture.channels_min) {
331 ret = kirkwood_dma_preallocate_dma_buffer(pcm,
332 SNDRV_PCM_STREAM_CAPTURE);
333 if (ret)
334 return ret;
335 }
336
337 return 0;
338}

--- 13 unchanged lines hidden (view full) ---

352 continue;
353
354 dma_free_coherent(pcm->card->dev, buf->bytes,
355 buf->area, buf->addr);
356 buf->area = NULL;
357 }
358}
359
333 ret = kirkwood_dma_preallocate_dma_buffer(pcm,
334 SNDRV_PCM_STREAM_CAPTURE);
335 if (ret)
336 return ret;
337 }
338
339 return 0;
340}

--- 13 unchanged lines hidden (view full) ---

354 continue;
355
356 dma_free_coherent(pcm->card->dev, buf->bytes,
357 buf->area, buf->addr);
358 buf->area = NULL;
359 }
360}
361
360struct snd_soc_platform kirkwood_soc_platform = {
361 .name = "kirkwood-dma",
362 .pcm_ops = &kirkwood_dma_ops,
362static struct snd_soc_platform_driver kirkwood_soc_platform = {
363 .ops = &kirkwood_dma_ops,
363 .pcm_new = kirkwood_dma_new,
364 .pcm_free = kirkwood_dma_free_dma_buffers,
365};
364 .pcm_new = kirkwood_dma_new,
365 .pcm_free = kirkwood_dma_free_dma_buffers,
366};
366EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
367
367
368static int __init kirkwood_soc_platform_init(void)
368static int __devinit kirkwood_soc_platform_probe(struct platform_device *pdev)
369{
369{
370 return snd_soc_register_platform(&kirkwood_soc_platform);
370 return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
371}
371}
372module_init(kirkwood_soc_platform_init);
373
372
374static void __exit kirkwood_soc_platform_exit(void)
373static int __devexit kirkwood_soc_platform_remove(struct platform_device *pdev)
375{
374{
376 snd_soc_unregister_platform(&kirkwood_soc_platform);
375 snd_soc_unregister_platform(&pdev->dev);
376 return 0;
377}
377}
378module_exit(kirkwood_soc_platform_exit);
379
378
380MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
379static struct platform_driver kirkwood_pcm_driver = {
380 .driver = {
381 .name = "kirkwood-pcm-audio",
382 .owner = THIS_MODULE,
383 },
384
385 .probe = kirkwood_soc_platform_probe,
386 .remove = __devexit_p(kirkwood_soc_platform_remove),
387};
388
389static int __init kirkwood_pcm_init(void)
390{
391 return platform_driver_register(&kirkwood_pcm_driver);
392}
393module_init(kirkwood_pcm_init);
394
395static void __exit kirkwood_pcm_exit(void)
396{
397 platform_driver_unregister(&kirkwood_pcm_driver);
398}
399module_exit(kirkwood_pcm_exit);
400
401MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
381MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
382MODULE_LICENSE("GPL");
402MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
403MODULE_LICENSE("GPL");
383
404MODULE_ALIAS("platform:kirkwood-pcm-audio");