at32-pcm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /* sound/soc/at32/at32-pcm.c
  2. * ASoC PCM interface for Atmel AT32 SoC
  3. *
  4. * Copyright (C) 2008 Long Range Systems
  5. * Geoffrey Wossum <gwossum@acm.org>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * Note that this is basically a port of the sound/soc/at91-pcm.c to
  12. * the AVR32 kernel. Thanks to Frank Mandarino for that code.
  13. */
  14. #include <linux/module.h>
  15. #include <linux/init.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/slab.h>
  18. #include <linux/dma-mapping.h>
  19. #include <linux/atmel_pdc.h>
  20. #include <sound/core.h>
  21. #include <sound/pcm.h>
  22. #include <sound/pcm_params.h>
  23. #include <sound/soc.h>
  24. #include "at32-pcm.h"
  25. /*--------------------------------------------------------------------------*\
  26. * Hardware definition
  27. \*--------------------------------------------------------------------------*/
  28. /* TODO: These values were taken from the AT91 platform driver, check
  29. * them against real values for AT32
  30. */
  31. static const struct snd_pcm_hardware at32_pcm_hardware = {
  32. .info = (SNDRV_PCM_INFO_MMAP |
  33. SNDRV_PCM_INFO_MMAP_VALID |
  34. SNDRV_PCM_INFO_INTERLEAVED |
  35. SNDRV_PCM_INFO_BLOCK_TRANSFER |
  36. SNDRV_PCM_INFO_PAUSE),
  37. .formats = SNDRV_PCM_FMTBIT_S16,
  38. .period_bytes_min = 32,
  39. .period_bytes_max = 8192, /* 512 frames * 16 bytes / frame */
  40. .periods_min = 2,
  41. .periods_max = 1024,
  42. .buffer_bytes_max = 32 * 1024,
  43. };
  44. /*--------------------------------------------------------------------------*\
  45. * Data types
  46. \*--------------------------------------------------------------------------*/
  47. struct at32_runtime_data {
  48. struct at32_pcm_dma_params *params;
  49. dma_addr_t dma_buffer; /* physical address of DMA buffer */
  50. dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
  51. size_t period_size;
  52. dma_addr_t period_ptr; /* physical address of next period */
  53. int periods; /* period index of period_ptr */
  54. /* Save PDC registers (for power management) */
  55. u32 pdc_xpr_save;
  56. u32 pdc_xcr_save;
  57. u32 pdc_xnpr_save;
  58. u32 pdc_xncr_save;
  59. };
  60. /*--------------------------------------------------------------------------*\
  61. * Helper functions
  62. \*--------------------------------------------------------------------------*/
  63. static int at32_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  64. {
  65. struct snd_pcm_substream *substream = pcm->streams[stream].substream;
  66. struct snd_dma_buffer *dmabuf = &substream->dma_buffer;
  67. size_t size = at32_pcm_hardware.buffer_bytes_max;
  68. dmabuf->dev.type = SNDRV_DMA_TYPE_DEV;
  69. dmabuf->dev.dev = pcm->card->dev;
  70. dmabuf->private_data = NULL;
  71. dmabuf->area = dma_alloc_coherent(pcm->card->dev, size,
  72. &dmabuf->addr, GFP_KERNEL);
  73. pr_debug("at32_pcm: preallocate_dma_buffer: "
  74. "area=%p, addr=%p, size=%ld\n",
  75. (void *)dmabuf->area, (void *)dmabuf->addr, size);
  76. if (!dmabuf->area)
  77. return -ENOMEM;
  78. dmabuf->bytes = size;
  79. return 0;
  80. }
  81. /*--------------------------------------------------------------------------*\
  82. * ISR
  83. \*--------------------------------------------------------------------------*/
  84. static void at32_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream)
  85. {
  86. struct snd_pcm_runtime *rtd = substream->runtime;
  87. struct at32_runtime_data *prtd = rtd->private_data;
  88. struct at32_pcm_dma_params *params = prtd->params;
  89. static int count;
  90. count++;
  91. if (ssc_sr & params->mask->ssc_endbuf) {
  92. pr_warning("at32-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
  93. substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
  94. "underrun" : "overrun", params->name, ssc_sr, count);
  95. /* re-start the PDC */
  96. ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
  97. params->mask->pdc_disable);
  98. prtd->period_ptr += prtd->period_size;
  99. if (prtd->period_ptr >= prtd->dma_buffer_end)
  100. prtd->period_ptr = prtd->dma_buffer;
  101. ssc_writex(params->ssc->regs, params->pdc->xpr,
  102. prtd->period_ptr);
  103. ssc_writex(params->ssc->regs, params->pdc->xcr,
  104. prtd->period_size / params->pdc_xfer_size);
  105. ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
  106. params->mask->pdc_enable);
  107. }
  108. if (ssc_sr & params->mask->ssc_endx) {
  109. /* Load the PDC next pointer and counter registers */
  110. prtd->period_ptr += prtd->period_size;
  111. if (prtd->period_ptr >= prtd->dma_buffer_end)
  112. prtd->period_ptr = prtd->dma_buffer;
  113. ssc_writex(params->ssc->regs, params->pdc->xnpr,
  114. prtd->period_ptr);
  115. ssc_writex(params->ssc->regs, params->pdc->xncr,
  116. prtd->period_size / params->pdc_xfer_size);
  117. }
  118. snd_pcm_period_elapsed(substream);
  119. }
  120. /*--------------------------------------------------------------------------*\
  121. * PCM operations
  122. \*--------------------------------------------------------------------------*/
  123. static int at32_pcm_hw_params(struct snd_pcm_substream *substream,
  124. struct snd_pcm_hw_params *params)
  125. {
  126. struct snd_pcm_runtime *runtime = substream->runtime;
  127. struct at32_runtime_data *prtd = runtime->private_data;
  128. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  129. /* this may get called several times by oss emulation
  130. * with different params
  131. */
  132. snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  133. runtime->dma_bytes = params_buffer_bytes(params);
  134. prtd->params = rtd->dai->cpu_dai->dma_data;
  135. prtd->params->dma_intr_handler = at32_pcm_dma_irq;
  136. prtd->dma_buffer = runtime->dma_addr;
  137. prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
  138. prtd->period_size = params_period_bytes(params);
  139. pr_debug("hw_params: DMA for %s initialized "
  140. "(dma_bytes=%ld, period_size=%ld)\n",
  141. prtd->params->name, runtime->dma_bytes, prtd->period_size);
  142. return 0;
  143. }
  144. static int at32_pcm_hw_free(struct snd_pcm_substream *substream)
  145. {
  146. struct at32_runtime_data *prtd = substream->runtime->private_data;
  147. struct at32_pcm_dma_params *params = prtd->params;
  148. if (params != NULL) {
  149. ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
  150. params->mask->pdc_disable);
  151. prtd->params->dma_intr_handler = NULL;
  152. }
  153. return 0;
  154. }
  155. static int at32_pcm_prepare(struct snd_pcm_substream *substream)
  156. {
  157. struct at32_runtime_data *prtd = substream->runtime->private_data;
  158. struct at32_pcm_dma_params *params = prtd->params;
  159. ssc_writex(params->ssc->regs, SSC_IDR,
  160. params->mask->ssc_endx | params->mask->ssc_endbuf);
  161. ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
  162. params->mask->pdc_disable);
  163. return 0;
  164. }
  165. static int at32_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  166. {
  167. struct snd_pcm_runtime *rtd = substream->runtime;
  168. struct at32_runtime_data *prtd = rtd->private_data;
  169. struct at32_pcm_dma_params *params = prtd->params;
  170. int ret = 0;
  171. pr_debug("at32_pcm_trigger: buffer_size = %ld, "
  172. "dma_area = %p, dma_bytes = %ld\n",
  173. rtd->buffer_size, rtd->dma_area, rtd->dma_bytes);
  174. switch (cmd) {
  175. case SNDRV_PCM_TRIGGER_START:
  176. prtd->period_ptr = prtd->dma_buffer;
  177. ssc_writex(params->ssc->regs, params->pdc->xpr,
  178. prtd->period_ptr);
  179. ssc_writex(params->ssc->regs, params->pdc->xcr,
  180. prtd->period_size / params->pdc_xfer_size);
  181. prtd->period_ptr += prtd->period_size;
  182. ssc_writex(params->ssc->regs, params->pdc->xnpr,
  183. prtd->period_ptr);
  184. ssc_writex(params->ssc->regs, params->pdc->xncr,
  185. prtd->period_size / params->pdc_xfer_size);
  186. pr_debug("trigger: period_ptr=%lx, xpr=%x, "
  187. "xcr=%d, xnpr=%x, xncr=%d\n",
  188. (unsigned long)prtd->period_ptr,
  189. ssc_readx(params->ssc->regs, params->pdc->xpr),
  190. ssc_readx(params->ssc->regs, params->pdc->xcr),
  191. ssc_readx(params->ssc->regs, params->pdc->xnpr),
  192. ssc_readx(params->ssc->regs, params->pdc->xncr));
  193. ssc_writex(params->ssc->regs, SSC_IER,
  194. params->mask->ssc_endx | params->mask->ssc_endbuf);
  195. ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
  196. params->mask->pdc_enable);
  197. pr_debug("sr=%x, imr=%x\n",
  198. ssc_readx(params->ssc->regs, SSC_SR),
  199. ssc_readx(params->ssc->regs, SSC_IER));
  200. break; /* SNDRV_PCM_TRIGGER_START */
  201. case SNDRV_PCM_TRIGGER_STOP:
  202. case SNDRV_PCM_TRIGGER_SUSPEND:
  203. case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  204. ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
  205. params->mask->pdc_disable);
  206. break;
  207. case SNDRV_PCM_TRIGGER_RESUME:
  208. case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  209. ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
  210. params->mask->pdc_enable);
  211. break;
  212. default:
  213. ret = -EINVAL;
  214. }
  215. return ret;
  216. }
  217. static snd_pcm_uframes_t at32_pcm_pointer(struct snd_pcm_substream *substream)
  218. {
  219. struct snd_pcm_runtime *runtime = substream->runtime;
  220. struct at32_runtime_data *prtd = runtime->private_data;
  221. struct at32_pcm_dma_params *params = prtd->params;
  222. dma_addr_t ptr;
  223. snd_pcm_uframes_t x;
  224. ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr);
  225. x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
  226. if (x == runtime->buffer_size)
  227. x = 0;
  228. return x;
  229. }
  230. static int at32_pcm_open(struct snd_pcm_substream *substream)
  231. {
  232. struct snd_pcm_runtime *runtime = substream->runtime;
  233. struct at32_runtime_data *prtd;
  234. int ret = 0;
  235. snd_soc_set_runtime_hwparams(substream, &at32_pcm_hardware);
  236. /* ensure that buffer size is a multiple of period size */
  237. ret = snd_pcm_hw_constraint_integer(runtime,
  238. SNDRV_PCM_HW_PARAM_PERIODS);
  239. if (ret < 0)
  240. goto out;
  241. prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
  242. if (prtd == NULL) {
  243. ret = -ENOMEM;
  244. goto out;
  245. }
  246. runtime->private_data = prtd;
  247. out:
  248. return ret;
  249. }
  250. static int at32_pcm_close(struct snd_pcm_substream *substream)
  251. {
  252. struct at32_runtime_data *prtd = substream->runtime->private_data;
  253. kfree(prtd);
  254. return 0;
  255. }
  256. static int at32_pcm_mmap(struct snd_pcm_substream *substream,
  257. struct vm_area_struct *vma)
  258. {
  259. return remap_pfn_range(vma, vma->vm_start,
  260. substream->dma_buffer.addr >> PAGE_SHIFT,
  261. vma->vm_end - vma->vm_start, vma->vm_page_prot);
  262. }
  263. static struct snd_pcm_ops at32_pcm_ops = {
  264. .open = at32_pcm_open,
  265. .close = at32_pcm_close,
  266. .ioctl = snd_pcm_lib_ioctl,
  267. .hw_params = at32_pcm_hw_params,
  268. .hw_free = at32_pcm_hw_free,
  269. .prepare = at32_pcm_prepare,
  270. .trigger = at32_pcm_trigger,
  271. .pointer = at32_pcm_pointer,
  272. .mmap = at32_pcm_mmap,
  273. };
  274. /*--------------------------------------------------------------------------*\
  275. * ASoC platform driver
  276. \*--------------------------------------------------------------------------*/
  277. static u64 at32_pcm_dmamask = 0xffffffff;
  278. static int at32_pcm_new(struct snd_card *card,
  279. struct snd_soc_dai *dai,
  280. struct snd_pcm *pcm)
  281. {
  282. int ret = 0;
  283. if (!card->dev->dma_mask)
  284. card->dev->dma_mask = &at32_pcm_dmamask;
  285. if (!card->dev->coherent_dma_mask)
  286. card->dev->coherent_dma_mask = 0xffffffff;
  287. if (dai->playback.channels_min) {
  288. ret = at32_pcm_preallocate_dma_buffer(
  289. pcm, SNDRV_PCM_STREAM_PLAYBACK);
  290. if (ret)
  291. goto out;
  292. }
  293. if (dai->capture.channels_min) {
  294. pr_debug("at32-pcm: Allocating PCM capture DMA buffer\n");
  295. ret = at32_pcm_preallocate_dma_buffer(
  296. pcm, SNDRV_PCM_STREAM_CAPTURE);
  297. if (ret)
  298. goto out;
  299. }
  300. out:
  301. return ret;
  302. }
  303. static void at32_pcm_free_dma_buffers(struct snd_pcm *pcm)
  304. {
  305. struct snd_pcm_substream *substream;
  306. struct snd_dma_buffer *buf;
  307. int stream;
  308. for (stream = 0; stream < 2; stream++) {
  309. substream = pcm->streams[stream].substream;
  310. if (substream == NULL)
  311. continue;
  312. buf = &substream->dma_buffer;
  313. if (!buf->area)
  314. continue;
  315. dma_free_coherent(pcm->card->dev, buf->bytes,
  316. buf->area, buf->addr);
  317. buf->area = NULL;
  318. }
  319. }
  320. #ifdef CONFIG_PM
  321. static int at32_pcm_suspend(struct platform_device *pdev,
  322. struct snd_soc_dai *dai)
  323. {
  324. struct snd_pcm_runtime *runtime = dai->runtime;
  325. struct at32_runtime_data *prtd;
  326. struct at32_pcm_dma_params *params;
  327. if (runtime == NULL)
  328. return 0;
  329. prtd = runtime->private_data;
  330. params = prtd->params;
  331. /* Disable the PDC and save the PDC registers */
  332. ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
  333. params->mask->pdc_disable);
  334. prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
  335. prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
  336. prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr);
  337. prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr);
  338. return 0;
  339. }
  340. static int at32_pcm_resume(struct platform_device *pdev,
  341. struct snd_soc_dai *dai)
  342. {
  343. struct snd_pcm_runtime *runtime = dai->runtime;
  344. struct at32_runtime_data *prtd;
  345. struct at32_pcm_dma_params *params;
  346. if (runtime == NULL)
  347. return 0;
  348. prtd = runtime->private_data;
  349. params = prtd->params;
  350. /* Restore the PDC registers and enable the PDC */
  351. ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save);
  352. ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
  353. ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
  354. ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
  355. ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, params->mask->pdc_enable);
  356. return 0;
  357. }
  358. #else /* CONFIG_PM */
  359. # define at32_pcm_suspend NULL
  360. # define at32_pcm_resume NULL
  361. #endif /* CONFIG_PM */
  362. struct snd_soc_platform at32_soc_platform = {
  363. .name = "at32-audio",
  364. .pcm_ops = &at32_pcm_ops,
  365. .pcm_new = at32_pcm_new,
  366. .pcm_free = at32_pcm_free_dma_buffers,
  367. .suspend = at32_pcm_suspend,
  368. .resume = at32_pcm_resume,
  369. };
  370. EXPORT_SYMBOL_GPL(at32_soc_platform);
  371. MODULE_AUTHOR("Geoffrey Wossum <gwossum@acm.org>");
  372. MODULE_DESCRIPTION("Atmel AT32 PCM module");
  373. MODULE_LICENSE("GPL");