pxa2xx-pcm-lib.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/slab.h>
  3. #include <linux/module.h>
  4. #include <linux/dma-mapping.h>
  5. #include <linux/dmaengine.h>
  6. #include <linux/dma/pxa-dma.h>
  7. #include <sound/core.h>
  8. #include <sound/pcm.h>
  9. #include <sound/pcm_params.h>
  10. #include <sound/pxa2xx-lib.h>
  11. #include <sound/dmaengine_pcm.h>
  12. static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
  13. .info = SNDRV_PCM_INFO_MMAP |
  14. SNDRV_PCM_INFO_MMAP_VALID |
  15. SNDRV_PCM_INFO_INTERLEAVED |
  16. SNDRV_PCM_INFO_PAUSE |
  17. SNDRV_PCM_INFO_RESUME,
  18. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  19. SNDRV_PCM_FMTBIT_S24_LE |
  20. SNDRV_PCM_FMTBIT_S32_LE,
  21. .period_bytes_min = 32,
  22. .period_bytes_max = 8192 - 32,
  23. .periods_min = 1,
  24. .periods_max = 256,
  25. .buffer_bytes_max = 128 * 1024,
  26. .fifo_size = 32,
  27. };
  28. int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
  29. struct snd_pcm_hw_params *params)
  30. {
  31. struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
  32. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  33. struct snd_dmaengine_dai_dma_data *dma_params;
  34. struct dma_slave_config config;
  35. int ret;
  36. dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
  37. if (!dma_params)
  38. return 0;
  39. ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
  40. if (ret)
  41. return ret;
  42. snd_dmaengine_pcm_set_config_from_dai_data(substream,
  43. snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream),
  44. &config);
  45. ret = dmaengine_slave_config(chan, &config);
  46. if (ret)
  47. return ret;
  48. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  49. return 0;
  50. }
  51. EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
  52. int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
  53. {
  54. snd_pcm_set_runtime_buffer(substream, NULL);
  55. return 0;
  56. }
  57. EXPORT_SYMBOL(pxa2xx_pcm_hw_free);
  58. int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  59. {
  60. return snd_dmaengine_pcm_trigger(substream, cmd);
  61. }
  62. EXPORT_SYMBOL(pxa2xx_pcm_trigger);
  63. snd_pcm_uframes_t
  64. pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
  65. {
  66. return snd_dmaengine_pcm_pointer(substream);
  67. }
  68. EXPORT_SYMBOL(pxa2xx_pcm_pointer);
  69. int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
  70. {
  71. return 0;
  72. }
  73. EXPORT_SYMBOL(pxa2xx_pcm_prepare);
  74. int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
  75. {
  76. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  77. struct snd_pcm_runtime *runtime = substream->runtime;
  78. struct snd_dmaengine_dai_dma_data *dma_params;
  79. int ret;
  80. runtime->hw = pxa2xx_pcm_hardware;
  81. dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
  82. if (!dma_params)
  83. return 0;
  84. /*
  85. * For mysterious reasons (and despite what the manual says)
  86. * playback samples are lost if the DMA count is not a multiple
  87. * of the DMA burst size. Let's add a rule to enforce that.
  88. */
  89. ret = snd_pcm_hw_constraint_step(runtime, 0,
  90. SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
  91. if (ret)
  92. return ret;
  93. ret = snd_pcm_hw_constraint_step(runtime, 0,
  94. SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
  95. if (ret)
  96. return ret;
  97. ret = snd_pcm_hw_constraint_integer(runtime,
  98. SNDRV_PCM_HW_PARAM_PERIODS);
  99. if (ret < 0)
  100. return ret;
  101. return snd_dmaengine_pcm_open(
  102. substream, dma_request_slave_channel(asoc_rtd_to_cpu(rtd, 0)->dev,
  103. dma_params->chan_name));
  104. }
  105. EXPORT_SYMBOL(pxa2xx_pcm_open);
  106. int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
  107. {
  108. return snd_dmaengine_pcm_close_release_chan(substream);
  109. }
  110. EXPORT_SYMBOL(pxa2xx_pcm_close);
  111. int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
  112. struct vm_area_struct *vma)
  113. {
  114. struct snd_pcm_runtime *runtime = substream->runtime;
  115. return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
  116. runtime->dma_addr, runtime->dma_bytes);
  117. }
  118. EXPORT_SYMBOL(pxa2xx_pcm_mmap);
  119. int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  120. {
  121. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  122. struct snd_dma_buffer *buf = &substream->dma_buffer;
  123. size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
  124. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  125. buf->dev.dev = pcm->card->dev;
  126. buf->private_data = NULL;
  127. buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
  128. if (!buf->area)
  129. return -ENOMEM;
  130. buf->bytes = size;
  131. return 0;
  132. }
  133. EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
  134. void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
  135. {
  136. struct snd_pcm_substream *substream;
  137. struct snd_dma_buffer *buf;
  138. int stream;
  139. for (stream = 0; stream < 2; stream++) {
  140. substream = pcm->streams[stream].substream;
  141. if (!substream)
  142. continue;
  143. buf = &substream->dma_buffer;
  144. if (!buf->area)
  145. continue;
  146. dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
  147. buf->area = NULL;
  148. }
  149. }
  150. EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
  151. void pxa2xx_soc_pcm_free(struct snd_soc_component *component,
  152. struct snd_pcm *pcm)
  153. {
  154. pxa2xx_pcm_free_dma_buffers(pcm);
  155. }
  156. EXPORT_SYMBOL(pxa2xx_soc_pcm_free);
  157. int pxa2xx_soc_pcm_new(struct snd_soc_component *component,
  158. struct snd_soc_pcm_runtime *rtd)
  159. {
  160. struct snd_card *card = rtd->card->snd_card;
  161. struct snd_pcm *pcm = rtd->pcm;
  162. int ret;
  163. ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
  164. if (ret)
  165. return ret;
  166. if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
  167. ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
  168. SNDRV_PCM_STREAM_PLAYBACK);
  169. if (ret)
  170. goto out;
  171. }
  172. if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
  173. ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
  174. SNDRV_PCM_STREAM_CAPTURE);
  175. if (ret)
  176. goto out;
  177. }
  178. out:
  179. return ret;
  180. }
  181. EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
  182. int pxa2xx_soc_pcm_open(struct snd_soc_component *component,
  183. struct snd_pcm_substream *substream)
  184. {
  185. return pxa2xx_pcm_open(substream);
  186. }
  187. EXPORT_SYMBOL(pxa2xx_soc_pcm_open);
  188. int pxa2xx_soc_pcm_close(struct snd_soc_component *component,
  189. struct snd_pcm_substream *substream)
  190. {
  191. return pxa2xx_pcm_close(substream);
  192. }
  193. EXPORT_SYMBOL(pxa2xx_soc_pcm_close);
  194. int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component,
  195. struct snd_pcm_substream *substream,
  196. struct snd_pcm_hw_params *params)
  197. {
  198. return pxa2xx_pcm_hw_params(substream, params);
  199. }
  200. EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params);
  201. int pxa2xx_soc_pcm_hw_free(struct snd_soc_component *component,
  202. struct snd_pcm_substream *substream)
  203. {
  204. return pxa2xx_pcm_hw_free(substream);
  205. }
  206. EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_free);
  207. int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component,
  208. struct snd_pcm_substream *substream)
  209. {
  210. return pxa2xx_pcm_prepare(substream);
  211. }
  212. EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare);
  213. int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component,
  214. struct snd_pcm_substream *substream, int cmd)
  215. {
  216. return pxa2xx_pcm_trigger(substream, cmd);
  217. }
  218. EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger);
  219. snd_pcm_uframes_t
  220. pxa2xx_soc_pcm_pointer(struct snd_soc_component *component,
  221. struct snd_pcm_substream *substream)
  222. {
  223. return pxa2xx_pcm_pointer(substream);
  224. }
  225. EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer);
  226. int pxa2xx_soc_pcm_mmap(struct snd_soc_component *component,
  227. struct snd_pcm_substream *substream,
  228. struct vm_area_struct *vma)
  229. {
  230. return pxa2xx_pcm_mmap(substream, vma);
  231. }
  232. EXPORT_SYMBOL(pxa2xx_soc_pcm_mmap);
  233. MODULE_AUTHOR("Nicolas Pitre");
  234. MODULE_DESCRIPTION("Intel PXA2xx sound library");
  235. MODULE_LICENSE("GPL");