pxa2xx-pcm-lib.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License version 2 as
  4. * published by the Free Software Foundation.
  5. */
  6. #include <linux/slab.h>
  7. #include <linux/module.h>
  8. #include <linux/dma-mapping.h>
  9. #include <linux/dmaengine.h>
  10. #include <linux/dma/pxa-dma.h>
  11. #include <sound/core.h>
  12. #include <sound/pcm.h>
  13. #include <sound/pcm_params.h>
  14. #include <sound/pxa2xx-lib.h>
  15. #include <sound/dmaengine_pcm.h>
  16. #include "pxa2xx-pcm.h"
  17. static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
  18. .info = SNDRV_PCM_INFO_MMAP |
  19. SNDRV_PCM_INFO_MMAP_VALID |
  20. SNDRV_PCM_INFO_INTERLEAVED |
  21. SNDRV_PCM_INFO_PAUSE |
  22. SNDRV_PCM_INFO_RESUME,
  23. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  24. SNDRV_PCM_FMTBIT_S24_LE |
  25. SNDRV_PCM_FMTBIT_S32_LE,
  26. .period_bytes_min = 32,
  27. .period_bytes_max = 8192 - 32,
  28. .periods_min = 1,
  29. .periods_max = 256,
  30. .buffer_bytes_max = 128 * 1024,
  31. .fifo_size = 32,
  32. };
  33. int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
  34. struct snd_pcm_hw_params *params)
  35. {
  36. struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
  37. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  38. struct snd_dmaengine_dai_dma_data *dma_params;
  39. struct dma_slave_config config;
  40. int ret;
  41. dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
  42. if (!dma_params)
  43. return 0;
  44. ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
  45. if (ret)
  46. return ret;
  47. snd_dmaengine_pcm_set_config_from_dai_data(substream,
  48. snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
  49. &config);
  50. ret = dmaengine_slave_config(chan, &config);
  51. if (ret)
  52. return ret;
  53. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  54. return 0;
  55. }
  56. EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
  57. int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
  58. {
  59. snd_pcm_set_runtime_buffer(substream, NULL);
  60. return 0;
  61. }
  62. EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
  63. int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  64. {
  65. return snd_dmaengine_pcm_trigger(substream, cmd);
  66. }
  67. EXPORT_SYMBOL(pxa2xx_pcm_trigger);
  68. snd_pcm_uframes_t
  69. pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
  70. {
  71. return snd_dmaengine_pcm_pointer(substream);
  72. }
  73. EXPORT_SYMBOL(pxa2xx_pcm_pointer);
  74. int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
  75. {
  76. return 0;
  77. }
  78. EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
  79. int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
  80. {
  81. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  82. struct snd_pcm_runtime *runtime = substream->runtime;
  83. struct snd_dmaengine_dai_dma_data *dma_params;
  84. int ret;
  85. runtime->hw = pxa2xx_pcm_hardware;
  86. dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
  87. if (!dma_params)
  88. return 0;
  89. /*
  90. * For mysterious reasons (and despite what the manual says)
  91. * playback samples are lost if the DMA count is not a multiple
  92. * of the DMA burst size. Let's add a rule to enforce that.
  93. */
  94. ret = snd_pcm_hw_constraint_step(runtime, 0,
  95. SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
  96. if (ret)
  97. return ret;
  98. ret = snd_pcm_hw_constraint_step(runtime, 0,
  99. SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
  100. if (ret)
  101. return ret;
  102. ret = snd_pcm_hw_constraint_integer(runtime,
  103. SNDRV_PCM_HW_PARAM_PERIODS);
  104. if (ret < 0)
  105. return ret;
  106. return snd_dmaengine_pcm_open_request_chan(substream,
  107. pxad_filter_fn,
  108. dma_params->filter_data);
  109. }
  110. EXPORT_SYMBOL(__pxa2xx_pcm_open);
  111. int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
  112. {
  113. return snd_dmaengine_pcm_close_release_chan(substream);
  114. }
  115. EXPORT_SYMBOL(__pxa2xx_pcm_close);
  116. int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
  117. struct vm_area_struct *vma)
  118. {
  119. struct snd_pcm_runtime *runtime = substream->runtime;
  120. return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
  121. runtime->dma_addr, runtime->dma_bytes);
  122. }
  123. EXPORT_SYMBOL(pxa2xx_pcm_mmap);
  124. int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  125. {
  126. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  127. struct snd_dma_buffer *buf = &substream->dma_buffer;
  128. size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
  129. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  130. buf->dev.dev = pcm->card->dev;
  131. buf->private_data = NULL;
  132. buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
  133. if (!buf->area)
  134. return -ENOMEM;
  135. buf->bytes = size;
  136. return 0;
  137. }
  138. EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
  139. void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
  140. {
  141. struct snd_pcm_substream *substream;
  142. struct snd_dma_buffer *buf;
  143. int stream;
  144. for (stream = 0; stream < 2; stream++) {
  145. substream = pcm->streams[stream].substream;
  146. if (!substream)
  147. continue;
  148. buf = &substream->dma_buffer;
  149. if (!buf->area)
  150. continue;
  151. dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
  152. buf->area = NULL;
  153. }
  154. }
  155. EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
  156. MODULE_AUTHOR("Nicolas Pitre");
  157. MODULE_DESCRIPTION("Intel PXA2xx sound library");
  158. MODULE_LICENSE("GPL");