tegra_pcm.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * tegra_pcm.c - Tegra PCM driver
  3. *
  4. * Author: Stephen Warren <swarren@nvidia.com>
  5. * Copyright (C) 2010,2012 - NVIDIA, Inc.
  6. *
  7. * Based on code copyright/by:
  8. *
  9. * Copyright (c) 2009-2010, NVIDIA Corporation.
  10. * Scott Peterson <speterson@nvidia.com>
  11. * Vijay Mali <vmali@nvidia.com>
  12. *
  13. * Copyright (C) 2010 Google, Inc.
  14. * Iliyan Malchev <malchev@google.com>
  15. *
  16. * This program is free software; you can redistribute it and/or
  17. * modify it under the terms of the GNU General Public License
  18. * version 2 as published by the Free Software Foundation.
  19. *
  20. * This program is distributed in the hope that it will be useful, but
  21. * WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  23. * General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, write to the Free Software
  27. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  28. * 02110-1301 USA
  29. *
  30. */
  31. #include <linux/dma-mapping.h>
  32. #include <linux/module.h>
  33. #include <linux/slab.h>
  34. #include <sound/core.h>
  35. #include <sound/pcm.h>
  36. #include <sound/pcm_params.h>
  37. #include <sound/soc.h>
  38. #include <sound/dmaengine_pcm.h>
  39. #include "tegra_pcm.h"
  40. static const struct snd_pcm_hardware tegra_pcm_hardware = {
  41. .info = SNDRV_PCM_INFO_MMAP |
  42. SNDRV_PCM_INFO_MMAP_VALID |
  43. SNDRV_PCM_INFO_PAUSE |
  44. SNDRV_PCM_INFO_RESUME |
  45. SNDRV_PCM_INFO_INTERLEAVED,
  46. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  47. .channels_min = 2,
  48. .channels_max = 2,
  49. .period_bytes_min = 1024,
  50. .period_bytes_max = PAGE_SIZE,
  51. .periods_min = 2,
  52. .periods_max = 8,
  53. .buffer_bytes_max = PAGE_SIZE * 8,
  54. .fifo_size = 4,
  55. };
  56. static int tegra_pcm_open(struct snd_pcm_substream *substream)
  57. {
  58. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  59. struct device *dev = rtd->platform->dev;
  60. int ret;
  61. /* Set HW params now that initialization is complete */
  62. snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
  63. ret = snd_dmaengine_pcm_open(substream, NULL, NULL);
  64. if (ret) {
  65. dev_err(dev, "dmaengine pcm open failed with err %d\n", ret);
  66. return ret;
  67. }
  68. return 0;
  69. }
  70. static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
  71. struct snd_pcm_hw_params *params)
  72. {
  73. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  74. struct device *dev = rtd->platform->dev;
  75. struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
  76. struct tegra_pcm_dma_params *dmap;
  77. struct dma_slave_config slave_config;
  78. int ret;
  79. dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
  80. ret = snd_hwparams_to_dma_slave_config(substream, params,
  81. &slave_config);
  82. if (ret) {
  83. dev_err(dev, "hw params config failed with err %d\n", ret);
  84. return ret;
  85. }
  86. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  87. slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
  88. slave_config.dst_addr = dmap->addr;
  89. slave_config.dst_maxburst = 4;
  90. } else {
  91. slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
  92. slave_config.src_addr = dmap->addr;
  93. slave_config.src_maxburst = 4;
  94. }
  95. slave_config.slave_id = dmap->req_sel;
  96. ret = dmaengine_slave_config(chan, &slave_config);
  97. if (ret < 0) {
  98. dev_err(dev, "dma slave config failed with err %d\n", ret);
  99. return ret;
  100. }
  101. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  102. return 0;
  103. }
  104. static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
  105. {
  106. snd_pcm_set_runtime_buffer(substream, NULL);
  107. return 0;
  108. }
  109. static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  110. {
  111. switch (cmd) {
  112. case SNDRV_PCM_TRIGGER_START:
  113. case SNDRV_PCM_TRIGGER_RESUME:
  114. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  115. return snd_dmaengine_pcm_trigger(substream,
  116. SNDRV_PCM_TRIGGER_START);
  117. case SNDRV_PCM_TRIGGER_STOP:
  118. case SNDRV_PCM_TRIGGER_SUSPEND:
  119. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  120. return snd_dmaengine_pcm_trigger(substream,
  121. SNDRV_PCM_TRIGGER_STOP);
  122. default:
  123. return -EINVAL;
  124. }
  125. return 0;
  126. }
  127. static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
  128. struct vm_area_struct *vma)
  129. {
  130. struct snd_pcm_runtime *runtime = substream->runtime;
  131. return dma_mmap_writecombine(substream->pcm->card->dev, vma,
  132. runtime->dma_area,
  133. runtime->dma_addr,
  134. runtime->dma_bytes);
  135. }
  136. static struct snd_pcm_ops tegra_pcm_ops = {
  137. .open = tegra_pcm_open,
  138. .close = snd_dmaengine_pcm_close,
  139. .ioctl = snd_pcm_lib_ioctl,
  140. .hw_params = tegra_pcm_hw_params,
  141. .hw_free = tegra_pcm_hw_free,
  142. .trigger = tegra_pcm_trigger,
  143. .pointer = snd_dmaengine_pcm_pointer,
  144. .mmap = tegra_pcm_mmap,
  145. };
  146. static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  147. {
  148. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  149. struct snd_dma_buffer *buf = &substream->dma_buffer;
  150. size_t size = tegra_pcm_hardware.buffer_bytes_max;
  151. buf->area = dma_alloc_writecombine(pcm->card->dev, size,
  152. &buf->addr, GFP_KERNEL);
  153. if (!buf->area)
  154. return -ENOMEM;
  155. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  156. buf->dev.dev = pcm->card->dev;
  157. buf->private_data = NULL;
  158. buf->bytes = size;
  159. return 0;
  160. }
  161. static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  162. {
  163. struct snd_pcm_substream *substream;
  164. struct snd_dma_buffer *buf;
  165. substream = pcm->streams[stream].substream;
  166. if (!substream)
  167. return;
  168. buf = &substream->dma_buffer;
  169. if (!buf->area)
  170. return;
  171. dma_free_writecombine(pcm->card->dev, buf->bytes,
  172. buf->area, buf->addr);
  173. buf->area = NULL;
  174. }
  175. static u64 tegra_dma_mask = DMA_BIT_MASK(32);
  176. static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
  177. {
  178. struct snd_card *card = rtd->card->snd_card;
  179. struct snd_pcm *pcm = rtd->pcm;
  180. int ret = 0;
  181. if (!card->dev->dma_mask)
  182. card->dev->dma_mask = &tegra_dma_mask;
  183. if (!card->dev->coherent_dma_mask)
  184. card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
  185. if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
  186. ret = tegra_pcm_preallocate_dma_buffer(pcm,
  187. SNDRV_PCM_STREAM_PLAYBACK);
  188. if (ret)
  189. goto err;
  190. }
  191. if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
  192. ret = tegra_pcm_preallocate_dma_buffer(pcm,
  193. SNDRV_PCM_STREAM_CAPTURE);
  194. if (ret)
  195. goto err_free_play;
  196. }
  197. return 0;
  198. err_free_play:
  199. tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
  200. err:
  201. return ret;
  202. }
  203. static void tegra_pcm_free(struct snd_pcm *pcm)
  204. {
  205. tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
  206. tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
  207. }
  208. static struct snd_soc_platform_driver tegra_pcm_platform = {
  209. .ops = &tegra_pcm_ops,
  210. .pcm_new = tegra_pcm_new,
  211. .pcm_free = tegra_pcm_free,
  212. };
  213. int tegra_pcm_platform_register(struct device *dev)
  214. {
  215. return snd_soc_register_platform(dev, &tegra_pcm_platform);
  216. }
  217. EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
  218. void tegra_pcm_platform_unregister(struct device *dev)
  219. {
  220. snd_soc_unregister_platform(dev);
  221. }
  222. EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
  223. MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
  224. MODULE_DESCRIPTION("Tegra PCM ASoC driver");
  225. MODULE_LICENSE("GPL");