ep93xx-pcm.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
  3. *
  4. * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
  5. * Copyright (C) 2006 Applied Data Systems
  6. *
  7. * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
  8. * Copyright (c) 2008 Ryan Mallon
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/init.h>
  16. #include <linux/device.h>
  17. #include <linux/slab.h>
  18. #include <linux/dmaengine.h>
  19. #include <linux/dma-mapping.h>
  20. #include <sound/core.h>
  21. #include <sound/pcm.h>
  22. #include <sound/pcm_params.h>
  23. #include <sound/soc.h>
  24. #include <mach/dma.h>
  25. #include <mach/hardware.h>
  26. #include <mach/ep93xx-regs.h>
  27. #include "ep93xx-pcm.h"
  28. static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
  29. .info = (SNDRV_PCM_INFO_MMAP |
  30. SNDRV_PCM_INFO_MMAP_VALID |
  31. SNDRV_PCM_INFO_INTERLEAVED |
  32. SNDRV_PCM_INFO_BLOCK_TRANSFER),
  33. .rates = SNDRV_PCM_RATE_8000_192000,
  34. .rate_min = SNDRV_PCM_RATE_8000,
  35. .rate_max = SNDRV_PCM_RATE_192000,
  36. .formats = (SNDRV_PCM_FMTBIT_S16_LE |
  37. SNDRV_PCM_FMTBIT_S24_LE |
  38. SNDRV_PCM_FMTBIT_S32_LE),
  39. .buffer_bytes_max = 131072,
  40. .period_bytes_min = 32,
  41. .period_bytes_max = 32768,
  42. .periods_min = 1,
  43. .periods_max = 32,
  44. .fifo_size = 32,
  45. };
  46. struct ep93xx_runtime_data
  47. {
  48. int pointer_bytes;
  49. int periods;
  50. int period_bytes;
  51. struct dma_chan *dma_chan;
  52. struct ep93xx_dma_data dma_data;
  53. };
  54. static void ep93xx_pcm_dma_callback(void *data)
  55. {
  56. struct snd_pcm_substream *substream = data;
  57. struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
  58. rtd->pointer_bytes += rtd->period_bytes;
  59. rtd->pointer_bytes %= rtd->period_bytes * rtd->periods;
  60. snd_pcm_period_elapsed(substream);
  61. }
  62. static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
  63. {
  64. struct ep93xx_dma_data *data = filter_param;
  65. if (data->direction == ep93xx_dma_chan_direction(chan)) {
  66. chan->private = data;
  67. return true;
  68. }
  69. return false;
  70. }
  71. static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
  72. {
  73. struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
  74. struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
  75. struct ep93xx_pcm_dma_params *dma_params;
  76. struct ep93xx_runtime_data *rtd;
  77. dma_cap_mask_t mask;
  78. int ret;
  79. ret = snd_pcm_hw_constraint_integer(substream->runtime,
  80. SNDRV_PCM_HW_PARAM_PERIODS);
  81. if (ret < 0)
  82. return ret;
  83. snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
  84. rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
  85. if (!rtd)
  86. return -ENOMEM;
  87. dma_cap_zero(mask);
  88. dma_cap_set(DMA_SLAVE, mask);
  89. dma_cap_set(DMA_CYCLIC, mask);
  90. dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
  91. rtd->dma_data.port = dma_params->dma_port;
  92. rtd->dma_data.name = dma_params->name;
  93. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  94. rtd->dma_data.direction = DMA_MEM_TO_DEV;
  95. else
  96. rtd->dma_data.direction = DMA_DEV_TO_MEM;
  97. rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter,
  98. &rtd->dma_data);
  99. if (!rtd->dma_chan) {
  100. kfree(rtd);
  101. return -EINVAL;
  102. }
  103. substream->runtime->private_data = rtd;
  104. return 0;
  105. }
  106. static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
  107. {
  108. struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
  109. dma_release_channel(rtd->dma_chan);
  110. kfree(rtd);
  111. return 0;
  112. }
  113. static int ep93xx_pcm_dma_submit(struct snd_pcm_substream *substream)
  114. {
  115. struct snd_pcm_runtime *runtime = substream->runtime;
  116. struct ep93xx_runtime_data *rtd = runtime->private_data;
  117. struct dma_chan *chan = rtd->dma_chan;
  118. struct dma_device *dma_dev = chan->device;
  119. struct dma_async_tx_descriptor *desc;
  120. rtd->pointer_bytes = 0;
  121. desc = dma_dev->device_prep_dma_cyclic(chan, runtime->dma_addr,
  122. rtd->period_bytes * rtd->periods,
  123. rtd->period_bytes,
  124. rtd->dma_data.direction);
  125. if (!desc)
  126. return -EINVAL;
  127. desc->callback = ep93xx_pcm_dma_callback;
  128. desc->callback_param = substream;
  129. dmaengine_submit(desc);
  130. return 0;
  131. }
  132. static void ep93xx_pcm_dma_flush(struct snd_pcm_substream *substream)
  133. {
  134. struct snd_pcm_runtime *runtime = substream->runtime;
  135. struct ep93xx_runtime_data *rtd = runtime->private_data;
  136. dmaengine_terminate_all(rtd->dma_chan);
  137. }
  138. static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
  139. struct snd_pcm_hw_params *params)
  140. {
  141. struct snd_pcm_runtime *runtime = substream->runtime;
  142. struct ep93xx_runtime_data *rtd = runtime->private_data;
  143. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  144. rtd->periods = params_periods(params);
  145. rtd->period_bytes = params_period_bytes(params);
  146. return 0;
  147. }
  148. static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
  149. {
  150. snd_pcm_set_runtime_buffer(substream, NULL);
  151. return 0;
  152. }
  153. static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  154. {
  155. int ret;
  156. ret = 0;
  157. switch (cmd) {
  158. case SNDRV_PCM_TRIGGER_START:
  159. case SNDRV_PCM_TRIGGER_RESUME:
  160. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  161. ret = ep93xx_pcm_dma_submit(substream);
  162. break;
  163. case SNDRV_PCM_TRIGGER_STOP:
  164. case SNDRV_PCM_TRIGGER_SUSPEND:
  165. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  166. ep93xx_pcm_dma_flush(substream);
  167. break;
  168. default:
  169. ret = -EINVAL;
  170. break;
  171. }
  172. return ret;
  173. }
  174. static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
  175. {
  176. struct snd_pcm_runtime *runtime = substream->runtime;
  177. struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
  178. /* FIXME: implement this with sub-period granularity */
  179. return bytes_to_frames(runtime, rtd->pointer_bytes);
  180. }
  181. static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
  182. struct vm_area_struct *vma)
  183. {
  184. struct snd_pcm_runtime *runtime = substream->runtime;
  185. return dma_mmap_writecombine(substream->pcm->card->dev, vma,
  186. runtime->dma_area,
  187. runtime->dma_addr,
  188. runtime->dma_bytes);
  189. }
  190. static struct snd_pcm_ops ep93xx_pcm_ops = {
  191. .open = ep93xx_pcm_open,
  192. .close = ep93xx_pcm_close,
  193. .ioctl = snd_pcm_lib_ioctl,
  194. .hw_params = ep93xx_pcm_hw_params,
  195. .hw_free = ep93xx_pcm_hw_free,
  196. .trigger = ep93xx_pcm_trigger,
  197. .pointer = ep93xx_pcm_pointer,
  198. .mmap = ep93xx_pcm_mmap,
  199. };
  200. static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  201. {
  202. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  203. struct snd_dma_buffer *buf = &substream->dma_buffer;
  204. size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
  205. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  206. buf->dev.dev = pcm->card->dev;
  207. buf->private_data = NULL;
  208. buf->area = dma_alloc_writecombine(pcm->card->dev, size,
  209. &buf->addr, GFP_KERNEL);
  210. buf->bytes = size;
  211. return (buf->area == NULL) ? -ENOMEM : 0;
  212. }
  213. static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
  214. {
  215. struct snd_pcm_substream *substream;
  216. struct snd_dma_buffer *buf;
  217. int stream;
  218. for (stream = 0; stream < 2; stream++) {
  219. substream = pcm->streams[stream].substream;
  220. if (!substream)
  221. continue;
  222. buf = &substream->dma_buffer;
  223. if (!buf->area)
  224. continue;
  225. dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
  226. buf->addr);
  227. buf->area = NULL;
  228. }
  229. }
  230. static u64 ep93xx_pcm_dmamask = 0xffffffff;
  231. static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
  232. {
  233. struct snd_card *card = rtd->card->snd_card;
  234. struct snd_pcm *pcm = rtd->pcm;
  235. int ret = 0;
  236. if (!card->dev->dma_mask)
  237. card->dev->dma_mask = &ep93xx_pcm_dmamask;
  238. if (!card->dev->coherent_dma_mask)
  239. card->dev->coherent_dma_mask = 0xffffffff;
  240. if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
  241. ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
  242. SNDRV_PCM_STREAM_PLAYBACK);
  243. if (ret)
  244. return ret;
  245. }
  246. if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
  247. ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
  248. SNDRV_PCM_STREAM_CAPTURE);
  249. if (ret)
  250. return ret;
  251. }
  252. return 0;
  253. }
  254. static struct snd_soc_platform_driver ep93xx_soc_platform = {
  255. .ops = &ep93xx_pcm_ops,
  256. .pcm_new = &ep93xx_pcm_new,
  257. .pcm_free = &ep93xx_pcm_free_dma_buffers,
  258. };
  259. static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
  260. {
  261. return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
  262. }
  263. static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
  264. {
  265. snd_soc_unregister_platform(&pdev->dev);
  266. return 0;
  267. }
  268. static struct platform_driver ep93xx_pcm_driver = {
  269. .driver = {
  270. .name = "ep93xx-pcm-audio",
  271. .owner = THIS_MODULE,
  272. },
  273. .probe = ep93xx_soc_platform_probe,
  274. .remove = __devexit_p(ep93xx_soc_platform_remove),
  275. };
  276. module_platform_driver(ep93xx_pcm_driver);
  277. MODULE_AUTHOR("Ryan Mallon");
  278. MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
  279. MODULE_LICENSE("GPL");
  280. MODULE_ALIAS("platform:ep93xx-pcm-audio");