ASoC: Tegra: Make dma_req count easily configurable
[linux-2.6.git] / sound / soc / tegra / tegra_pcm.c
1 /*
2  * tegra_pcm.c - Tegra PCM driver
3  *
4  * Author: Stephen Warren <swarren@nvidia.com>
5  * Copyright (C) 2010 - NVIDIA, Inc.
6  *
7  * Based on code copyright/by:
8  *
9  * Copyright (c) 2009-2010, NVIDIA Corporation.
10  * Scott Peterson <speterson@nvidia.com>
11  * Vijay Mali <vmali@nvidia.com>
12  *
13  * Copyright (C) 2010 Google, Inc.
14  * Iliyan Malchev <malchev@google.com>
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * version 2 as published by the Free Software Foundation.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
28  * 02110-1301 USA
29  *
30  */
31
32 #include <linux/module.h>
33 #include <linux/dma-mapping.h>
34 #include <linux/slab.h>
35 #include <sound/core.h>
36 #include <sound/pcm.h>
37 #include <sound/pcm_params.h>
38 #include <sound/soc.h>
39
40 #include "tegra_pcm.h"
41
42 #define DRV_NAME "tegra-pcm-audio"
43
44 static const struct snd_pcm_hardware tegra_pcm_hardware = {
45         .info                   = SNDRV_PCM_INFO_MMAP |
46                                   SNDRV_PCM_INFO_MMAP_VALID |
47                                   SNDRV_PCM_INFO_PAUSE |
48                                   SNDRV_PCM_INFO_RESUME |
49                                   SNDRV_PCM_INFO_INTERLEAVED,
50         .formats                = SNDRV_PCM_FMTBIT_S16_LE,
51         .channels_min           = 1,
52         .channels_max           = 2,
53         .period_bytes_min       = 128,
54         .period_bytes_max       = PAGE_SIZE,
55         .periods_min            = 2,
56         .periods_max            = 8,
57         .buffer_bytes_max       = PAGE_SIZE * 8,
58         .fifo_size              = 4,
59 };
60
61 static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
62 {
63         struct snd_pcm_substream *substream = prtd->substream;
64         struct snd_dma_buffer *buf = &substream->dma_buffer;
65         struct tegra_dma_req *dma_req;
66         unsigned long addr;
67
68         dma_req = &prtd->dma_req[prtd->dma_req_idx];
69         if (++prtd->dma_req_idx >= prtd->dma_req_count)
70                 prtd->dma_req_idx -= prtd->dma_req_count;
71
72         addr = buf->addr + prtd->dma_pos;
73         prtd->dma_pos += dma_req->size;
74         if (prtd->dma_pos >= prtd->dma_pos_end)
75                 prtd->dma_pos = 0;
76
77         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
78                 dma_req->source_addr = addr;
79         else
80                 dma_req->dest_addr = addr;
81
82         tegra_dma_enqueue_req(prtd->dma_chan, dma_req);
83 }
84
85 static void dma_complete_callback(struct tegra_dma_req *req)
86 {
87         struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev;
88         struct snd_pcm_substream *substream = prtd->substream;
89         struct snd_pcm_runtime *runtime = substream->runtime;
90
91         spin_lock(&prtd->lock);
92
93         if (!prtd->running) {
94                 spin_unlock(&prtd->lock);
95                 return;
96         }
97
98         if (++prtd->period_index >= runtime->periods)
99                 prtd->period_index = 0;
100
101         tegra_pcm_queue_dma(prtd);
102
103         spin_unlock(&prtd->lock);
104
105         snd_pcm_period_elapsed(substream);
106 }
107
108 static void setup_dma_tx_request(struct tegra_dma_req *req,
109                                         struct tegra_pcm_dma_params * dmap)
110 {
111         req->complete = dma_complete_callback;
112         req->to_memory = false;
113         req->dest_addr = dmap->addr;
114         req->dest_wrap = dmap->wrap;
115         req->source_bus_width = 32;
116         req->source_wrap = 0;
117         req->dest_bus_width = dmap->width;
118         req->req_sel = dmap->req_sel;
119 }
120
121 static void setup_dma_rx_request(struct tegra_dma_req *req,
122                                         struct tegra_pcm_dma_params * dmap)
123 {
124         req->complete = dma_complete_callback;
125         req->to_memory = true;
126         req->source_addr = dmap->addr;
127         req->dest_wrap = 0;
128         req->source_bus_width = dmap->width;
129         req->source_wrap = dmap->wrap;
130         req->dest_bus_width = 32;
131         req->req_sel = dmap->req_sel;
132 }
133
134 static int tegra_pcm_open(struct snd_pcm_substream *substream)
135 {
136         struct snd_pcm_runtime *runtime = substream->runtime;
137         struct tegra_runtime_data *prtd;
138         struct snd_soc_pcm_runtime *rtd = substream->private_data;
139         struct tegra_pcm_dma_params * dmap;
140         int ret = 0;
141         int i = 0;
142
143         prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL);
144         if (prtd == NULL)
145                 return -ENOMEM;
146
147         runtime->private_data = prtd;
148         prtd->substream = substream;
149
150         spin_lock_init(&prtd->lock);
151
152         dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
153         prtd->dma_req_count = MAX_DMA_REQ_COUNT;
154
155         if (dmap) {
156                 for (i = 0; i < prtd->dma_req_count; i++)
157                         prtd->dma_req[i].dev = prtd;
158
159                 prtd->dma_chan = tegra_dma_allocate_channel(
160                                         TEGRA_DMA_MODE_CONTINUOUS_SINGLE,
161                                         "pcm");
162                 if (prtd->dma_chan == NULL) {
163                         ret = -ENOMEM;
164                         goto err;
165                 }
166         }
167
168         /* Set HW params now that initialization is complete */
169         snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
170
171         /* Ensure period size is multiple of 8 */
172         ret = snd_pcm_hw_constraint_step(runtime, 0,
173                 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 0x8);
174         if (ret < 0)
175                 goto err;
176
177         /* Ensure that buffer size is a multiple of period size */
178         ret = snd_pcm_hw_constraint_integer(runtime,
179                                                 SNDRV_PCM_HW_PARAM_PERIODS);
180         if (ret < 0)
181                 goto err;
182
183         return 0;
184
185 err:
186         if (prtd->dma_chan) {
187                 tegra_dma_free_channel(prtd->dma_chan);
188         }
189
190         kfree(prtd);
191
192         return ret;
193 }
194
195 static int tegra_pcm_close(struct snd_pcm_substream *substream)
196 {
197         struct snd_pcm_runtime *runtime = substream->runtime;
198         struct tegra_runtime_data *prtd = runtime->private_data;
199
200         if (prtd->dma_chan)
201                 tegra_dma_free_channel(prtd->dma_chan);
202
203         kfree(prtd);
204
205         return 0;
206 }
207
208 static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
209                                 struct snd_pcm_hw_params *params)
210 {
211         struct snd_pcm_runtime *runtime = substream->runtime;
212         struct tegra_runtime_data *prtd = runtime->private_data;
213         struct snd_soc_pcm_runtime *rtd = substream->private_data;
214         struct tegra_pcm_dma_params * dmap;
215         int i;
216
217         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
218
219         /* Limit dma_req_count to period count */
220         if (prtd->dma_req_count > params_periods(params))
221                 prtd->dma_req_count = params_periods(params);
222         dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
223         if (dmap) {
224                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
225                         for (i = 0; i < prtd->dma_req_count; i++)
226                                 setup_dma_tx_request(&prtd->dma_req[i], dmap);
227                 } else {
228                         for (i = 0; i < prtd->dma_req_count; i++)
229                                 setup_dma_rx_request(&prtd->dma_req[i], dmap);
230                 }
231         }
232         for (i = 0; i < prtd->dma_req_count; i++)
233                 prtd->dma_req[i].size = params_period_bytes(params);
234
235         return 0;
236 }
237
238 static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
239 {
240         snd_pcm_set_runtime_buffer(substream, NULL);
241
242         return 0;
243 }
244
245 static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
246 {
247         struct snd_pcm_runtime *runtime = substream->runtime;
248         struct tegra_runtime_data *prtd = runtime->private_data;
249         unsigned long flags;
250         int i;
251
252         switch (cmd) {
253         case SNDRV_PCM_TRIGGER_START:
254                 prtd->dma_pos = 0;
255                 prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size);
256                 prtd->period_index = 0;
257                 prtd->dma_req_idx = 0;
258                 /* Fall-through */
259         case SNDRV_PCM_TRIGGER_RESUME:
260         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
261                 spin_lock_irqsave(&prtd->lock, flags);
262                 prtd->running = 1;
263                 spin_unlock_irqrestore(&prtd->lock, flags);
264                 for (i = 0; i < prtd->dma_req_count; i++)
265                         tegra_pcm_queue_dma(prtd);
266                 break;
267         case SNDRV_PCM_TRIGGER_STOP:
268         case SNDRV_PCM_TRIGGER_SUSPEND:
269         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
270                 spin_lock_irqsave(&prtd->lock, flags);
271                 prtd->running = 0;
272                 spin_unlock_irqrestore(&prtd->lock, flags);
273                 tegra_dma_cancel(prtd->dma_chan);
274                 for (i = 0; i < prtd->dma_req_count; i++) {
275                         if (prtd->dma_req[i].status ==
276                                 -TEGRA_DMA_REQ_ERROR_ABORTED)
277                                 prtd->dma_req[i].complete(&prtd->dma_req[i]);
278                 }
279                 break;
280         default:
281                 return -EINVAL;
282         }
283
284         return 0;
285 }
286
287 static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
288 {
289         struct snd_pcm_runtime *runtime = substream->runtime;
290         struct tegra_runtime_data *prtd = runtime->private_data;
291         int dma_transfer_count;
292
293         dma_transfer_count = tegra_dma_get_transfer_count(prtd->dma_chan,
294                                         &prtd->dma_req[prtd->dma_req_idx]);
295
296         return prtd->period_index * runtime->period_size +
297                 bytes_to_frames(runtime, dma_transfer_count);
298 }
299
300 static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
301                                 struct vm_area_struct *vma)
302 {
303         struct snd_pcm_runtime *runtime = substream->runtime;
304
305         return dma_mmap_writecombine(substream->pcm->card->dev, vma,
306                                         runtime->dma_area,
307                                         runtime->dma_addr,
308                                         runtime->dma_bytes);
309 }
310
311 static struct snd_pcm_ops tegra_pcm_ops = {
312         .open           = tegra_pcm_open,
313         .close          = tegra_pcm_close,
314         .ioctl          = snd_pcm_lib_ioctl,
315         .hw_params      = tegra_pcm_hw_params,
316         .hw_free        = tegra_pcm_hw_free,
317         .trigger        = tegra_pcm_trigger,
318         .pointer        = tegra_pcm_pointer,
319         .mmap           = tegra_pcm_mmap,
320 };
321
322 static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
323 {
324         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
325         struct snd_dma_buffer *buf = &substream->dma_buffer;
326         size_t size = tegra_pcm_hardware.buffer_bytes_max;
327
328         buf->area = dma_alloc_writecombine(pcm->card->dev, size,
329                                                 &buf->addr, GFP_KERNEL);
330         if (!buf->area)
331                 return -ENOMEM;
332
333         buf->dev.type = SNDRV_DMA_TYPE_DEV;
334         buf->dev.dev = pcm->card->dev;
335         buf->private_data = NULL;
336         buf->bytes = size;
337
338         return 0;
339 }
340
341 static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
342 {
343         struct snd_pcm_substream *substream;
344         struct snd_dma_buffer *buf;
345
346         substream = pcm->streams[stream].substream;
347         if (!substream)
348                 return;
349
350         buf = &substream->dma_buffer;
351         if (!buf->area)
352                 return;
353
354         dma_free_writecombine(pcm->card->dev, buf->bytes,
355                                 buf->area, buf->addr);
356         buf->area = NULL;
357 }
358
359 static u64 tegra_dma_mask = DMA_BIT_MASK(32);
360
361 static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
362 {
363         struct snd_card *card = rtd->card->snd_card;
364         struct snd_soc_dai *dai = rtd->cpu_dai;
365         struct snd_pcm *pcm = rtd->pcm;
366         int ret = 0;
367
368         if (!card->dev->dma_mask)
369                 card->dev->dma_mask = &tegra_dma_mask;
370         if (!card->dev->coherent_dma_mask)
371                 card->dev->coherent_dma_mask = 0xffffffff;
372
373         if (dai->driver->playback.channels_min) {
374                 ret = tegra_pcm_preallocate_dma_buffer(pcm,
375                                                 SNDRV_PCM_STREAM_PLAYBACK);
376                 if (ret)
377                         goto err;
378         }
379
380         if (dai->driver->capture.channels_min) {
381                 ret = tegra_pcm_preallocate_dma_buffer(pcm,
382                                                 SNDRV_PCM_STREAM_CAPTURE);
383                 if (ret)
384                         goto err_free_play;
385         }
386
387         return 0;
388
389 err_free_play:
390         tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
391 err:
392         return ret;
393 }
394
395 static void tegra_pcm_free(struct snd_pcm *pcm)
396 {
397         tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
398         tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
399 }
400
401 struct snd_soc_platform_driver tegra_pcm_platform = {
402         .ops            = &tegra_pcm_ops,
403         .pcm_new        = tegra_pcm_new,
404         .pcm_free       = tegra_pcm_free,
405 };
406
407 static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
408 {
409         return snd_soc_register_platform(&pdev->dev, &tegra_pcm_platform);
410 }
411
412 static int __devexit tegra_pcm_platform_remove(struct platform_device *pdev)
413 {
414         snd_soc_unregister_platform(&pdev->dev);
415         return 0;
416 }
417
418 static struct platform_driver tegra_pcm_driver = {
419         .driver = {
420                 .name = DRV_NAME,
421                 .owner = THIS_MODULE,
422         },
423         .probe = tegra_pcm_platform_probe,
424         .remove = __devexit_p(tegra_pcm_platform_remove),
425 };
426
427 static int __init snd_tegra_pcm_init(void)
428 {
429         return platform_driver_register(&tegra_pcm_driver);
430 }
431 module_init(snd_tegra_pcm_init);
432
433 static void __exit snd_tegra_pcm_exit(void)
434 {
435         platform_driver_unregister(&tegra_pcm_driver);
436 }
437 module_exit(snd_tegra_pcm_exit);
438
439 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
440 MODULE_DESCRIPTION("Tegra PCM ASoC driver");
441 MODULE_LICENSE("GPL");
442 MODULE_ALIAS("platform:" DRV_NAME);