ux500_pcm.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * Copyright (C) ST-Ericsson SA 2012
  3. *
  4. * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
  5. * Roger Nilsson <roger.xr.nilsson@stericsson.com>
  6. * for ST-Ericsson.
  7. *
  8. * License terms:
  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 published
  12. * by the Free Software Foundation.
  13. */
  14. #include <asm/page.h>
  15. #include <linux/module.h>
  16. #include <linux/dma-mapping.h>
  17. #include <linux/dmaengine.h>
  18. #include <linux/slab.h>
  19. #include <linux/platform_data/dma-ste-dma40.h>
  20. #include <sound/pcm.h>
  21. #include <sound/pcm_params.h>
  22. #include <sound/soc.h>
  23. #include <sound/dmaengine_pcm.h>
  24. #include "ux500_msp_i2s.h"
  25. #include "ux500_pcm.h"
  26. static struct snd_pcm_hardware ux500_pcm_hw_playback = {
  27. .info = SNDRV_PCM_INFO_INTERLEAVED |
  28. SNDRV_PCM_INFO_MMAP |
  29. SNDRV_PCM_INFO_RESUME |
  30. SNDRV_PCM_INFO_PAUSE,
  31. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  32. SNDRV_PCM_FMTBIT_U16_LE |
  33. SNDRV_PCM_FMTBIT_S16_BE |
  34. SNDRV_PCM_FMTBIT_U16_BE,
  35. .rates = SNDRV_PCM_RATE_KNOT,
  36. .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
  37. .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
  38. .channels_min = UX500_PLATFORM_MIN_CHANNELS,
  39. .channels_max = UX500_PLATFORM_MAX_CHANNELS,
  40. .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
  41. .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
  42. .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
  43. .periods_min = UX500_PLATFORM_PERIODS_MIN,
  44. .periods_max = UX500_PLATFORM_PERIODS_MAX,
  45. };
  46. static struct snd_pcm_hardware ux500_pcm_hw_capture = {
  47. .info = SNDRV_PCM_INFO_INTERLEAVED |
  48. SNDRV_PCM_INFO_MMAP |
  49. SNDRV_PCM_INFO_RESUME |
  50. SNDRV_PCM_INFO_PAUSE,
  51. .formats = SNDRV_PCM_FMTBIT_S16_LE |
  52. SNDRV_PCM_FMTBIT_U16_LE |
  53. SNDRV_PCM_FMTBIT_S16_BE |
  54. SNDRV_PCM_FMTBIT_U16_BE,
  55. .rates = SNDRV_PCM_RATE_KNOT,
  56. .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE,
  57. .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE,
  58. .channels_min = UX500_PLATFORM_MIN_CHANNELS,
  59. .channels_max = UX500_PLATFORM_MAX_CHANNELS,
  60. .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
  61. .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
  62. .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
  63. .periods_min = UX500_PLATFORM_PERIODS_MIN,
  64. .periods_max = UX500_PLATFORM_PERIODS_MAX,
  65. };
  66. static void ux500_pcm_dma_hw_free(struct device *dev,
  67. struct snd_pcm_substream *substream)
  68. {
  69. struct snd_pcm_runtime *runtime = substream->runtime;
  70. struct snd_dma_buffer *buf = runtime->dma_buffer_p;
  71. if (runtime->dma_area == NULL)
  72. return;
  73. if (buf != &substream->dma_buffer) {
  74. dma_free_coherent(buf->dev.dev, buf->bytes, buf->area,
  75. buf->addr);
  76. kfree(runtime->dma_buffer_p);
  77. }
  78. snd_pcm_set_runtime_buffer(substream, NULL);
  79. }
  80. static int ux500_pcm_open(struct snd_pcm_substream *substream)
  81. {
  82. int stream_id = substream->pstr->stream;
  83. struct snd_pcm_runtime *runtime = substream->runtime;
  84. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  85. struct snd_soc_dai *dai = rtd->cpu_dai;
  86. struct device *dev = dai->dev;
  87. int ret;
  88. struct ux500_msp_dma_params *dma_params;
  89. u16 per_data_width, mem_data_width;
  90. struct stedma40_chan_cfg *dma_cfg;
  91. dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
  92. snd_pcm_stream_str(substream));
  93. dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__);
  94. if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
  95. snd_soc_set_runtime_hwparams(substream,
  96. &ux500_pcm_hw_playback);
  97. else
  98. snd_soc_set_runtime_hwparams(substream,
  99. &ux500_pcm_hw_capture);
  100. /* ensure that buffer size is a multiple of period size */
  101. ret = snd_pcm_hw_constraint_integer(runtime,
  102. SNDRV_PCM_HW_PARAM_PERIODS);
  103. if (ret < 0) {
  104. dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n",
  105. __func__, ret);
  106. return ret;
  107. }
  108. dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__,
  109. snd_pcm_stream_str(substream));
  110. runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
  111. ux500_pcm_hw_playback : ux500_pcm_hw_capture;
  112. mem_data_width = STEDMA40_HALFWORD_WIDTH;
  113. dma_params = snd_soc_dai_get_dma_data(dai, substream);
  114. switch (dma_params->data_size) {
  115. case 32:
  116. per_data_width = STEDMA40_WORD_WIDTH;
  117. break;
  118. case 16:
  119. per_data_width = STEDMA40_HALFWORD_WIDTH;
  120. break;
  121. case 8:
  122. per_data_width = STEDMA40_BYTE_WIDTH;
  123. break;
  124. default:
  125. per_data_width = STEDMA40_WORD_WIDTH;
  126. dev_warn(rtd->platform->dev,
  127. "%s: Unknown data-size (%d)! Assuming 32 bits.\n",
  128. __func__, dma_params->data_size);
  129. }
  130. dma_cfg = dma_params->dma_cfg;
  131. if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  132. dma_cfg->src_info.data_width = mem_data_width;
  133. dma_cfg->dst_info.data_width = per_data_width;
  134. } else {
  135. dma_cfg->src_info.data_width = per_data_width;
  136. dma_cfg->dst_info.data_width = mem_data_width;
  137. }
  138. ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg);
  139. if (ret) {
  140. dev_dbg(dai->dev,
  141. "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
  142. __func__, ret);
  143. return ret;
  144. }
  145. snd_dmaengine_pcm_set_data(substream, dma_cfg);
  146. return 0;
  147. }
  148. static int ux500_pcm_close(struct snd_pcm_substream *substream)
  149. {
  150. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  151. struct snd_soc_dai *dai = rtd->cpu_dai;
  152. dev_dbg(dai->dev, "%s: Enter\n", __func__);
  153. snd_dmaengine_pcm_close(substream);
  154. return 0;
  155. }
  156. static int ux500_pcm_hw_params(struct snd_pcm_substream *substream,
  157. struct snd_pcm_hw_params *hw_params)
  158. {
  159. struct snd_pcm_runtime *runtime = substream->runtime;
  160. struct snd_dma_buffer *buf = runtime->dma_buffer_p;
  161. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  162. int ret = 0;
  163. int size;
  164. dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
  165. size = params_buffer_bytes(hw_params);
  166. if (buf) {
  167. if (buf->bytes >= size)
  168. goto out;
  169. ux500_pcm_dma_hw_free(NULL, substream);
  170. }
  171. if (substream->dma_buffer.area != NULL &&
  172. substream->dma_buffer.bytes >= size) {
  173. buf = &substream->dma_buffer;
  174. } else {
  175. buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
  176. if (!buf)
  177. goto nomem;
  178. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  179. buf->dev.dev = NULL;
  180. buf->area = dma_alloc_coherent(NULL, size, &buf->addr,
  181. GFP_KERNEL);
  182. buf->bytes = size;
  183. buf->private_data = NULL;
  184. if (!buf->area)
  185. goto free;
  186. }
  187. snd_pcm_set_runtime_buffer(substream, buf);
  188. ret = 1;
  189. out:
  190. runtime->dma_bytes = size;
  191. return ret;
  192. free:
  193. kfree(buf);
  194. nomem:
  195. return -ENOMEM;
  196. }
  197. static int ux500_pcm_hw_free(struct snd_pcm_substream *substream)
  198. {
  199. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  200. dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
  201. ux500_pcm_dma_hw_free(NULL, substream);
  202. return 0;
  203. }
  204. static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
  205. struct vm_area_struct *vma)
  206. {
  207. struct snd_pcm_runtime *runtime = substream->runtime;
  208. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  209. dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__);
  210. return dma_mmap_coherent(NULL, vma, runtime->dma_area,
  211. runtime->dma_addr, runtime->dma_bytes);
  212. }
  213. static struct snd_pcm_ops ux500_pcm_ops = {
  214. .open = ux500_pcm_open,
  215. .close = ux500_pcm_close,
  216. .ioctl = snd_pcm_lib_ioctl,
  217. .hw_params = ux500_pcm_hw_params,
  218. .hw_free = ux500_pcm_hw_free,
  219. .trigger = snd_dmaengine_pcm_trigger,
  220. .pointer = snd_dmaengine_pcm_pointer_no_residue,
  221. .mmap = ux500_pcm_mmap
  222. };
  223. int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd)
  224. {
  225. struct snd_pcm *pcm = rtd->pcm;
  226. dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__,
  227. pcm->id);
  228. pcm->info_flags = 0;
  229. return 0;
  230. }
  231. static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
  232. .ops = &ux500_pcm_ops,
  233. .pcm_new = ux500_pcm_new,
  234. };
  235. int ux500_pcm_register_platform(struct platform_device *pdev)
  236. {
  237. int ret;
  238. ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv);
  239. if (ret < 0) {
  240. dev_err(&pdev->dev,
  241. "%s: ERROR: Failed to register platform '%s' (%d)!\n",
  242. __func__, pdev->name, ret);
  243. return ret;
  244. }
  245. return 0;
  246. }
  247. EXPORT_SYMBOL_GPL(ux500_pcm_register_platform);
  248. int ux500_pcm_unregister_platform(struct platform_device *pdev)
  249. {
  250. snd_soc_unregister_platform(&pdev->dev);
  251. return 0;
  252. }
  253. EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);