jz4740-pcm.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation; either version 2 of the License, or (at your
  7. * option) any later version.
  8. *
  9. * You should have received a copy of the GNU General Public License along
  10. * with this program; if not, write to the Free Software Foundation, Inc.,
  11. * 675 Mass Ave, Cambridge, MA 02139, USA.
  12. *
  13. */
  14. #include <linux/init.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/slab.h>
  20. #include <linux/dma-mapping.h>
  21. #include <sound/core.h>
  22. #include <sound/pcm.h>
  23. #include <sound/pcm_params.h>
  24. #include <sound/soc.h>
  25. #include <asm/mach-jz4740/dma.h>
  26. #include "jz4740-pcm.h"
  27. struct jz4740_runtime_data {
  28. unsigned long dma_period;
  29. dma_addr_t dma_start;
  30. dma_addr_t dma_pos;
  31. dma_addr_t dma_end;
  32. struct jz4740_dma_chan *dma;
  33. dma_addr_t fifo_addr;
  34. };
  35. /* identify hardware playback capabilities */
  36. static const struct snd_pcm_hardware jz4740_pcm_hardware = {
  37. .info = SNDRV_PCM_INFO_MMAP |
  38. SNDRV_PCM_INFO_MMAP_VALID |
  39. SNDRV_PCM_INFO_INTERLEAVED |
  40. SNDRV_PCM_INFO_BLOCK_TRANSFER,
  41. .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
  42. .rates = SNDRV_PCM_RATE_8000_48000,
  43. .channels_min = 1,
  44. .channels_max = 2,
  45. .period_bytes_min = 16,
  46. .period_bytes_max = 2 * PAGE_SIZE,
  47. .periods_min = 2,
  48. .periods_max = 128,
  49. .buffer_bytes_max = 128 * 2 * PAGE_SIZE,
  50. .fifo_size = 32,
  51. };
  52. static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd,
  53. struct snd_pcm_substream *substream)
  54. {
  55. unsigned long count;
  56. if (prtd->dma_pos == prtd->dma_end)
  57. prtd->dma_pos = prtd->dma_start;
  58. if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
  59. count = prtd->dma_end - prtd->dma_pos;
  60. else
  61. count = prtd->dma_period;
  62. jz4740_dma_disable(prtd->dma);
  63. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  64. jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos);
  65. jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr);
  66. } else {
  67. jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr);
  68. jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos);
  69. }
  70. jz4740_dma_set_transfer_count(prtd->dma, count);
  71. prtd->dma_pos += count;
  72. jz4740_dma_enable(prtd->dma);
  73. }
  74. static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err,
  75. void *dev_id)
  76. {
  77. struct snd_pcm_substream *substream = dev_id;
  78. struct snd_pcm_runtime *runtime = substream->runtime;
  79. struct jz4740_runtime_data *prtd = runtime->private_data;
  80. snd_pcm_period_elapsed(substream);
  81. jz4740_pcm_start_transfer(prtd, substream);
  82. }
  83. static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream,
  84. struct snd_pcm_hw_params *params)
  85. {
  86. struct snd_pcm_runtime *runtime = substream->runtime;
  87. struct jz4740_runtime_data *prtd = runtime->private_data;
  88. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  89. struct jz4740_pcm_config *config;
  90. config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
  91. if (!config)
  92. return 0;
  93. if (!prtd->dma) {
  94. if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
  95. prtd->dma = jz4740_dma_request(substream, "PCM Capture");
  96. else
  97. prtd->dma = jz4740_dma_request(substream, "PCM Playback");
  98. }
  99. if (!prtd->dma)
  100. return -EBUSY;
  101. jz4740_dma_configure(prtd->dma, &config->dma_config);
  102. prtd->fifo_addr = config->fifo_addr;
  103. jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done);
  104. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  105. runtime->dma_bytes = params_buffer_bytes(params);
  106. prtd->dma_period = params_period_bytes(params);
  107. prtd->dma_start = runtime->dma_addr;
  108. prtd->dma_pos = prtd->dma_start;
  109. prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
  110. return 0;
  111. }
  112. static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream)
  113. {
  114. struct jz4740_runtime_data *prtd = substream->runtime->private_data;
  115. snd_pcm_set_runtime_buffer(substream, NULL);
  116. if (prtd->dma) {
  117. jz4740_dma_free(prtd->dma);
  118. prtd->dma = NULL;
  119. }
  120. return 0;
  121. }
  122. static int jz4740_pcm_prepare(struct snd_pcm_substream *substream)
  123. {
  124. struct jz4740_runtime_data *prtd = substream->runtime->private_data;
  125. if (!prtd->dma)
  126. return -EBUSY;
  127. prtd->dma_pos = prtd->dma_start;
  128. return 0;
  129. }
  130. static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  131. {
  132. struct snd_pcm_runtime *runtime = substream->runtime;
  133. struct jz4740_runtime_data *prtd = runtime->private_data;
  134. switch (cmd) {
  135. case SNDRV_PCM_TRIGGER_START:
  136. case SNDRV_PCM_TRIGGER_RESUME:
  137. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  138. jz4740_pcm_start_transfer(prtd, substream);
  139. break;
  140. case SNDRV_PCM_TRIGGER_STOP:
  141. case SNDRV_PCM_TRIGGER_SUSPEND:
  142. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  143. jz4740_dma_disable(prtd->dma);
  144. break;
  145. default:
  146. break;
  147. }
  148. return 0;
  149. }
  150. static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream)
  151. {
  152. struct snd_pcm_runtime *runtime = substream->runtime;
  153. struct jz4740_runtime_data *prtd = runtime->private_data;
  154. unsigned long byte_offset;
  155. snd_pcm_uframes_t offset;
  156. struct jz4740_dma_chan *dma = prtd->dma;
  157. /* prtd->dma_pos points to the end of the current transfer. So by
  158. * subtracting prdt->dma_start we get the offset to the end of the
  159. * current period in bytes. By subtracting the residue of the transfer
  160. * we get the current offset in bytes. */
  161. byte_offset = prtd->dma_pos - prtd->dma_start;
  162. byte_offset -= jz4740_dma_get_residue(dma);
  163. offset = bytes_to_frames(runtime, byte_offset);
  164. if (offset >= runtime->buffer_size)
  165. offset = 0;
  166. return offset;
  167. }
  168. static int jz4740_pcm_open(struct snd_pcm_substream *substream)
  169. {
  170. struct snd_pcm_runtime *runtime = substream->runtime;
  171. struct jz4740_runtime_data *prtd;
  172. prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
  173. if (prtd == NULL)
  174. return -ENOMEM;
  175. snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
  176. runtime->private_data = prtd;
  177. return 0;
  178. }
  179. static int jz4740_pcm_close(struct snd_pcm_substream *substream)
  180. {
  181. struct snd_pcm_runtime *runtime = substream->runtime;
  182. struct jz4740_runtime_data *prtd = runtime->private_data;
  183. kfree(prtd);
  184. return 0;
  185. }
  186. static int jz4740_pcm_mmap(struct snd_pcm_substream *substream,
  187. struct vm_area_struct *vma)
  188. {
  189. return remap_pfn_range(vma, vma->vm_start,
  190. substream->dma_buffer.addr >> PAGE_SHIFT,
  191. vma->vm_end - vma->vm_start, vma->vm_page_prot);
  192. }
  193. static struct snd_pcm_ops jz4740_pcm_ops = {
  194. .open = jz4740_pcm_open,
  195. .close = jz4740_pcm_close,
  196. .ioctl = snd_pcm_lib_ioctl,
  197. .hw_params = jz4740_pcm_hw_params,
  198. .hw_free = jz4740_pcm_hw_free,
  199. .prepare = jz4740_pcm_prepare,
  200. .trigger = jz4740_pcm_trigger,
  201. .pointer = jz4740_pcm_pointer,
  202. .mmap = jz4740_pcm_mmap,
  203. };
  204. static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  205. {
  206. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  207. struct snd_dma_buffer *buf = &substream->dma_buffer;
  208. size_t size = jz4740_pcm_hardware.buffer_bytes_max;
  209. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  210. buf->dev.dev = pcm->card->dev;
  211. buf->private_data = NULL;
  212. buf->area = dma_alloc_noncoherent(pcm->card->dev, size,
  213. &buf->addr, GFP_KERNEL);
  214. if (!buf->area)
  215. return -ENOMEM;
  216. buf->bytes = size;
  217. return 0;
  218. }
  219. static void jz4740_pcm_free(struct snd_pcm *pcm)
  220. {
  221. struct snd_pcm_substream *substream;
  222. struct snd_dma_buffer *buf;
  223. int stream;
  224. for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) {
  225. substream = pcm->streams[stream].substream;
  226. if (!substream)
  227. continue;
  228. buf = &substream->dma_buffer;
  229. if (!buf->area)
  230. continue;
  231. dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area,
  232. buf->addr);
  233. buf->area = NULL;
  234. }
  235. }
  236. static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32);
  237. static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd)
  238. {
  239. struct snd_card *card = rtd->card->snd_card;
  240. struct snd_pcm *pcm = rtd->pcm;
  241. int ret = 0;
  242. if (!card->dev->dma_mask)
  243. card->dev->dma_mask = &jz4740_pcm_dmamask;
  244. if (!card->dev->coherent_dma_mask)
  245. card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  246. if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
  247. ret = jz4740_pcm_preallocate_dma_buffer(pcm,
  248. SNDRV_PCM_STREAM_PLAYBACK);
  249. if (ret)
  250. goto err;
  251. }
  252. if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
  253. ret = jz4740_pcm_preallocate_dma_buffer(pcm,
  254. SNDRV_PCM_STREAM_CAPTURE);
  255. if (ret)
  256. goto err;
  257. }
  258. err:
  259. return ret;
  260. }
  261. static struct snd_soc_platform_driver jz4740_soc_platform = {
  262. .ops = &jz4740_pcm_ops,
  263. .pcm_new = jz4740_pcm_new,
  264. .pcm_free = jz4740_pcm_free,
  265. };
  266. static int __devinit jz4740_pcm_probe(struct platform_device *pdev)
  267. {
  268. return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform);
  269. }
  270. static int __devexit jz4740_pcm_remove(struct platform_device *pdev)
  271. {
  272. snd_soc_unregister_platform(&pdev->dev);
  273. return 0;
  274. }
  275. static struct platform_driver jz4740_pcm_driver = {
  276. .probe = jz4740_pcm_probe,
  277. .remove = __devexit_p(jz4740_pcm_remove),
  278. .driver = {
  279. .name = "jz4740-pcm-audio",
  280. .owner = THIS_MODULE,
  281. },
  282. };
  283. module_platform_driver(jz4740_pcm_driver);
  284. MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
  285. MODULE_DESCRIPTION("Ingenic SoC JZ4740 PCM driver");
  286. MODULE_LICENSE("GPL");