Commit | Line | Data |
---|---|---|
f11a96d5 LG |
1 | /* |
2 | * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip | |
3 | * | |
4 | * Author: Nicolas Pitre | |
5 | * Created: Nov 30, 2004 | |
6 | * Copyright: (C) 2004 MontaVista Software, Inc. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
f11a96d5 LG |
13 | #include <linux/dma-mapping.h> |
14 | ||
f11a96d5 | 15 | #include <sound/core.h> |
f11a96d5 | 16 | #include <sound/soc.h> |
a6d77317 | 17 | #include <sound/pxa2xx-lib.h> |
f11a96d5 LG |
18 | |
19 | #include "pxa2xx-pcm.h" | |
a6d77317 | 20 | #include "../../arm/pxa2xx-pcm.h" |
f11a96d5 LG |
21 | |
22 | static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |
23 | struct snd_pcm_hw_params *params) | |
24 | { | |
25 | struct snd_pcm_runtime *runtime = substream->runtime; | |
26 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | |
27 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
a8f5d0a5 | 28 | struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; |
f11a96d5 LG |
29 | int ret; |
30 | ||
a8f5d0a5 AJ |
31 | /* return if this is a bufferless transfer e.g. |
32 | * codec <--> BT codec or GSM modem -- lg FIXME */ | |
b32432e3 MB |
33 | if (!dma) |
34 | return 0; | |
a8f5d0a5 | 35 | |
f11a96d5 LG |
36 | /* this may get called several times by oss emulation |
37 | * with different params */ | |
38 | if (prtd->params == NULL) { | |
39 | prtd->params = dma; | |
40 | ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, | |
41 | pxa2xx_pcm_dma_irq, substream); | |
42 | if (ret < 0) | |
43 | return ret; | |
44 | prtd->dma_ch = ret; | |
45 | } else if (prtd->params != dma) { | |
46 | pxa_free_dma(prtd->dma_ch); | |
47 | prtd->params = dma; | |
48 | ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW, | |
49 | pxa2xx_pcm_dma_irq, substream); | |
50 | if (ret < 0) | |
51 | return ret; | |
52 | prtd->dma_ch = ret; | |
53 | } | |
54 | ||
a6d77317 | 55 | return __pxa2xx_pcm_hw_params(substream, params); |
f11a96d5 LG |
56 | } |
57 | ||
58 | static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | |
59 | { | |
60 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | |
61 | ||
a6d77317 | 62 | __pxa2xx_pcm_hw_free(substream); |
f11a96d5 LG |
63 | |
64 | if (prtd->dma_ch) { | |
f11a96d5 LG |
65 | pxa_free_dma(prtd->dma_ch); |
66 | prtd->dma_ch = 0; | |
67 | } | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
0e734ad5 | 72 | static struct snd_pcm_ops pxa2xx_pcm_ops = { |
a6d77317 DB |
73 | .open = __pxa2xx_pcm_open, |
74 | .close = __pxa2xx_pcm_close, | |
f11a96d5 LG |
75 | .ioctl = snd_pcm_lib_ioctl, |
76 | .hw_params = pxa2xx_pcm_hw_params, | |
77 | .hw_free = pxa2xx_pcm_hw_free, | |
a6d77317 | 78 | .prepare = __pxa2xx_pcm_prepare, |
f11a96d5 LG |
79 | .trigger = pxa2xx_pcm_trigger, |
80 | .pointer = pxa2xx_pcm_pointer, | |
81 | .mmap = pxa2xx_pcm_mmap, | |
82 | }; | |
83 | ||
f11a96d5 LG |
84 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; |
85 | ||
8a33de9e | 86 | static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
f11a96d5 LG |
87 | struct snd_pcm *pcm) |
88 | { | |
89 | int ret = 0; | |
90 | ||
91 | if (!card->dev->dma_mask) | |
92 | card->dev->dma_mask = &pxa2xx_pcm_dmamask; | |
93 | if (!card->dev->coherent_dma_mask) | |
94 | card->dev->coherent_dma_mask = DMA_32BIT_MASK; | |
95 | ||
96 | if (dai->playback.channels_min) { | |
97 | ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, | |
98 | SNDRV_PCM_STREAM_PLAYBACK); | |
99 | if (ret) | |
100 | goto out; | |
101 | } | |
102 | ||
103 | if (dai->capture.channels_min) { | |
104 | ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, | |
105 | SNDRV_PCM_STREAM_CAPTURE); | |
106 | if (ret) | |
107 | goto out; | |
108 | } | |
109 | out: | |
110 | return ret; | |
111 | } | |
112 | ||
113 | struct snd_soc_platform pxa2xx_soc_platform = { | |
114 | .name = "pxa2xx-audio", | |
115 | .pcm_ops = &pxa2xx_pcm_ops, | |
8a33de9e | 116 | .pcm_new = pxa2xx_soc_pcm_new, |
f11a96d5 LG |
117 | .pcm_free = pxa2xx_pcm_free_dma_buffers, |
118 | }; | |
f11a96d5 LG |
119 | EXPORT_SYMBOL_GPL(pxa2xx_soc_platform); |
120 | ||
c9b3a40f | 121 | static int __init pxa2xx_soc_platform_init(void) |
958e792c MB |
122 | { |
123 | return snd_soc_register_platform(&pxa2xx_soc_platform); | |
124 | } | |
125 | module_init(pxa2xx_soc_platform_init); | |
126 | ||
127 | static void __exit pxa2xx_soc_platform_exit(void) | |
128 | { | |
129 | snd_soc_unregister_platform(&pxa2xx_soc_platform); | |
130 | } | |
131 | module_exit(pxa2xx_soc_platform_exit); | |
132 | ||
f11a96d5 LG |
133 | MODULE_AUTHOR("Nicolas Pitre"); |
134 | MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); | |
135 | MODULE_LICENSE("GPL"); |