ep93xx-pcm.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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 <ryan@bluewatersys.com>
  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/dma-mapping.h>
  19. #include <sound/core.h>
  20. #include <sound/pcm.h>
  21. #include <sound/pcm_params.h>
  22. #include <sound/soc.h>
  23. #include <mach/dma.h>
  24. #include <mach/hardware.h>
  25. #include <mach/ep93xx-regs.h>
  26. #include "ep93xx-pcm.h"
  27. static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
  28. .info = (SNDRV_PCM_INFO_MMAP |
  29. SNDRV_PCM_INFO_MMAP_VALID |
  30. SNDRV_PCM_INFO_INTERLEAVED |
  31. SNDRV_PCM_INFO_BLOCK_TRANSFER),
  32. .rates = SNDRV_PCM_RATE_8000_192000,
  33. .rate_min = SNDRV_PCM_RATE_8000,
  34. .rate_max = SNDRV_PCM_RATE_192000,
  35. .formats = (SNDRV_PCM_FMTBIT_S16_LE |
  36. SNDRV_PCM_FMTBIT_S24_LE |
  37. SNDRV_PCM_FMTBIT_S32_LE),
  38. .buffer_bytes_max = 131072,
  39. .period_bytes_min = 32,
  40. .period_bytes_max = 32768,
  41. .periods_min = 1,
  42. .periods_max = 32,
  43. .fifo_size = 32,
  44. };
  45. struct ep93xx_runtime_data
  46. {
  47. struct ep93xx_dma_m2p_client cl;
  48. struct ep93xx_pcm_dma_params *params;
  49. int pointer_bytes;
  50. struct tasklet_struct period_tasklet;
  51. int periods;
  52. struct ep93xx_dma_buffer buf[32];
  53. };
  54. static void ep93xx_pcm_period_elapsed(unsigned long data)
  55. {
  56. struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
  57. snd_pcm_period_elapsed(substream);
  58. }
  59. static void ep93xx_pcm_buffer_started(void *cookie,
  60. struct ep93xx_dma_buffer *buf)
  61. {
  62. }
  63. static void ep93xx_pcm_buffer_finished(void *cookie,
  64. struct ep93xx_dma_buffer *buf,
  65. int bytes, int error)
  66. {
  67. struct snd_pcm_substream *substream = cookie;
  68. struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
  69. if (buf == rtd->buf + rtd->periods - 1)
  70. rtd->pointer_bytes = 0;
  71. else
  72. rtd->pointer_bytes += buf->size;
  73. if (!error) {
  74. ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
  75. tasklet_schedule(&rtd->period_tasklet);
  76. } else {
  77. snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
  78. }
  79. }
  80. static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
  81. {
  82. struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
  83. struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
  84. struct ep93xx_pcm_dma_params *dma_params;
  85. struct ep93xx_runtime_data *rtd;
  86. int ret;
  87. dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
  88. snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
  89. rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
  90. if (!rtd)
  91. return -ENOMEM;
  92. memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
  93. rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
  94. rtd->period_tasklet.data = (unsigned long)substream;
  95. rtd->cl.name = dma_params->name;
  96. rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
  97. ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
  98. EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
  99. rtd->cl.cookie = substream;
  100. rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
  101. rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
  102. ret = ep93xx_dma_m2p_client_register(&rtd->cl);
  103. if (ret < 0) {
  104. kfree(rtd);
  105. return ret;
  106. }
  107. substream->runtime->private_data = rtd;
  108. return 0;
  109. }
  110. static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
  111. {
  112. struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
  113. ep93xx_dma_m2p_client_unregister(&rtd->cl);
  114. kfree(rtd);
  115. return 0;
  116. }
  117. static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
  118. struct snd_pcm_hw_params *params)
  119. {
  120. struct snd_pcm_runtime *runtime = substream->runtime;
  121. struct ep93xx_runtime_data *rtd = runtime->private_data;
  122. size_t totsize = params_buffer_bytes(params);
  123. size_t period = params_period_bytes(params);
  124. int i;
  125. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  126. runtime->dma_bytes = totsize;
  127. rtd->periods = (totsize + period - 1) / period;
  128. for (i = 0; i < rtd->periods; i++) {
  129. rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
  130. rtd->buf[i].size = period;
  131. if ((i + 1) * period > totsize)
  132. rtd->buf[i].size = totsize - (i * period);
  133. }
  134. return 0;
  135. }
  136. static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
  137. {
  138. snd_pcm_set_runtime_buffer(substream, NULL);
  139. return 0;
  140. }
  141. static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  142. {
  143. struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
  144. int ret;
  145. int i;
  146. ret = 0;
  147. switch (cmd) {
  148. case SNDRV_PCM_TRIGGER_START:
  149. case SNDRV_PCM_TRIGGER_RESUME:
  150. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  151. rtd->pointer_bytes = 0;
  152. for (i = 0; i < rtd->periods; i++)
  153. ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
  154. break;
  155. case SNDRV_PCM_TRIGGER_STOP:
  156. case SNDRV_PCM_TRIGGER_SUSPEND:
  157. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  158. ep93xx_dma_m2p_flush(&rtd->cl);
  159. break;
  160. default:
  161. ret = -EINVAL;
  162. break;
  163. }
  164. return ret;
  165. }
  166. static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
  167. {
  168. struct snd_pcm_runtime *runtime = substream->runtime;
  169. struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
  170. /* FIXME: implement this with sub-period granularity */
  171. return bytes_to_frames(runtime, rtd->pointer_bytes);
  172. }
  173. static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
  174. struct vm_area_struct *vma)
  175. {
  176. struct snd_pcm_runtime *runtime = substream->runtime;
  177. return dma_mmap_writecombine(substream->pcm->card->dev, vma,
  178. runtime->dma_area,
  179. runtime->dma_addr,
  180. runtime->dma_bytes);
  181. }
  182. static struct snd_pcm_ops ep93xx_pcm_ops = {
  183. .open = ep93xx_pcm_open,
  184. .close = ep93xx_pcm_close,
  185. .ioctl = snd_pcm_lib_ioctl,
  186. .hw_params = ep93xx_pcm_hw_params,
  187. .hw_free = ep93xx_pcm_hw_free,
  188. .trigger = ep93xx_pcm_trigger,
  189. .pointer = ep93xx_pcm_pointer,
  190. .mmap = ep93xx_pcm_mmap,
  191. };
  192. static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  193. {
  194. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  195. struct snd_dma_buffer *buf = &substream->dma_buffer;
  196. size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
  197. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  198. buf->dev.dev = pcm->card->dev;
  199. buf->private_data = NULL;
  200. buf->area = dma_alloc_writecombine(pcm->card->dev, size,
  201. &buf->addr, GFP_KERNEL);
  202. buf->bytes = size;
  203. return (buf->area == NULL) ? -ENOMEM : 0;
  204. }
  205. static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
  206. {
  207. struct snd_pcm_substream *substream;
  208. struct snd_dma_buffer *buf;
  209. int stream;
  210. for (stream = 0; stream < 2; stream++) {
  211. substream = pcm->streams[stream].substream;
  212. if (!substream)
  213. continue;
  214. buf = &substream->dma_buffer;
  215. if (!buf->area)
  216. continue;
  217. dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
  218. buf->addr);
  219. buf->area = NULL;
  220. }
  221. }
  222. static u64 ep93xx_pcm_dmamask = 0xffffffff;
  223. static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
  224. struct snd_pcm *pcm)
  225. {
  226. int ret = 0;
  227. if (!card->dev->dma_mask)
  228. card->dev->dma_mask = &ep93xx_pcm_dmamask;
  229. if (!card->dev->coherent_dma_mask)
  230. card->dev->coherent_dma_mask = 0xffffffff;
  231. if (dai->driver->playback.channels_min) {
  232. ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
  233. SNDRV_PCM_STREAM_PLAYBACK);
  234. if (ret)
  235. return ret;
  236. }
  237. if (dai->driver->capture.channels_min) {
  238. ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
  239. SNDRV_PCM_STREAM_CAPTURE);
  240. if (ret)
  241. return ret;
  242. }
  243. return 0;
  244. }
  245. static struct snd_soc_platform_driver ep93xx_soc_platform = {
  246. .ops = &ep93xx_pcm_ops,
  247. .pcm_new = &ep93xx_pcm_new,
  248. .pcm_free = &ep93xx_pcm_free_dma_buffers,
  249. };
  250. static int __devinit ep93xx_soc_platform_probe(struct platform_device *pdev)
  251. {
  252. return snd_soc_register_platform(&pdev->dev, &ep93xx_soc_platform);
  253. }
  254. static int __devexit ep93xx_soc_platform_remove(struct platform_device *pdev)
  255. {
  256. snd_soc_unregister_platform(&pdev->dev);
  257. return 0;
  258. }
  259. static struct platform_driver ep93xx_pcm_driver = {
  260. .driver = {
  261. .name = "ep93xx-pcm-audio",
  262. .owner = THIS_MODULE,
  263. },
  264. .probe = ep93xx_soc_platform_probe,
  265. .remove = __devexit_p(ep93xx_soc_platform_remove),
  266. };
  267. static int __init ep93xx_soc_platform_init(void)
  268. {
  269. return platform_driver_register(&ep93xx_pcm_driver);
  270. }
  271. static void __exit ep93xx_soc_platform_exit(void)
  272. {
  273. platform_driver_unregister(&ep93xx_pcm_driver);
  274. }
  275. module_init(ep93xx_soc_platform_init);
  276. module_exit(ep93xx_soc_platform_exit);
  277. MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
  278. MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
  279. MODULE_LICENSE("GPL");