at91-pcm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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 <mach/hardware.h>
  29. #include <mach/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,
  90. prtd->period_ptr);
  91. at91_ssc_write(params->ssc_base + params->pdc->xncr,
  92. prtd->period_size / params->pdc_xfer_size);
  93. }
  94. snd_pcm_period_elapsed(substream);
  95. }
  96. static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
  97. struct snd_pcm_hw_params *params)
  98. {
  99. struct snd_pcm_runtime *runtime = substream->runtime;
  100. struct at91_runtime_data *prtd = runtime->private_data;
  101. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  102. /* this may get called several times by oss emulation
  103. * with different params */
  104. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  105. runtime->dma_bytes = params_buffer_bytes(params);
  106. prtd->params = rtd->dai->cpu_dai->dma_data;
  107. prtd->params->dma_intr_handler = at91_pcm_dma_irq;
  108. prtd->dma_buffer = runtime->dma_addr;
  109. prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
  110. prtd->period_size = params_period_bytes(params);
  111. DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
  112. prtd->params->name, runtime->dma_bytes, prtd->period_size);
  113. return 0;
  114. }
  115. static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
  116. {
  117. struct at91_runtime_data *prtd = substream->runtime->private_data;
  118. struct at91_pcm_dma_params *params = prtd->params;
  119. if (params != NULL) {
  120. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  121. prtd->params->dma_intr_handler = NULL;
  122. }
  123. return 0;
  124. }
  125. static int at91_pcm_prepare(struct snd_pcm_substream *substream)
  126. {
  127. struct at91_runtime_data *prtd = substream->runtime->private_data;
  128. struct at91_pcm_dma_params *params = prtd->params;
  129. at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
  130. params->mask->ssc_endx | params->mask->ssc_endbuf);
  131. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  132. return 0;
  133. }
  134. static int at91_pcm_trigger(struct snd_pcm_substream *substream,
  135. int cmd)
  136. {
  137. struct at91_runtime_data *prtd = substream->runtime->private_data;
  138. struct at91_pcm_dma_params *params = prtd->params;
  139. int ret = 0;
  140. switch (cmd) {
  141. case SNDRV_PCM_TRIGGER_START:
  142. prtd->period_ptr = prtd->dma_buffer;
  143. at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
  144. at91_ssc_write(params->ssc_base + params->pdc->xcr,
  145. prtd->period_size / params->pdc_xfer_size);
  146. prtd->period_ptr += prtd->period_size;
  147. at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
  148. at91_ssc_write(params->ssc_base + params->pdc->xncr,
  149. prtd->period_size / params->pdc_xfer_size);
  150. DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
  151. (unsigned long) prtd->period_ptr,
  152. at91_ssc_read(params->ssc_base + params->pdc->xpr),
  153. at91_ssc_read(params->ssc_base + params->pdc->xcr),
  154. at91_ssc_read(params->ssc_base + params->pdc->xnpr),
  155. at91_ssc_read(params->ssc_base + params->pdc->xncr));
  156. at91_ssc_write(params->ssc_base + AT91_SSC_IER,
  157. params->mask->ssc_endx | params->mask->ssc_endbuf);
  158. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR,
  159. params->mask->pdc_enable);
  160. DBG("sr=%lx imr=%lx\n",
  161. at91_ssc_read(params->ssc_base + AT91_SSC_SR),
  162. at91_ssc_read(params->ssc_base + AT91_SSC_IMR));
  163. break;
  164. case SNDRV_PCM_TRIGGER_STOP:
  165. case SNDRV_PCM_TRIGGER_SUSPEND:
  166. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  167. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  168. break;
  169. case SNDRV_PCM_TRIGGER_RESUME:
  170. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  171. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  172. break;
  173. default:
  174. ret = -EINVAL;
  175. }
  176. return ret;
  177. }
  178. static snd_pcm_uframes_t at91_pcm_pointer(
  179. struct snd_pcm_substream *substream)
  180. {
  181. struct snd_pcm_runtime *runtime = substream->runtime;
  182. struct at91_runtime_data *prtd = runtime->private_data;
  183. struct at91_pcm_dma_params *params = prtd->params;
  184. dma_addr_t ptr;
  185. snd_pcm_uframes_t x;
  186. ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
  187. x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
  188. if (x == runtime->buffer_size)
  189. x = 0;
  190. return x;
  191. }
  192. static int at91_pcm_open(struct snd_pcm_substream *substream)
  193. {
  194. struct snd_pcm_runtime *runtime = substream->runtime;
  195. struct at91_runtime_data *prtd;
  196. int ret = 0;
  197. snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
  198. /* ensure that buffer size is a multiple of period size */
  199. ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
  200. if (ret < 0)
  201. goto out;
  202. prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
  203. if (prtd == NULL) {
  204. ret = -ENOMEM;
  205. goto out;
  206. }
  207. runtime->private_data = prtd;
  208. out:
  209. return ret;
  210. }
  211. static int at91_pcm_close(struct snd_pcm_substream *substream)
  212. {
  213. struct at91_runtime_data *prtd = substream->runtime->private_data;
  214. kfree(prtd);
  215. return 0;
  216. }
  217. static int at91_pcm_mmap(struct snd_pcm_substream *substream,
  218. struct vm_area_struct *vma)
  219. {
  220. struct snd_pcm_runtime *runtime = substream->runtime;
  221. return dma_mmap_writecombine(substream->pcm->card->dev, vma,
  222. runtime->dma_area,
  223. runtime->dma_addr,
  224. runtime->dma_bytes);
  225. }
  226. struct snd_pcm_ops at91_pcm_ops = {
  227. .open = at91_pcm_open,
  228. .close = at91_pcm_close,
  229. .ioctl = snd_pcm_lib_ioctl,
  230. .hw_params = at91_pcm_hw_params,
  231. .hw_free = at91_pcm_hw_free,
  232. .prepare = at91_pcm_prepare,
  233. .trigger = at91_pcm_trigger,
  234. .pointer = at91_pcm_pointer,
  235. .mmap = at91_pcm_mmap,
  236. };
  237. static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
  238. int stream)
  239. {
  240. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  241. struct snd_dma_buffer *buf = &substream->dma_buffer;
  242. size_t size = at91_pcm_hardware.buffer_bytes_max;
  243. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  244. buf->dev.dev = pcm->card->dev;
  245. buf->private_data = NULL;
  246. buf->area = dma_alloc_writecombine(pcm->card->dev, size,
  247. &buf->addr, GFP_KERNEL);
  248. DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
  249. (void *) buf->area,
  250. (void *) buf->addr,
  251. size);
  252. if (!buf->area)
  253. return -ENOMEM;
  254. buf->bytes = size;
  255. return 0;
  256. }
  257. static u64 at91_pcm_dmamask = 0xffffffff;
  258. static int at91_pcm_new(struct snd_card *card,
  259. struct snd_soc_dai *dai, struct snd_pcm *pcm)
  260. {
  261. int ret = 0;
  262. if (!card->dev->dma_mask)
  263. card->dev->dma_mask = &at91_pcm_dmamask;
  264. if (!card->dev->coherent_dma_mask)
  265. card->dev->coherent_dma_mask = 0xffffffff;
  266. if (dai->playback.channels_min) {
  267. ret = at91_pcm_preallocate_dma_buffer(pcm,
  268. SNDRV_PCM_STREAM_PLAYBACK);
  269. if (ret)
  270. goto out;
  271. }
  272. if (dai->capture.channels_min) {
  273. ret = at91_pcm_preallocate_dma_buffer(pcm,
  274. SNDRV_PCM_STREAM_CAPTURE);
  275. if (ret)
  276. goto out;
  277. }
  278. out:
  279. return ret;
  280. }
  281. static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
  282. {
  283. struct snd_pcm_substream *substream;
  284. struct snd_dma_buffer *buf;
  285. int stream;
  286. for (stream = 0; stream < 2; stream++) {
  287. substream = pcm->streams[stream].substream;
  288. if (!substream)
  289. continue;
  290. buf = &substream->dma_buffer;
  291. if (!buf->area)
  292. continue;
  293. dma_free_writecombine(pcm->card->dev, buf->bytes,
  294. buf->area, buf->addr);
  295. buf->area = NULL;
  296. }
  297. }
  298. #ifdef CONFIG_PM
  299. static int at91_pcm_suspend(struct platform_device *pdev,
  300. struct snd_soc_dai *dai)
  301. {
  302. struct snd_pcm_runtime *runtime = dai->runtime;
  303. struct at91_runtime_data *prtd;
  304. struct at91_pcm_dma_params *params;
  305. if (!runtime)
  306. return 0;
  307. prtd = runtime->private_data;
  308. params = prtd->params;
  309. /* disable the PDC and save the PDC registers */
  310. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  311. prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr);
  312. prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr);
  313. prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
  314. prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
  315. return 0;
  316. }
  317. static int at91_pcm_resume(struct platform_device *pdev,
  318. struct snd_soc_dai *dai)
  319. {
  320. struct snd_pcm_runtime *runtime = dai->runtime;
  321. struct at91_runtime_data *prtd;
  322. struct at91_pcm_dma_params *params;
  323. if (!runtime)
  324. return 0;
  325. prtd = runtime->private_data;
  326. params = prtd->params;
  327. /* restore the PDC registers and enable the PDC */
  328. at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save);
  329. at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save);
  330. at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
  331. at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
  332. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  333. return 0;
  334. }
  335. #else
  336. #define at91_pcm_suspend NULL
  337. #define at91_pcm_resume NULL
  338. #endif
  339. struct snd_soc_platform at91_soc_platform = {
  340. .name = "at91-audio",
  341. .pcm_ops = &at91_pcm_ops,
  342. .pcm_new = at91_pcm_new,
  343. .pcm_free = at91_pcm_free_dma_buffers,
  344. .suspend = at91_pcm_suspend,
  345. .resume = at91_pcm_resume,
  346. };
  347. EXPORT_SYMBOL_GPL(at91_soc_platform);
  348. MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
  349. MODULE_DESCRIPTION("Atmel AT91 PCM module");
  350. MODULE_LICENSE("GPL");