at91-pcm.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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/driver.h>
  25. #include <sound/core.h>
  26. #include <sound/pcm.h>
  27. #include <sound/pcm_params.h>
  28. #include <sound/soc.h>
  29. #include <asm/arch/hardware.h>
  30. #include <asm/arch/at91_ssc.h>
  31. #include "at91-pcm.h"
  32. #if 0
  33. #define DBG(x...) printk(KERN_INFO "at91-pcm: " x)
  34. #else
  35. #define DBG(x...)
  36. #endif
  37. static const struct snd_pcm_hardware at91_pcm_hardware = {
  38. .info = SNDRV_PCM_INFO_MMAP |
  39. SNDRV_PCM_INFO_MMAP_VALID |
  40. SNDRV_PCM_INFO_INTERLEAVED |
  41. SNDRV_PCM_INFO_PAUSE,
  42. .formats = SNDRV_PCM_FMTBIT_S16_LE,
  43. .period_bytes_min = 32,
  44. .period_bytes_max = 8192,
  45. .periods_min = 2,
  46. .periods_max = 1024,
  47. .buffer_bytes_max = 32 * 1024,
  48. };
  49. struct at91_runtime_data {
  50. struct at91_pcm_dma_params *params;
  51. dma_addr_t dma_buffer; /* physical address of dma buffer */
  52. dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
  53. size_t period_size;
  54. dma_addr_t period_ptr; /* physical address of next period */
  55. u32 pdc_xpr_save; /* PDC register save */
  56. u32 pdc_xcr_save;
  57. u32 pdc_xnpr_save;
  58. u32 pdc_xncr_save;
  59. };
  60. static void at91_pcm_dma_irq(u32 ssc_sr,
  61. struct snd_pcm_substream *substream)
  62. {
  63. struct at91_runtime_data *prtd = substream->runtime->private_data;
  64. struct at91_pcm_dma_params *params = prtd->params;
  65. static int count = 0;
  66. count++;
  67. if (ssc_sr & params->mask->ssc_endbuf) {
  68. printk(KERN_WARNING
  69. "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
  70. substream->stream == SNDRV_PCM_STREAM_PLAYBACK
  71. ? "underrun" : "overrun",
  72. params->name, ssc_sr, count);
  73. /* re-start the PDC */
  74. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  75. prtd->period_ptr += prtd->period_size;
  76. if (prtd->period_ptr >= prtd->dma_buffer_end) {
  77. prtd->period_ptr = prtd->dma_buffer;
  78. }
  79. at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
  80. at91_ssc_write(params->ssc_base + params->pdc->xcr,
  81. prtd->period_size / params->pdc_xfer_size);
  82. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  83. }
  84. if (ssc_sr & params->mask->ssc_endx) {
  85. /* Load the PDC next pointer and counter registers */
  86. prtd->period_ptr += prtd->period_size;
  87. if (prtd->period_ptr >= prtd->dma_buffer_end) {
  88. prtd->period_ptr = prtd->dma_buffer;
  89. }
  90. at91_ssc_write(params->ssc_base + params->pdc->xnpr, 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, params->mask->pdc_enable);
  159. DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR),
  160. at91_ssc_read(params->ssc_base + AT91_SSC_IER));
  161. break;
  162. case SNDRV_PCM_TRIGGER_STOP:
  163. case SNDRV_PCM_TRIGGER_SUSPEND:
  164. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  165. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  166. break;
  167. case SNDRV_PCM_TRIGGER_RESUME:
  168. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  169. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  170. break;
  171. default:
  172. ret = -EINVAL;
  173. }
  174. return ret;
  175. }
  176. static snd_pcm_uframes_t at91_pcm_pointer(
  177. struct snd_pcm_substream *substream)
  178. {
  179. struct snd_pcm_runtime *runtime = substream->runtime;
  180. struct at91_runtime_data *prtd = runtime->private_data;
  181. struct at91_pcm_dma_params *params = prtd->params;
  182. dma_addr_t ptr;
  183. snd_pcm_uframes_t x;
  184. ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
  185. x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
  186. if (x == runtime->buffer_size)
  187. x = 0;
  188. return x;
  189. }
  190. static int at91_pcm_open(struct snd_pcm_substream *substream)
  191. {
  192. struct snd_pcm_runtime *runtime = substream->runtime;
  193. struct at91_runtime_data *prtd;
  194. int ret = 0;
  195. snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
  196. /* ensure that buffer size is a multiple of period size */
  197. ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
  198. if (ret < 0)
  199. goto out;
  200. prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
  201. if (prtd == NULL) {
  202. ret = -ENOMEM;
  203. goto out;
  204. }
  205. runtime->private_data = prtd;
  206. out:
  207. return ret;
  208. }
  209. static int at91_pcm_close(struct snd_pcm_substream *substream)
  210. {
  211. struct at91_runtime_data *prtd = substream->runtime->private_data;
  212. kfree(prtd);
  213. return 0;
  214. }
  215. static int at91_pcm_mmap(struct snd_pcm_substream *substream,
  216. struct vm_area_struct *vma)
  217. {
  218. struct snd_pcm_runtime *runtime = substream->runtime;
  219. return dma_mmap_writecombine(substream->pcm->card->dev, vma,
  220. runtime->dma_area,
  221. runtime->dma_addr,
  222. runtime->dma_bytes);
  223. }
  224. struct snd_pcm_ops at91_pcm_ops = {
  225. .open = at91_pcm_open,
  226. .close = at91_pcm_close,
  227. .ioctl = snd_pcm_lib_ioctl,
  228. .hw_params = at91_pcm_hw_params,
  229. .hw_free = at91_pcm_hw_free,
  230. .prepare = at91_pcm_prepare,
  231. .trigger = at91_pcm_trigger,
  232. .pointer = at91_pcm_pointer,
  233. .mmap = at91_pcm_mmap,
  234. };
  235. static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
  236. int stream)
  237. {
  238. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  239. struct snd_dma_buffer *buf = &substream->dma_buffer;
  240. size_t size = at91_pcm_hardware.buffer_bytes_max;
  241. buf->dev.type = SNDRV_DMA_TYPE_DEV;
  242. buf->dev.dev = pcm->card->dev;
  243. buf->private_data = NULL;
  244. buf->area = dma_alloc_writecombine(pcm->card->dev, size,
  245. &buf->addr, GFP_KERNEL);
  246. DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
  247. (void *) buf->area,
  248. (void *) buf->addr,
  249. size);
  250. if (!buf->area)
  251. return -ENOMEM;
  252. buf->bytes = size;
  253. return 0;
  254. }
  255. static u64 at91_pcm_dmamask = 0xffffffff;
  256. static int at91_pcm_new(struct snd_card *card,
  257. struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
  258. {
  259. int ret = 0;
  260. if (!card->dev->dma_mask)
  261. card->dev->dma_mask = &at91_pcm_dmamask;
  262. if (!card->dev->coherent_dma_mask)
  263. card->dev->coherent_dma_mask = 0xffffffff;
  264. if (dai->playback.channels_min) {
  265. ret = at91_pcm_preallocate_dma_buffer(pcm,
  266. SNDRV_PCM_STREAM_PLAYBACK);
  267. if (ret)
  268. goto out;
  269. }
  270. if (dai->capture.channels_min) {
  271. ret = at91_pcm_preallocate_dma_buffer(pcm,
  272. SNDRV_PCM_STREAM_CAPTURE);
  273. if (ret)
  274. goto out;
  275. }
  276. out:
  277. return ret;
  278. }
  279. static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
  280. {
  281. struct snd_pcm_substream *substream;
  282. struct snd_dma_buffer *buf;
  283. int stream;
  284. for (stream = 0; stream < 2; stream++) {
  285. substream = pcm->streams[stream].substream;
  286. if (!substream)
  287. continue;
  288. buf = &substream->dma_buffer;
  289. if (!buf->area)
  290. continue;
  291. dma_free_writecombine(pcm->card->dev, buf->bytes,
  292. buf->area, buf->addr);
  293. buf->area = NULL;
  294. }
  295. }
  296. #ifdef CONFIG_PM
  297. static int at91_pcm_suspend(struct platform_device *pdev,
  298. struct snd_soc_cpu_dai *dai)
  299. {
  300. struct snd_pcm_runtime *runtime = dai->runtime;
  301. struct at91_runtime_data *prtd;
  302. struct at91_pcm_dma_params *params;
  303. if (!runtime)
  304. return 0;
  305. prtd = runtime->private_data;
  306. params = prtd->params;
  307. /* disable the PDC and save the PDC registers */
  308. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
  309. prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr);
  310. prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr);
  311. prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
  312. prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
  313. return 0;
  314. }
  315. static int at91_pcm_resume(struct platform_device *pdev,
  316. struct snd_soc_cpu_dai *dai)
  317. {
  318. struct snd_pcm_runtime *runtime = dai->runtime;
  319. struct at91_runtime_data *prtd;
  320. struct at91_pcm_dma_params *params;
  321. if (!runtime)
  322. return 0;
  323. prtd = runtime->private_data;
  324. params = prtd->params;
  325. /* restore the PDC registers and enable the PDC */
  326. at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save);
  327. at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save);
  328. at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
  329. at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
  330. at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
  331. return 0;
  332. }
  333. #else
  334. #define at91_pcm_suspend NULL
  335. #define at91_pcm_resume NULL
  336. #endif
  337. struct snd_soc_platform at91_soc_platform = {
  338. .name = "at91-audio",
  339. .pcm_ops = &at91_pcm_ops,
  340. .pcm_new = at91_pcm_new,
  341. .pcm_free = at91_pcm_free_dma_buffers,
  342. .suspend = at91_pcm_suspend,
  343. .resume = at91_pcm_resume,
  344. };
  345. EXPORT_SYMBOL_GPL(at91_soc_platform);
  346. MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
  347. MODULE_DESCRIPTION("Atmel AT91 PCM module");
  348. MODULE_LICENSE("GPL");