mmp-pcm.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * linux/sound/soc/pxa/mmp-pcm.c
  3. *
  4. * Copyright (C) 2011 Marvell International Ltd.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. */
  12. #include <linux/module.h>
  13. #include <linux/init.h>
  14. #include <linux/platform_device.h>
  15. #include <linux/slab.h>
  16. #include <linux/dma-mapping.h>
  17. #include <linux/dmaengine.h>
  18. #include <linux/platform_data/dma-mmp_tdma.h>
  19. #include <linux/platform_data/mmp_audio.h>
  20. #include <sound/pxa2xx-lib.h>
  21. #include <sound/core.h>
  22. #include <sound/pcm.h>
  23. #include <sound/pcm_params.h>
  24. #include <sound/soc.h>
  25. #include <sound/dmaengine_pcm.h>
  26. struct mmp_dma_data {
  27. int ssp_id;
  28. struct resource *dma_res;
  29. };
  30. #define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP | \
  31. SNDRV_PCM_INFO_MMAP_VALID | \
  32. SNDRV_PCM_INFO_INTERLEAVED | \
  33. SNDRV_PCM_INFO_PAUSE | \
  34. SNDRV_PCM_INFO_RESUME | \
  35. SNDRV_PCM_INFO_NO_PERIOD_WAKEUP)
  36. static struct snd_pcm_hardware mmp_pcm_hardware[] = {
  37. {
  38. .info = MMP_PCM_INFO,
  39. .period_bytes_min = 1024,
  40. .period_bytes_max = 2048,
  41. .periods_min = 2,
  42. .periods_max = 32,
  43. .buffer_bytes_max = 4096,
  44. .fifo_size = 32,
  45. },
  46. {
  47. .info = MMP_PCM_INFO,
  48. .period_bytes_min = 1024,
  49. .period_bytes_max = 2048,
  50. .periods_min = 2,
  51. .periods_max = 32,
  52. .buffer_bytes_max = 4096,
  53. .fifo_size = 32,
  54. },
  55. };
  56. static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
  57. struct snd_pcm_hw_params *params)
  58. {
  59. struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
  60. struct dma_slave_config slave_config;
  61. int ret;
  62. ret =
  63. snd_dmaengine_pcm_prepare_slave_config(substream, params,
  64. &slave_config);
  65. if (ret)
  66. return ret;
  67. ret = dmaengine_slave_config(chan, &slave_config);
  68. if (ret)
  69. return ret;
  70. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  71. return 0;
  72. }
  73. static bool filter(struct dma_chan *chan, void *param)
  74. {
  75. struct mmp_dma_data *dma_data = param;
  76. bool found = false;
  77. char *devname;
  78. devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
  79. dma_data->ssp_id);
  80. if ((strcmp(dev_name(chan->device->dev), devname) == 0) &&
  81. (chan->chan_id == dma_data->dma_res->start)) {
  82. found = true;
  83. }
  84. kfree(devname);
  85. return found;
  86. }
  87. static int mmp_pcm_open(struct snd_pcm_substream *substream)
  88. {
  89. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  90. struct platform_device *pdev = to_platform_device(rtd->platform->dev);
  91. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  92. struct mmp_dma_data dma_data;
  93. struct resource *r;
  94. r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
  95. if (!r)
  96. return -EBUSY;
  97. snd_soc_set_runtime_hwparams(substream,
  98. &mmp_pcm_hardware[substream->stream]);
  99. dma_data.dma_res = r;
  100. dma_data.ssp_id = cpu_dai->id;
  101. return snd_dmaengine_pcm_open_request_chan(substream, filter,
  102. &dma_data);
  103. }
  104. static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
  105. struct vm_area_struct *vma)
  106. {
  107. struct snd_pcm_runtime *runtime = substream->runtime;
  108. unsigned long off = vma->vm_pgoff;
  109. vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  110. return remap_pfn_range(vma, vma->vm_start,
  111. __phys_to_pfn(runtime->dma_addr) + off,
  112. vma->vm_end - vma->vm_start, vma->vm_page_prot);
  113. }
  114. static struct snd_pcm_ops mmp_pcm_ops = {
  115. .open = mmp_pcm_open,
  116. .close = snd_dmaengine_pcm_close_release_chan,
  117. .ioctl = snd_pcm_lib_ioctl,
  118. .hw_params = mmp_pcm_hw_params,
  119. .trigger = snd_dmaengine_pcm_trigger,
  120. .pointer = snd_dmaengine_pcm_pointer,
  121. .mmap = mmp_pcm_mmap,
  122. };
  123. static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm)
  124. {
  125. struct snd_pcm_substream *substream;
  126. struct snd_dma_buffer *buf;
  127. int stream;
  128. struct gen_pool *gpool;
  129. gpool = sram_get_gpool("asram");
  130. if (!gpool)
  131. return;
  132. for (stream = 0; stream < 2; stream++) {
  133. size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
  134. substream = pcm->streams[stream].substream;
  135. if (!substream)
  136. continue;
  137. buf = &substream->dma_buffer;
  138. if (!buf->area)
  139. continue;
  140. gen_pool_free(gpool, (unsigned long)buf->area, size);
  141. buf->area = NULL;
  142. }
  143. return;
  144. }
  145. static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
  146. int stream)
  147. {
  148. struct snd_dma_buffer *buf = &substream->dma_buffer;
  149. size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
  150. struct gen_pool *gpool;
  151. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  152. buf->dev.dev = substream->pcm->card->dev;
  153. buf->private_data = NULL;
  154. gpool = sram_get_gpool("asram");
  155. if (!gpool)
  156. return -ENOMEM;
  157. buf->area = gen_pool_dma_alloc(gpool, size, &buf->addr);
  158. if (!buf->area)
  159. return -ENOMEM;
  160. buf->bytes = size;
  161. return 0;
  162. }
  163. static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
  164. {
  165. struct snd_pcm_substream *substream;
  166. struct snd_pcm *pcm = rtd->pcm;
  167. int ret = 0, stream;
  168. for (stream = 0; stream < 2; stream++) {
  169. substream = pcm->streams[stream].substream;
  170. ret = mmp_pcm_preallocate_dma_buffer(substream, stream);
  171. if (ret)
  172. goto err;
  173. }
  174. return 0;
  175. err:
  176. mmp_pcm_free_dma_buffers(pcm);
  177. return ret;
  178. }
  179. static struct snd_soc_platform_driver mmp_soc_platform = {
  180. .ops = &mmp_pcm_ops,
  181. .pcm_new = mmp_pcm_new,
  182. .pcm_free = mmp_pcm_free_dma_buffers,
  183. };
  184. static int mmp_pcm_probe(struct platform_device *pdev)
  185. {
  186. struct mmp_audio_platdata *pdata = pdev->dev.platform_data;
  187. if (pdata) {
  188. mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].buffer_bytes_max =
  189. pdata->buffer_max_playback;
  190. mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].period_bytes_max =
  191. pdata->period_max_playback;
  192. mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].buffer_bytes_max =
  193. pdata->buffer_max_capture;
  194. mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
  195. pdata->period_max_capture;
  196. }
  197. return devm_snd_soc_register_platform(&pdev->dev, &mmp_soc_platform);
  198. }
  199. static struct platform_driver mmp_pcm_driver = {
  200. .driver = {
  201. .name = "mmp-pcm-audio",
  202. },
  203. .probe = mmp_pcm_probe,
  204. };
  205. module_platform_driver(mmp_pcm_driver);
  206. MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
  207. MODULE_DESCRIPTION("MMP Soc Audio DMA module");
  208. MODULE_LICENSE("GPL");
  209. MODULE_ALIAS("platform:mmp-pcm-audio");