diff options
Diffstat (limited to 'sound/soc/tegra/tegra_pcm.c')
-rw-r--r-- | sound/soc/tegra/tegra_pcm.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 127348dc09b1..5658bcec1931 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <sound/pcm.h> | 36 | #include <sound/pcm.h> |
37 | #include <sound/pcm_params.h> | 37 | #include <sound/pcm_params.h> |
38 | #include <sound/soc.h> | 38 | #include <sound/soc.h> |
39 | #include <sound/dmaengine_pcm.h> | ||
39 | 40 | ||
40 | #include "tegra_pcm.h" | 41 | #include "tegra_pcm.h" |
41 | 42 | ||
@@ -56,6 +57,7 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { | |||
56 | .fifo_size = 4, | 57 | .fifo_size = 4, |
57 | }; | 58 | }; |
58 | 59 | ||
60 | #if defined(CONFIG_TEGRA_SYSTEM_DMA) | ||
59 | static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd) | 61 | static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd) |
60 | { | 62 | { |
61 | struct snd_pcm_substream *substream = prtd->substream; | 63 | struct snd_pcm_substream *substream = prtd->substream; |
@@ -285,6 +287,119 @@ static struct snd_pcm_ops tegra_pcm_ops = { | |||
285 | .pointer = tegra_pcm_pointer, | 287 | .pointer = tegra_pcm_pointer, |
286 | .mmap = tegra_pcm_mmap, | 288 | .mmap = tegra_pcm_mmap, |
287 | }; | 289 | }; |
290 | #else | ||
291 | static int tegra_pcm_open(struct snd_pcm_substream *substream) | ||
292 | { | ||
293 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
294 | struct device *dev = rtd->platform->dev; | ||
295 | int ret; | ||
296 | |||
297 | /* Set HW params now that initialization is complete */ | ||
298 | snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); | ||
299 | |||
300 | ret = snd_dmaengine_pcm_open(substream, NULL, NULL); | ||
301 | if (ret) { | ||
302 | dev_err(dev, "dmaengine pcm open failed with err %d\n", ret); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int tegra_pcm_close(struct snd_pcm_substream *substream) | ||
310 | { | ||
311 | snd_dmaengine_pcm_close(substream); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, | ||
316 | struct snd_pcm_hw_params *params) | ||
317 | { | ||
318 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
319 | struct device *dev = rtd->platform->dev; | ||
320 | struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); | ||
321 | struct tegra_pcm_dma_params *dmap; | ||
322 | struct dma_slave_config slave_config; | ||
323 | int ret; | ||
324 | |||
325 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
326 | |||
327 | ret = snd_hwparams_to_dma_slave_config(substream, params, | ||
328 | &slave_config); | ||
329 | if (ret) { | ||
330 | dev_err(dev, "hw params config failed with err %d\n", ret); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
335 | slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
336 | slave_config.dst_addr = dmap->addr; | ||
337 | slave_config.src_maxburst = 0; | ||
338 | } else { | ||
339 | slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
340 | slave_config.src_addr = dmap->addr; | ||
341 | slave_config.dst_maxburst = 0; | ||
342 | } | ||
343 | slave_config.slave_id = dmap->req_sel; | ||
344 | |||
345 | ret = dmaengine_slave_config(chan, &slave_config); | ||
346 | if (ret < 0) { | ||
347 | dev_err(dev, "dma slave config failed with err %d\n", ret); | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) | ||
356 | { | ||
357 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
362 | { | ||
363 | switch (cmd) { | ||
364 | case SNDRV_PCM_TRIGGER_START: | ||
365 | case SNDRV_PCM_TRIGGER_RESUME: | ||
366 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
367 | return snd_dmaengine_pcm_trigger(substream, | ||
368 | SNDRV_PCM_TRIGGER_START); | ||
369 | |||
370 | case SNDRV_PCM_TRIGGER_STOP: | ||
371 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
372 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
373 | return snd_dmaengine_pcm_trigger(substream, | ||
374 | SNDRV_PCM_TRIGGER_STOP); | ||
375 | default: | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int tegra_pcm_mmap(struct snd_pcm_substream *substream, | ||
382 | struct vm_area_struct *vma) | ||
383 | { | ||
384 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
385 | |||
386 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
387 | runtime->dma_area, | ||
388 | runtime->dma_addr, | ||
389 | runtime->dma_bytes); | ||
390 | } | ||
391 | |||
392 | static struct snd_pcm_ops tegra_pcm_ops = { | ||
393 | .open = tegra_pcm_open, | ||
394 | .close = tegra_pcm_close, | ||
395 | .ioctl = snd_pcm_lib_ioctl, | ||
396 | .hw_params = tegra_pcm_hw_params, | ||
397 | .hw_free = tegra_pcm_hw_free, | ||
398 | .trigger = tegra_pcm_trigger, | ||
399 | .pointer = snd_dmaengine_pcm_pointer, | ||
400 | .mmap = tegra_pcm_mmap, | ||
401 | }; | ||
402 | #endif | ||
288 | 403 | ||
289 | static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | 404 | static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) |
290 | { | 405 | { |