at91-pcm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC
  3. *
  4. * Author: Frank Mandarino <fmandarino@endrelia.com>
  5. * Endrelia Technologies Inc.
  6. * Created: Mar 3, 2006
  7. *
  8. * Based on pxa2xx-pcm.c by:
  9. *
  10. * Author: Nicolas Pitre
  11. * Created: Nov 30, 2004
  12. * Copyright: (C) 2004 MontaVista Software, Inc.
  13. *
  14. * This program is free software; you can redistribute it and/or modify
  15. * it under the terms of the GNU General Public License version 2 as
  16. * published by the Free Software Foundation.
  17. */
  18. #include <linux/module.h>
  19. #include <linux/init.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/slab.h>
  22. #include <linux/dma-mapping.h>
  23. #include <linux/atmel_pdc.h>
  24. #include <sound/core.h>
  25. #include <sound/pcm.h>
  26. #include <sound/pcm_params.h>
  27. #include <sound/soc.h>
  28. #include <asm/arch/hardware.h>
  29. #include <asm/arch/at91_ssc.h>
  30. #include "at91-pcm.h"
  31. #if 0
  32. #define DBG(x...) printk(KERN_INFO "at91-pcm: " x)
  33. #else
  34. #define DBG(x...)
  35. #endif
  36. static const struct snd_pcm_hardware at91_pcm_hardware = {
  37. .info = SNDRV_PCM_INFO_MMAP |
  38. SNDRV_PCM_INFO_MMAP_VALID |
  39. SNDRV_PCM_INFO_INTERLEAVED |
  40. SNDRV_PCM_INFO_PAUSE,
  41. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  42. .period_bytes_min = 32,
  43. .period_bytes_max = 8192,
  44. .periods_min = 2,
  45. .periods_max = 1024,
  46. .buffer_bytes_max = 32 * 1024,
  47. };
  48. struct at91_runtime_data {
  49. struct at91_pcm_dma_params *params;
  50. dma_addr_t dma_buffer; /* physical address of dma buffer */
  51. dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
  52. size_t period_size;
  53. dma_addr_t period_ptr; /* physical address of next period */
  54. u32 pdc_xpr_save; /* PDC register save */
  55. u32 pdc_xcr_save;
  56. u32 pdc_xnpr_save;
  57. u32 pdc_xncr_save;
  58. };
  59. static void at91_pcm_dma_irq(u32 ssc_sr,
  60. struct snd_pcm_substream *substream)
  61. {
  62. struct at91_runtime_data *prtd = substream->runtime->private_data;
  63. struct at91_pcm_dma_params *params = prtd->params;
  64. static int count = 0;
  65. count++;
  66. if (ssc_sr & params->mask->ssc_endbuf) {
  67. printk(KERN_WARNING
  68. "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
  69. substream->stream == SNDRV_PCM_STREAM_PLAYBACK
  70. ? "underrun" : "overrun",
  71. params->name, ssc_sr, count);
  72. /* re-start the PDC */
  73. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  74. prtd->period_ptr += prtd->period_size;
  75. if (prtd->period_ptr >= prtd->dma_buffer_end) {
  76. prtd->period_ptr = prtd->dma_buffer;
  77. }
  78. at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
  79. at91_ssc_write(params->ssc_base + params->pdc->xcr,
  80. prtd->period_size / params->pdc_xfer_size);
  81. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  82. }
  83. if (ssc_sr & params->mask->ssc_endx) {
  84. /* Load the PDC next pointer and counter registers */
  85. prtd->period_ptr += prtd->period_size;
  86. if (prtd->period_ptr >= prtd->dma_buffer_end) {
  87. prtd->period_ptr = prtd->dma_buffer;
  88. }
  89. at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
  90. at91_ssc_write(params->ssc_base + params->pdc->xncr,
  91. prtd->period_size / params->pdc_xfer_size);
  92. }
  93. snd_pcm_period_elapsed(substream);
  94. }
  95. static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
  96. struct snd_pcm_hw_params *params)
  97. {
  98. struct snd_pcm_runtime *runtime = substream->runtime;
  99. struct at91_runtime_data *prtd = runtime->private_data;
  100. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  101. /* this may get called several times by oss emulation
  102. * with different params */
  103. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  104. runtime->dma_bytes = params_buffer_bytes(params);
  105. prtd->params = rtd->dai->cpu_dai->dma_data;
  106. prtd->params->dma_intr_handler = at91_pcm_dma_irq;
  107. prtd->dma_buffer = runtime->dma_addr;
  108. prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
  109. prtd->period_size = params_period_bytes(params);
  110. DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
  111. prtd->params->name, runtime->dma_bytes, prtd->period_size);
  112. return 0;
  113. }
  114. static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
  115. {
  116. struct at91_runtime_data *prtd = substream->runtime->private_data;
  117. struct at91_pcm_dma_params *params = prtd->params;
  118. if (params != NULL) {
  119. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  120. prtd->params->dma_intr_handler = NULL;
  121. }
  122. return 0;
  123. }
  124. static int at91_pcm_prepare(struct snd_pcm_substream *substream)
  125. {
  126. struct at91_runtime_data *prtd = substream->runtime->private_data;
  127. struct at91_pcm_dma_params *params = prtd->params;
  128. at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
  129. params->mask->ssc_endx | params->mask->ssc_endbuf);
  130. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  131. return 0;
  132. }
  133. static int at91_pcm_trigger(struct snd_pcm_substream *substream,
  134. int cmd)
  135. {
  136. struct at91_runtime_data *prtd = substream->runtime->private_data;
  137. struct at91_pcm_dma_params *params = prtd->params;
  138. int ret = 0;
  139. switch (cmd) {
  140. case SNDRV_PCM_TRIGGER_START:
  141. prtd->period_ptr = prtd->dma_buffer;
  142. at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
  143. at91_ssc_write(params->ssc_base + params->pdc->xcr,
  144. prtd->period_size / params->pdc_xfer_size);
  145. prtd->period_ptr += prtd->period_size;
  146. at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
  147. at91_ssc_write(params->ssc_base + params->pdc->xncr,
  148. prtd->period_size / params->pdc_xfer_size);
  149. DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
  150. (unsigned long) prtd->period_ptr,
  151. at91_ssc_read(params->ssc_base + params->pdc->xpr),
  152. at91_ssc_read(params->ssc_base + params->pdc->xcr),
  153. at91_ssc_read(params->ssc_base + params->pdc->xnpr),
  154. at91_ssc_read(params->ssc_base + params->pdc->xncr));
  155. at91_ssc_write(params->ssc_base + AT91_SSC_IER,
  156. params->mask->ssc_endx | params->mask->ssc_endbuf);
  157. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  158. DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR),
  159. at91_ssc_read(params->ssc_base + AT91_SSC_IER));
  160. break;
  161. case SNDRV_PCM_TRIGGER_STOP:
  162. case SNDRV_PCM_TRIGGER_SUSPEND:
  163. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  164. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  165. break;
  166. case SNDRV_PCM_TRIGGER_RESUME:
  167. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  168. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  169. break;
  170. default:
  171. ret = -EINVAL;
  172. }
  173. return ret;
  174. }
  175. static snd_pcm_uframes_t at91_pcm_pointer(
  176. struct snd_pcm_substream *substream)
  177. {
  178. struct snd_pcm_runtime *runtime = substream->runtime;
  179. struct at91_runtime_data *prtd = runtime->private_data;
  180. struct at91_pcm_dma_params *params = prtd->params;
  181. dma_addr_t ptr;
  182. snd_pcm_uframes_t x;
  183. ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
  184. x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
  185. if (x == runtime->buffer_size)
  186. x = 0;
  187. return x;
  188. }
  189. static int at91_pcm_open(struct snd_pcm_substream *substream)
  190. {
  191. struct snd_pcm_runtime *runtime = substream->runtime;
  192. struct at91_runtime_data *prtd;
  193. int ret = 0;
  194. snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
  195. /* ensure that buffer size is a multiple of period size */
  196. ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
  197. if (ret < 0)
  198. goto out;
  199. prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
  200. if (prtd == NULL) {
  201. ret = -ENOMEM;
  202. goto out;
  203. }
  204. runtime->private_data = prtd;
  205. out:
  206. return ret;
  207. }
  208. static int at91_pcm_close(struct snd_pcm_substream *substream)
  209. {
  210. struct at91_runtime_data *prtd = substream->runtime->private_data;
  211. kfree(prtd);
  212. return 0;
  213. }
  214. static int at91_pcm_mmap(struct snd_pcm_substream *substream,
  215. struct vm_area_struct *vma)
  216. {
  217. struct snd_pcm_runtime *runtime = substream->runtime;
  218. return dma_mmap_writecombine(substream->pcm->card->dev, vma,
  219. runtime->dma_area,
  220. runtime->dma_addr,
  221. runtime->dma_bytes);
  222. }
  223. struct snd_pcm_ops at91_pcm_ops = {
  224. .open = at91_pcm_open,
  225. .close = at91_pcm_close,
  226. .ioctl = snd_pcm_lib_ioctl,
  227. .hw_params = at91_pcm_hw_params,
  228. .hw_free = at91_pcm_hw_free,
  229. .prepare = at91_pcm_prepare,
  230. .trigger = at91_pcm_trigger,
  231. .pointer = at91_pcm_pointer,
  232. .mmap = at91_pcm_mmap,
  233. };
  234. static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
  235. int stream)
  236. {
  237. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  238. struct snd_dma_buffer *buf = &substream->dma_buffer;
  239. size_t size = at91_pcm_hardware.buffer_bytes_max;
  240. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  241. buf->dev.dev = pcm->card->dev;
  242. buf->private_data = NULL;
  243. buf->area = dma_alloc_writecombine(pcm->card->dev, size,
  244. &buf->addr, GFP_KERNEL);
  245. DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
  246. (void *) buf->area,
  247. (void *) buf->addr,
  248. size);
  249. if (!buf->area)
  250. return -ENOMEM;
  251. buf->bytes = size;
  252. return 0;
  253. }
  254. static u64 at91_pcm_dmamask = 0xffffffff;
  255. static int at91_pcm_new(struct snd_card *card,
  256. struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
  257. {
  258. int ret = 0;
  259. if (!card->dev->dma_mask)
  260. card->dev->dma_mask = &at91_pcm_dmamask;
  261. if (!card->dev->coherent_dma_mask)
  262. card->dev->coherent_dma_mask = 0xffffffff;
  263. if (dai->playback.channels_min) {
  264. ret = at91_pcm_preallocate_dma_buffer(pcm,
  265. SNDRV_PCM_STREAM_PLAYBACK);
  266. if (ret)
  267. goto out;
  268. }
  269. if (dai->capture.channels_min) {
  270. ret = at91_pcm_preallocate_dma_buffer(pcm,
  271. SNDRV_PCM_STREAM_CAPTURE);
  272. if (ret)
  273. goto out;
  274. }
  275. out:
  276. return ret;
  277. }
  278. static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
  279. {
  280. struct snd_pcm_substream *substream;
  281. struct snd_dma_buffer *buf;
  282. int stream;
  283. for (stream = 0; stream < 2; stream++) {
  284. substream = pcm->streams[stream].substream;
  285. if (!substream)
  286. continue;
  287. buf = &substream->dma_buffer;
  288. if (!buf->area)
  289. continue;
  290. dma_free_writecombine(pcm->card->dev, buf->bytes,
  291. buf->area, buf->addr);
  292. buf->area = NULL;
  293. }
  294. }
  295. #ifdef CONFIG_PM
  296. static int at91_pcm_suspend(struct platform_device *pdev,
  297. struct snd_soc_cpu_dai *dai)
  298. {
  299. struct snd_pcm_runtime *runtime = dai->runtime;
  300. struct at91_runtime_data *prtd;
  301. struct at91_pcm_dma_params *params;
  302. if (!runtime)
  303. return 0;
  304. prtd = runtime->private_data;
  305. params = prtd->params;
  306. /* disable the PDC and save the PDC registers */
  307. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  308. prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr);
  309. prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr);
  310. prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
  311. prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
  312. return 0;
  313. }
  314. static int at91_pcm_resume(struct platform_device *pdev,
  315. struct snd_soc_cpu_dai *dai)
  316. {
  317. struct snd_pcm_runtime *runtime = dai->runtime;
  318. struct at91_runtime_data *prtd;
  319. struct at91_pcm_dma_params *params;
  320. if (!runtime)
  321. return 0;
  322. prtd = runtime->private_data;
  323. params = prtd->params;
  324. /* restore the PDC registers and enable the PDC */
  325. at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save);
  326. at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save);
  327. at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
  328. at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
  329. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  330. return 0;
  331. }
  332. #else
  333. #define at91_pcm_suspend NULL
  334. #define at91_pcm_resume NULL
  335. #endif
  336. struct snd_soc_platform at91_soc_platform = {
  337. .name = "at91-audio",
  338. .pcm_ops = &at91_pcm_ops,
  339. .pcm_new = at91_pcm_new,
  340. .pcm_free = at91_pcm_free_dma_buffers,
  341. .suspend = at91_pcm_suspend,
  342. .resume = at91_pcm_resume,
  343. };
  344. EXPORT_SYMBOL_GPL(at91_soc_platform);
  345. MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
  346. MODULE_DESCRIPTION("Atmel AT91 PCM module");
  347. MODULE_LICENSE("GPL");