pxa2xx-pcm-lib.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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. return 0;
  49. }
  50. EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
  51. int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  52. {
  53. return snd_dmaengine_pcm_trigger(substream, cmd);
  54. }
  55. EXPORT_SYMBOL(pxa2xx_pcm_trigger);
  56. snd_pcm_uframes_t
  57. pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
  58. {
  59. return snd_dmaengine_pcm_pointer(substream);
  60. }
  61. EXPORT_SYMBOL(pxa2xx_pcm_pointer);
  62. int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
  63. {
  64. return 0;
  65. }
  66. EXPORT_SYMBOL(pxa2xx_pcm_prepare);
  67. int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
  68. {
  69. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  70. struct snd_pcm_runtime *runtime = substream->runtime;
  71. struct snd_dmaengine_dai_dma_data *dma_params;
  72. int ret;
  73. runtime->hw = pxa2xx_pcm_hardware;
  74. dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
  75. if (!dma_params)
  76. return 0;
  77. /*
  78. * For mysterious reasons (and despite what the manual says)
  79. * playback samples are lost if the DMA count is not a multiple
  80. * of the DMA burst size. Let's add a rule to enforce that.
  81. */
  82. ret = snd_pcm_hw_constraint_step(runtime, 0,
  83. SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
  84. if (ret)
  85. return ret;
  86. ret = snd_pcm_hw_constraint_step(runtime, 0,
  87. SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
  88. if (ret)
  89. return ret;
  90. ret = snd_pcm_hw_constraint_integer(runtime,
  91. SNDRV_PCM_HW_PARAM_PERIODS);
  92. if (ret < 0)
  93. return ret;
  94. return snd_dmaengine_pcm_open(
  95. substream, dma_request_slave_channel(asoc_rtd_to_cpu(rtd, 0)->dev,
  96. dma_params->chan_name));
  97. }
  98. EXPORT_SYMBOL(pxa2xx_pcm_open);
  99. int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
  100. {
  101. return snd_dmaengine_pcm_close_release_chan(substream);
  102. }
  103. EXPORT_SYMBOL(pxa2xx_pcm_close);
  104. int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm)
  105. {
  106. size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
  107. return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
  108. pcm->card->dev, size);
  109. }
  110. EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
  111. int pxa2xx_soc_pcm_new(struct snd_soc_component *component,
  112. struct snd_soc_pcm_runtime *rtd)
  113. {
  114. struct snd_card *card = rtd->card->snd_card;
  115. struct snd_pcm *pcm = rtd->pcm;
  116. int ret;
  117. ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
  118. if (ret)
  119. return ret;
  120. return pxa2xx_pcm_preallocate_dma_buffer(pcm);
  121. }
  122. EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
  123. int pxa2xx_soc_pcm_open(struct snd_soc_component *component,
  124. struct snd_pcm_substream *substream)
  125. {
  126. return pxa2xx_pcm_open(substream);
  127. }
  128. EXPORT_SYMBOL(pxa2xx_soc_pcm_open);
  129. int pxa2xx_soc_pcm_close(struct snd_soc_component *component,
  130. struct snd_pcm_substream *substream)
  131. {
  132. return pxa2xx_pcm_close(substream);
  133. }
  134. EXPORT_SYMBOL(pxa2xx_soc_pcm_close);
  135. int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component,
  136. struct snd_pcm_substream *substream,
  137. struct snd_pcm_hw_params *params)
  138. {
  139. return pxa2xx_pcm_hw_params(substream, params);
  140. }
  141. EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params);
  142. int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component,
  143. struct snd_pcm_substream *substream)
  144. {
  145. return pxa2xx_pcm_prepare(substream);
  146. }
  147. EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare);
  148. int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component,
  149. struct snd_pcm_substream *substream, int cmd)
  150. {
  151. return pxa2xx_pcm_trigger(substream, cmd);
  152. }
  153. EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger);
  154. snd_pcm_uframes_t
  155. pxa2xx_soc_pcm_pointer(struct snd_soc_component *component,
  156. struct snd_pcm_substream *substream)
  157. {
  158. return pxa2xx_pcm_pointer(substream);
  159. }
  160. EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer);
  161. MODULE_AUTHOR("Nicolas Pitre");
  162. MODULE_DESCRIPTION("Intel PXA2xx sound library");
  163. MODULE_LICENSE("GPL");