diff options
-rw-r--r-- | include/sound/pxa2xx-lib.h | 25 | ||||
-rw-r--r-- | sound/arm/Kconfig | 6 | ||||
-rw-r--r-- | sound/arm/Makefile | 3 | ||||
-rw-r--r-- | sound/arm/pxa2xx-pcm-lib.c | 278 | ||||
-rw-r--r-- | sound/arm/pxa2xx-pcm.c | 252 | ||||
-rw-r--r-- | sound/arm/pxa2xx-pcm.h | 13 | ||||
-rw-r--r-- | sound/soc/pxa/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/pxa/pxa2xx-i2s.c | 10 | ||||
-rw-r--r-- | sound/soc/pxa/pxa2xx-pcm.c | 261 | ||||
-rw-r--r-- | sound/soc/pxa/pxa2xx-pcm.h | 15 |
10 files changed, 344 insertions, 522 deletions
diff --git a/include/sound/pxa2xx-lib.h b/include/sound/pxa2xx-lib.h index d18dd2d35978..2fd3d251d9a5 100644 --- a/include/sound/pxa2xx-lib.h +++ b/include/sound/pxa2xx-lib.h | |||
@@ -4,6 +4,31 @@ | |||
4 | #include <linux/platform_device.h> | 4 | #include <linux/platform_device.h> |
5 | #include <sound/ac97_codec.h> | 5 | #include <sound/ac97_codec.h> |
6 | 6 | ||
7 | /* PCM */ | ||
8 | |||
9 | struct pxa2xx_pcm_dma_params { | ||
10 | char *name; /* stream identifier */ | ||
11 | u32 dcmd; /* DMA descriptor dcmd field */ | ||
12 | volatile u32 *drcmr; /* the DMA request channel to use */ | ||
13 | u32 dev_addr; /* device physical address for DMA */ | ||
14 | }; | ||
15 | |||
16 | extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
17 | struct snd_pcm_hw_params *params); | ||
18 | extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream); | ||
19 | extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd); | ||
20 | extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream); | ||
21 | extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream); | ||
22 | extern void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id); | ||
23 | extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream); | ||
24 | extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream); | ||
25 | extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
26 | struct vm_area_struct *vma); | ||
27 | extern int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream); | ||
28 | extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm); | ||
29 | |||
30 | /* AC97 */ | ||
31 | |||
7 | extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg); | 32 | extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg); |
8 | extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val); | 33 | extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val); |
9 | 34 | ||
diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 2e554815e27c..f8e6de48d816 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig | |||
@@ -34,7 +34,10 @@ config SND_PXA2XX_PCM | |||
34 | 34 | ||
35 | config SND_PXA2XX_LIB | 35 | config SND_PXA2XX_LIB |
36 | tristate | 36 | tristate |
37 | select SND_AC97_CODEC | 37 | select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97 |
38 | |||
39 | config SND_PXA2XX_LIB_AC97 | ||
40 | bool | ||
38 | 41 | ||
39 | config SND_PXA2XX_AC97 | 42 | config SND_PXA2XX_AC97 |
40 | tristate "AC97 driver for the Intel PXA2xx chip" | 43 | tristate "AC97 driver for the Intel PXA2xx chip" |
@@ -42,6 +45,7 @@ config SND_PXA2XX_AC97 | |||
42 | select SND_PXA2XX_PCM | 45 | select SND_PXA2XX_PCM |
43 | select SND_AC97_CODEC | 46 | select SND_AC97_CODEC |
44 | select SND_PXA2XX_LIB | 47 | select SND_PXA2XX_LIB |
48 | select SND_PXA2XX_LIB_AC97 | ||
45 | help | 49 | help |
46 | Say Y or M if you want to support any AC97 codec attached to | 50 | Say Y or M if you want to support any AC97 codec attached to |
47 | the PXA2xx AC97 interface. | 51 | the PXA2xx AC97 interface. |
diff --git a/sound/arm/Makefile b/sound/arm/Makefile index bb2ed884acdd..2054de11de8a 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile | |||
@@ -12,7 +12,8 @@ obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o | |||
12 | snd-pxa2xx-pcm-objs := pxa2xx-pcm.o | 12 | snd-pxa2xx-pcm-objs := pxa2xx-pcm.o |
13 | 13 | ||
14 | obj-$(CONFIG_SND_PXA2XX_LIB) += snd-pxa2xx-lib.o | 14 | obj-$(CONFIG_SND_PXA2XX_LIB) += snd-pxa2xx-lib.o |
15 | snd-pxa2xx-lib-objs := pxa2xx-ac97-lib.o | 15 | snd-pxa2xx-lib-y := pxa2xx-pcm-lib.o |
16 | snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o | ||
16 | 17 | ||
17 | obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o | 18 | obj-$(CONFIG_SND_PXA2XX_AC97) += snd-pxa2xx-ac97.o |
18 | snd-pxa2xx-ac97-objs := pxa2xx-ac97.o | 19 | snd-pxa2xx-ac97-objs := pxa2xx-ac97.o |
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c new file mode 100644 index 000000000000..1c93eb77cb99 --- /dev/null +++ b/sound/arm/pxa2xx-pcm-lib.c | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/dma-mapping.h> | ||
9 | |||
10 | #include <sound/core.h> | ||
11 | #include <sound/pcm.h> | ||
12 | #include <sound/pcm_params.h> | ||
13 | #include <sound/pxa2xx-lib.h> | ||
14 | |||
15 | #include <asm/dma.h> | ||
16 | #include <mach/pxa-regs.h> | ||
17 | |||
18 | #include "pxa2xx-pcm.h" | ||
19 | |||
20 | static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { | ||
21 | .info = SNDRV_PCM_INFO_MMAP | | ||
22 | SNDRV_PCM_INFO_MMAP_VALID | | ||
23 | SNDRV_PCM_INFO_INTERLEAVED | | ||
24 | SNDRV_PCM_INFO_PAUSE | | ||
25 | SNDRV_PCM_INFO_RESUME, | ||
26 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
27 | SNDRV_PCM_FMTBIT_S24_LE | | ||
28 | SNDRV_PCM_FMTBIT_S32_LE, | ||
29 | .period_bytes_min = 32, | ||
30 | .period_bytes_max = 8192 - 32, | ||
31 | .periods_min = 1, | ||
32 | .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), | ||
33 | .buffer_bytes_max = 128 * 1024, | ||
34 | .fifo_size = 32, | ||
35 | }; | ||
36 | |||
37 | int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
38 | struct snd_pcm_hw_params *params) | ||
39 | { | ||
40 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
41 | struct pxa2xx_runtime_data *rtd = runtime->private_data; | ||
42 | size_t totsize = params_buffer_bytes(params); | ||
43 | size_t period = params_period_bytes(params); | ||
44 | pxa_dma_desc *dma_desc; | ||
45 | dma_addr_t dma_buff_phys, next_desc_phys; | ||
46 | |||
47 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
48 | runtime->dma_bytes = totsize; | ||
49 | |||
50 | dma_desc = rtd->dma_desc_array; | ||
51 | next_desc_phys = rtd->dma_desc_array_phys; | ||
52 | dma_buff_phys = runtime->dma_addr; | ||
53 | do { | ||
54 | next_desc_phys += sizeof(pxa_dma_desc); | ||
55 | dma_desc->ddadr = next_desc_phys; | ||
56 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
57 | dma_desc->dsadr = dma_buff_phys; | ||
58 | dma_desc->dtadr = rtd->params->dev_addr; | ||
59 | } else { | ||
60 | dma_desc->dsadr = rtd->params->dev_addr; | ||
61 | dma_desc->dtadr = dma_buff_phys; | ||
62 | } | ||
63 | if (period > totsize) | ||
64 | period = totsize; | ||
65 | dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN; | ||
66 | dma_desc++; | ||
67 | dma_buff_phys += period; | ||
68 | } while (totsize -= period); | ||
69 | dma_desc[-1].ddadr = rtd->dma_desc_array_phys; | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | EXPORT_SYMBOL(__pxa2xx_pcm_hw_params); | ||
74 | |||
75 | int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
76 | { | ||
77 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; | ||
78 | |||
79 | if (rtd && rtd->params) | ||
80 | *rtd->params->drcmr = 0; | ||
81 | |||
82 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
83 | return 0; | ||
84 | } | ||
85 | EXPORT_SYMBOL(__pxa2xx_pcm_hw_free); | ||
86 | |||
87 | int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
88 | { | ||
89 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
90 | int ret = 0; | ||
91 | |||
92 | switch (cmd) { | ||
93 | case SNDRV_PCM_TRIGGER_START: | ||
94 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
95 | DCSR(prtd->dma_ch) = DCSR_RUN; | ||
96 | break; | ||
97 | |||
98 | case SNDRV_PCM_TRIGGER_STOP: | ||
99 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
100 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
101 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
102 | break; | ||
103 | |||
104 | case SNDRV_PCM_TRIGGER_RESUME: | ||
105 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
106 | break; | ||
107 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
108 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
109 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
110 | break; | ||
111 | |||
112 | default: | ||
113 | ret = -EINVAL; | ||
114 | } | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | EXPORT_SYMBOL(pxa2xx_pcm_trigger); | ||
119 | |||
120 | snd_pcm_uframes_t | ||
121 | pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
122 | { | ||
123 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
124 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
125 | |||
126 | dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
127 | DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch); | ||
128 | snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); | ||
129 | |||
130 | if (x == runtime->buffer_size) | ||
131 | x = 0; | ||
132 | return x; | ||
133 | } | ||
134 | EXPORT_SYMBOL(pxa2xx_pcm_pointer); | ||
135 | |||
136 | int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | ||
137 | { | ||
138 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
139 | |||
140 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
141 | DCSR(prtd->dma_ch) = 0; | ||
142 | DCMD(prtd->dma_ch) = 0; | ||
143 | *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | EXPORT_SYMBOL(__pxa2xx_pcm_prepare); | ||
148 | |||
149 | void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) | ||
150 | { | ||
151 | struct snd_pcm_substream *substream = dev_id; | ||
152 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; | ||
153 | int dcsr; | ||
154 | |||
155 | dcsr = DCSR(dma_ch); | ||
156 | DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; | ||
157 | |||
158 | if (dcsr & DCSR_ENDINTR) { | ||
159 | snd_pcm_period_elapsed(substream); | ||
160 | } else { | ||
161 | printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | ||
162 | rtd->params->name, dma_ch, dcsr); | ||
163 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
164 | } | ||
165 | } | ||
166 | EXPORT_SYMBOL(pxa2xx_pcm_dma_irq); | ||
167 | |||
168 | int __pxa2xx_pcm_open(struct snd_pcm_substream *substream) | ||
169 | { | ||
170 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
171 | struct pxa2xx_runtime_data *rtd; | ||
172 | int ret; | ||
173 | |||
174 | runtime->hw = pxa2xx_pcm_hardware; | ||
175 | |||
176 | /* | ||
177 | * For mysterious reasons (and despite what the manual says) | ||
178 | * playback samples are lost if the DMA count is not a multiple | ||
179 | * of the DMA burst size. Let's add a rule to enforce that. | ||
180 | */ | ||
181 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
182 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); | ||
183 | if (ret) | ||
184 | goto out; | ||
185 | |||
186 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
187 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); | ||
188 | if (ret) | ||
189 | goto out; | ||
190 | |||
191 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
192 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
193 | if (ret < 0) | ||
194 | goto out; | ||
195 | |||
196 | ret = -ENOMEM; | ||
197 | rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); | ||
198 | if (!rtd) | ||
199 | goto out; | ||
200 | rtd->dma_desc_array = | ||
201 | dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
202 | &rtd->dma_desc_array_phys, GFP_KERNEL); | ||
203 | if (!rtd->dma_desc_array) | ||
204 | goto err1; | ||
205 | |||
206 | runtime->private_data = rtd; | ||
207 | return 0; | ||
208 | |||
209 | err1: | ||
210 | kfree(rtd); | ||
211 | out: | ||
212 | return ret; | ||
213 | } | ||
214 | EXPORT_SYMBOL(__pxa2xx_pcm_open); | ||
215 | |||
216 | int __pxa2xx_pcm_close(struct snd_pcm_substream *substream) | ||
217 | { | ||
218 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
219 | struct pxa2xx_runtime_data *rtd = runtime->private_data; | ||
220 | |||
221 | dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
222 | rtd->dma_desc_array, rtd->dma_desc_array_phys); | ||
223 | kfree(rtd); | ||
224 | return 0; | ||
225 | } | ||
226 | EXPORT_SYMBOL(__pxa2xx_pcm_close); | ||
227 | |||
228 | int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
229 | struct vm_area_struct *vma) | ||
230 | { | ||
231 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
232 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
233 | runtime->dma_area, | ||
234 | runtime->dma_addr, | ||
235 | runtime->dma_bytes); | ||
236 | } | ||
237 | EXPORT_SYMBOL(pxa2xx_pcm_mmap); | ||
238 | |||
239 | int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
240 | { | ||
241 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
242 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
243 | size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; | ||
244 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
245 | buf->dev.dev = pcm->card->dev; | ||
246 | buf->private_data = NULL; | ||
247 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
248 | &buf->addr, GFP_KERNEL); | ||
249 | if (!buf->area) | ||
250 | return -ENOMEM; | ||
251 | buf->bytes = size; | ||
252 | return 0; | ||
253 | } | ||
254 | EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer); | ||
255 | |||
256 | void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
257 | { | ||
258 | struct snd_pcm_substream *substream; | ||
259 | struct snd_dma_buffer *buf; | ||
260 | int stream; | ||
261 | |||
262 | for (stream = 0; stream < 2; stream++) { | ||
263 | substream = pcm->streams[stream].substream; | ||
264 | if (!substream) | ||
265 | continue; | ||
266 | buf = &substream->dma_buffer; | ||
267 | if (!buf->area) | ||
268 | continue; | ||
269 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
270 | buf->area, buf->addr); | ||
271 | buf->area = NULL; | ||
272 | } | ||
273 | } | ||
274 | EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers); | ||
275 | |||
276 | MODULE_AUTHOR("Nicolas Pitre"); | ||
277 | MODULE_DESCRIPTION("Intel PXA2xx sound library"); | ||
278 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c index 381094aab235..535704f77496 100644 --- a/sound/arm/pxa2xx-pcm.c +++ b/sound/arm/pxa2xx-pcm.c | |||
@@ -10,183 +10,20 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/dma-mapping.h> | ||
18 | |||
19 | #include <sound/core.h> | 13 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | 14 | #include <sound/pxa2xx-lib.h> |
21 | #include <sound/pcm_params.h> | ||
22 | |||
23 | #include <asm/dma.h> | ||
24 | #include <mach/hardware.h> | ||
25 | #include <mach/pxa-regs.h> | ||
26 | 15 | ||
27 | #include "pxa2xx-pcm.h" | 16 | #include "pxa2xx-pcm.h" |
28 | 17 | ||
29 | |||
30 | static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { | ||
31 | .info = SNDRV_PCM_INFO_MMAP | | ||
32 | SNDRV_PCM_INFO_MMAP_VALID | | ||
33 | SNDRV_PCM_INFO_INTERLEAVED | | ||
34 | SNDRV_PCM_INFO_PAUSE, | ||
35 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
36 | .period_bytes_min = 32, | ||
37 | .period_bytes_max = 8192 - 32, | ||
38 | .periods_min = 1, | ||
39 | .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), | ||
40 | .buffer_bytes_max = 128 * 1024, | ||
41 | .fifo_size = 32, | ||
42 | }; | ||
43 | |||
44 | struct pxa2xx_runtime_data { | ||
45 | int dma_ch; | ||
46 | struct pxa2xx_pcm_dma_params *params; | ||
47 | pxa_dma_desc *dma_desc_array; | ||
48 | dma_addr_t dma_desc_array_phys; | ||
49 | }; | ||
50 | |||
51 | static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
52 | struct snd_pcm_hw_params *params) | ||
53 | { | ||
54 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
55 | struct pxa2xx_runtime_data *rtd = runtime->private_data; | ||
56 | size_t totsize = params_buffer_bytes(params); | ||
57 | size_t period = params_period_bytes(params); | ||
58 | pxa_dma_desc *dma_desc; | ||
59 | dma_addr_t dma_buff_phys, next_desc_phys; | ||
60 | |||
61 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
62 | runtime->dma_bytes = totsize; | ||
63 | |||
64 | dma_desc = rtd->dma_desc_array; | ||
65 | next_desc_phys = rtd->dma_desc_array_phys; | ||
66 | dma_buff_phys = runtime->dma_addr; | ||
67 | do { | ||
68 | next_desc_phys += sizeof(pxa_dma_desc); | ||
69 | dma_desc->ddadr = next_desc_phys; | ||
70 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
71 | dma_desc->dsadr = dma_buff_phys; | ||
72 | dma_desc->dtadr = rtd->params->dev_addr; | ||
73 | } else { | ||
74 | dma_desc->dsadr = rtd->params->dev_addr; | ||
75 | dma_desc->dtadr = dma_buff_phys; | ||
76 | } | ||
77 | if (period > totsize) | ||
78 | period = totsize; | ||
79 | dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN; | ||
80 | dma_desc++; | ||
81 | dma_buff_phys += period; | ||
82 | } while (totsize -= period); | ||
83 | dma_desc[-1].ddadr = rtd->dma_desc_array_phys; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
89 | { | ||
90 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; | ||
91 | |||
92 | *rtd->params->drcmr = 0; | ||
93 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | 18 | static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) |
98 | { | 19 | { |
99 | struct pxa2xx_pcm_client *client = substream->private_data; | 20 | struct pxa2xx_pcm_client *client = substream->private_data; |
100 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
101 | struct pxa2xx_runtime_data *rtd = runtime->private_data; | ||
102 | 21 | ||
103 | DCSR(rtd->dma_ch) &= ~DCSR_RUN; | 22 | __pxa2xx_pcm_prepare(substream); |
104 | DCSR(rtd->dma_ch) = 0; | ||
105 | DCMD(rtd->dma_ch) = 0; | ||
106 | *rtd->params->drcmr = rtd->dma_ch | DRCMR_MAPVLD; | ||
107 | 23 | ||
108 | return client->prepare(substream); | 24 | return client->prepare(substream); |
109 | } | 25 | } |
110 | 26 | ||
111 | static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
112 | { | ||
113 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; | ||
114 | int ret = 0; | ||
115 | |||
116 | switch (cmd) { | ||
117 | case SNDRV_PCM_TRIGGER_START: | ||
118 | DDADR(rtd->dma_ch) = rtd->dma_desc_array_phys; | ||
119 | DCSR(rtd->dma_ch) = DCSR_RUN; | ||
120 | break; | ||
121 | |||
122 | case SNDRV_PCM_TRIGGER_STOP: | ||
123 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
124 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
125 | DCSR(rtd->dma_ch) &= ~DCSR_RUN; | ||
126 | break; | ||
127 | |||
128 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
129 | DCSR(rtd->dma_ch) |= DCSR_RUN; | ||
130 | break; | ||
131 | |||
132 | default: | ||
133 | ret = -EINVAL; | ||
134 | } | ||
135 | |||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) | ||
140 | { | ||
141 | struct snd_pcm_substream *substream = dev_id; | ||
142 | struct pxa2xx_runtime_data *rtd = substream->runtime->private_data; | ||
143 | int dcsr; | ||
144 | |||
145 | dcsr = DCSR(dma_ch); | ||
146 | DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; | ||
147 | |||
148 | if (dcsr & DCSR_ENDINTR) { | ||
149 | snd_pcm_period_elapsed(substream); | ||
150 | } else { | ||
151 | printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | ||
152 | rtd->params->name, dma_ch, dcsr ); | ||
153 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
158 | { | ||
159 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
160 | struct pxa2xx_runtime_data *rtd = runtime->private_data; | ||
161 | dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
162 | DSADR(rtd->dma_ch) : DTADR(rtd->dma_ch); | ||
163 | snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); | ||
164 | if (x == runtime->buffer_size) | ||
165 | x = 0; | ||
166 | return x; | ||
167 | } | ||
168 | |||
169 | static int | ||
170 | pxa2xx_pcm_hw_rule_mult32(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) | ||
171 | { | ||
172 | struct snd_interval *i = hw_param_interval(params, rule->var); | ||
173 | int changed = 0; | ||
174 | |||
175 | if (i->min & 31) { | ||
176 | i->min = (i->min & ~31) + 32; | ||
177 | i->openmin = 0; | ||
178 | changed = 1; | ||
179 | } | ||
180 | |||
181 | if (i->max & 31) { | ||
182 | i->max &= ~31; | ||
183 | i->openmax = 0; | ||
184 | changed = 1; | ||
185 | } | ||
186 | |||
187 | return changed; | ||
188 | } | ||
189 | |||
190 | static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) | 27 | static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) |
191 | { | 28 | { |
192 | struct pxa2xx_pcm_client *client = substream->private_data; | 29 | struct pxa2xx_pcm_client *client = substream->private_data; |
@@ -194,33 +31,11 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) | |||
194 | struct pxa2xx_runtime_data *rtd; | 31 | struct pxa2xx_runtime_data *rtd; |
195 | int ret; | 32 | int ret; |
196 | 33 | ||
197 | runtime->hw = pxa2xx_pcm_hardware; | 34 | ret = __pxa2xx_pcm_open(substream); |
198 | |||
199 | /* | ||
200 | * For mysterious reasons (and despite what the manual says) | ||
201 | * playback samples are lost if the DMA count is not a multiple | ||
202 | * of the DMA burst size. Let's add a rule to enforce that. | ||
203 | */ | ||
204 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
205 | pxa2xx_pcm_hw_rule_mult32, NULL, | ||
206 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1); | ||
207 | if (ret) | ||
208 | goto out; | ||
209 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
210 | pxa2xx_pcm_hw_rule_mult32, NULL, | ||
211 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1); | ||
212 | if (ret) | 35 | if (ret) |
213 | goto out; | 36 | goto out; |
214 | 37 | ||
215 | ret = -ENOMEM; | 38 | rtd = runtime->private_data; |
216 | rtd = kmalloc(sizeof(*rtd), GFP_KERNEL); | ||
217 | if (!rtd) | ||
218 | goto out; | ||
219 | rtd->dma_desc_array = | ||
220 | dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
221 | &rtd->dma_desc_array_phys, GFP_KERNEL); | ||
222 | if (!rtd->dma_desc_array) | ||
223 | goto err1; | ||
224 | 39 | ||
225 | rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 40 | rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
226 | client->playback_params : client->capture_params; | 41 | client->playback_params : client->capture_params; |
@@ -230,17 +45,13 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) | |||
230 | goto err2; | 45 | goto err2; |
231 | rtd->dma_ch = ret; | 46 | rtd->dma_ch = ret; |
232 | 47 | ||
233 | runtime->private_data = rtd; | ||
234 | ret = client->startup(substream); | 48 | ret = client->startup(substream); |
235 | if (!ret) | 49 | if (!ret) |
236 | goto out; | 50 | goto out; |
237 | 51 | ||
238 | pxa_free_dma(rtd->dma_ch); | 52 | pxa_free_dma(rtd->dma_ch); |
239 | err2: | 53 | err2: |
240 | dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, | 54 | __pxa2xx_pcm_close(substream); |
241 | rtd->dma_desc_array, rtd->dma_desc_array_phys); | ||
242 | err1: | ||
243 | kfree(rtd); | ||
244 | out: | 55 | out: |
245 | return ret; | 56 | return ret; |
246 | } | 57 | } |
@@ -252,69 +63,22 @@ static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) | |||
252 | 63 | ||
253 | pxa_free_dma(rtd->dma_ch); | 64 | pxa_free_dma(rtd->dma_ch); |
254 | client->shutdown(substream); | 65 | client->shutdown(substream); |
255 | dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
256 | rtd->dma_desc_array, rtd->dma_desc_array_phys); | ||
257 | kfree(rtd); | ||
258 | return 0; | ||
259 | } | ||
260 | 66 | ||
261 | static int | 67 | return __pxa2xx_pcm_close(substream); |
262 | pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) | ||
263 | { | ||
264 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
265 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
266 | runtime->dma_area, | ||
267 | runtime->dma_addr, | ||
268 | runtime->dma_bytes); | ||
269 | } | 68 | } |
270 | 69 | ||
271 | static struct snd_pcm_ops pxa2xx_pcm_ops = { | 70 | static struct snd_pcm_ops pxa2xx_pcm_ops = { |
272 | .open = pxa2xx_pcm_open, | 71 | .open = pxa2xx_pcm_open, |
273 | .close = pxa2xx_pcm_close, | 72 | .close = pxa2xx_pcm_close, |
274 | .ioctl = snd_pcm_lib_ioctl, | 73 | .ioctl = snd_pcm_lib_ioctl, |
275 | .hw_params = pxa2xx_pcm_hw_params, | 74 | .hw_params = __pxa2xx_pcm_hw_params, |
276 | .hw_free = pxa2xx_pcm_hw_free, | 75 | .hw_free = __pxa2xx_pcm_hw_free, |
277 | .prepare = pxa2xx_pcm_prepare, | 76 | .prepare = pxa2xx_pcm_prepare, |
278 | .trigger = pxa2xx_pcm_trigger, | 77 | .trigger = pxa2xx_pcm_trigger, |
279 | .pointer = pxa2xx_pcm_pointer, | 78 | .pointer = pxa2xx_pcm_pointer, |
280 | .mmap = pxa2xx_pcm_mmap, | 79 | .mmap = pxa2xx_pcm_mmap, |
281 | }; | 80 | }; |
282 | 81 | ||
283 | static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
284 | { | ||
285 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
286 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
287 | size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; | ||
288 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
289 | buf->dev.dev = pcm->card->dev; | ||
290 | buf->private_data = NULL; | ||
291 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
292 | &buf->addr, GFP_KERNEL); | ||
293 | if (!buf->area) | ||
294 | return -ENOMEM; | ||
295 | buf->bytes = size; | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
300 | { | ||
301 | struct snd_pcm_substream *substream; | ||
302 | struct snd_dma_buffer *buf; | ||
303 | int stream; | ||
304 | |||
305 | for (stream = 0; stream < 2; stream++) { | ||
306 | substream = pcm->streams[stream].substream; | ||
307 | if (!substream) | ||
308 | continue; | ||
309 | buf = &substream->dma_buffer; | ||
310 | if (!buf->area) | ||
311 | continue; | ||
312 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
313 | buf->area, buf->addr); | ||
314 | buf->area = NULL; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | static u64 pxa2xx_pcm_dmamask = 0xffffffff; | 82 | static u64 pxa2xx_pcm_dmamask = 0xffffffff; |
319 | 83 | ||
320 | int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client, | 84 | int pxa2xx_pcm_new(struct snd_card *card, struct pxa2xx_pcm_client *client, |
diff --git a/sound/arm/pxa2xx-pcm.h b/sound/arm/pxa2xx-pcm.h index b79f1e803780..5c4a4d38a083 100644 --- a/sound/arm/pxa2xx-pcm.h +++ b/sound/arm/pxa2xx-pcm.h | |||
@@ -9,14 +9,15 @@ | |||
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | #include <asm/dma.h> | ||
12 | 13 | ||
13 | struct pxa2xx_pcm_dma_params { | 14 | struct pxa2xx_runtime_data { |
14 | char *name; /* stream identifier */ | 15 | int dma_ch; |
15 | u32 dcmd; /* DMA descriptor dcmd field */ | 16 | struct pxa2xx_pcm_dma_params *params; |
16 | volatile u32 *drcmr; /* the DMA request channel to use */ | 17 | pxa_dma_desc *dma_desc_array; |
17 | u32 dev_addr; /* device physical address for DMA */ | 18 | dma_addr_t dma_desc_array_phys; |
18 | }; | 19 | }; |
19 | 20 | ||
20 | struct pxa2xx_pcm_client { | 21 | struct pxa2xx_pcm_client { |
21 | struct pxa2xx_pcm_dma_params *playback_params; | 22 | struct pxa2xx_pcm_dma_params *playback_params; |
22 | struct pxa2xx_pcm_dma_params *capture_params; | 23 | struct pxa2xx_pcm_dma_params *capture_params; |
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index d1ccbdc8371b..f8c1cdd940ac 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config SND_PXA2XX_SOC | 1 | config SND_PXA2XX_SOC |
2 | tristate "SoC Audio for the Intel PXA2xx chip" | 2 | tristate "SoC Audio for the Intel PXA2xx chip" |
3 | depends on ARCH_PXA | 3 | depends on ARCH_PXA |
4 | select SND_PXA2XX_LIB | ||
4 | help | 5 | help |
5 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
6 | the PXA2xx AC97, I2S or SSP interface. You will also need | 7 | the PXA2xx AC97, I2S or SSP interface. You will also need |
@@ -14,7 +15,7 @@ config SND_PXA2XX_SOC_AC97 | |||
14 | tristate | 15 | tristate |
15 | select AC97_BUS | 16 | select AC97_BUS |
16 | select SND_ARM | 17 | select SND_ARM |
17 | select SND_PXA2XX_LIB | 18 | select SND_PXA2XX_LIB_AC97 |
18 | select SND_SOC_AC97_BUS | 19 | select SND_SOC_AC97_BUS |
19 | 20 | ||
20 | config SND_PXA2XX_SOC_I2S | 21 | config SND_PXA2XX_SOC_I2S |
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index 21ca3fe22306..39d19212f6d3 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
22 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/pxa2xx-lib.h> | ||
24 | 25 | ||
25 | #include <mach/hardware.h> | 26 | #include <mach/hardware.h> |
26 | #include <mach/pxa-regs.h> | 27 | #include <mach/pxa-regs.h> |
@@ -30,6 +31,15 @@ | |||
30 | #include "pxa2xx-pcm.h" | 31 | #include "pxa2xx-pcm.h" |
31 | #include "pxa2xx-i2s.h" | 32 | #include "pxa2xx-i2s.h" |
32 | 33 | ||
34 | struct pxa2xx_gpio { | ||
35 | u32 sys; | ||
36 | u32 rx; | ||
37 | u32 tx; | ||
38 | u32 clk; | ||
39 | u32 frm; | ||
40 | }; | ||
41 | |||
42 | |||
33 | struct pxa_i2s_port { | 43 | struct pxa_i2s_port { |
34 | u32 sadiv; | 44 | u32 sadiv; |
35 | u32 sacr0; | 45 | u32 sacr0; |
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 771c592b0429..afcd892cd2fa 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -10,64 +10,14 @@ | |||
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/dma-mapping.h> | 13 | #include <linux/dma-mapping.h> |
18 | 14 | ||
19 | #include <sound/core.h> | 15 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
23 | 17 | #include <sound/pxa2xx-lib.h> | |
24 | #include <asm/dma.h> | ||
25 | #include <mach/hardware.h> | ||
26 | #include <mach/pxa-regs.h> | ||
27 | #include <mach/audio.h> | ||
28 | 18 | ||
29 | #include "pxa2xx-pcm.h" | 19 | #include "pxa2xx-pcm.h" |
30 | 20 | #include "../../arm/pxa2xx-pcm.h" | |
31 | static const struct snd_pcm_hardware pxa2xx_pcm_hardware = { | ||
32 | .info = SNDRV_PCM_INFO_MMAP | | ||
33 | SNDRV_PCM_INFO_MMAP_VALID | | ||
34 | SNDRV_PCM_INFO_INTERLEAVED | | ||
35 | SNDRV_PCM_INFO_PAUSE | | ||
36 | SNDRV_PCM_INFO_RESUME, | ||
37 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
38 | SNDRV_PCM_FMTBIT_S24_LE | | ||
39 | SNDRV_PCM_FMTBIT_S32_LE, | ||
40 | .period_bytes_min = 32, | ||
41 | .period_bytes_max = 8192 - 32, | ||
42 | .periods_min = 1, | ||
43 | .periods_max = PAGE_SIZE/sizeof(pxa_dma_desc), | ||
44 | .buffer_bytes_max = 128 * 1024, | ||
45 | .fifo_size = 32, | ||
46 | }; | ||
47 | |||
48 | struct pxa2xx_runtime_data { | ||
49 | int dma_ch; | ||
50 | struct pxa2xx_pcm_dma_params *params; | ||
51 | pxa_dma_desc *dma_desc_array; | ||
52 | dma_addr_t dma_desc_array_phys; | ||
53 | }; | ||
54 | |||
55 | static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id) | ||
56 | { | ||
57 | struct snd_pcm_substream *substream = dev_id; | ||
58 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
59 | int dcsr; | ||
60 | |||
61 | dcsr = DCSR(dma_ch); | ||
62 | DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN; | ||
63 | |||
64 | if (dcsr & DCSR_ENDINTR) { | ||
65 | snd_pcm_period_elapsed(substream); | ||
66 | } else { | ||
67 | printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | ||
68 | prtd->params->name, dma_ch, dcsr); | ||
69 | } | ||
70 | } | ||
71 | 21 | ||
72 | static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | 22 | static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, |
73 | struct snd_pcm_hw_params *params) | 23 | struct snd_pcm_hw_params *params) |
@@ -76,10 +26,6 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
76 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | 26 | struct pxa2xx_runtime_data *prtd = runtime->private_data; |
77 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 27 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
78 | struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; | 28 | struct pxa2xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data; |
79 | size_t totsize = params_buffer_bytes(params); | ||
80 | size_t period = params_period_bytes(params); | ||
81 | pxa_dma_desc *dma_desc; | ||
82 | dma_addr_t dma_buff_phys, next_desc_phys; | ||
83 | int ret; | 29 | int ret; |
84 | 30 | ||
85 | /* return if this is a bufferless transfer e.g. | 31 | /* return if this is a bufferless transfer e.g. |
@@ -106,42 +52,16 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
106 | prtd->dma_ch = ret; | 52 | prtd->dma_ch = ret; |
107 | } | 53 | } |
108 | 54 | ||
109 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 55 | return __pxa2xx_pcm_hw_params(substream, params); |
110 | runtime->dma_bytes = totsize; | ||
111 | |||
112 | dma_desc = prtd->dma_desc_array; | ||
113 | next_desc_phys = prtd->dma_desc_array_phys; | ||
114 | dma_buff_phys = runtime->dma_addr; | ||
115 | do { | ||
116 | next_desc_phys += sizeof(pxa_dma_desc); | ||
117 | dma_desc->ddadr = next_desc_phys; | ||
118 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
119 | dma_desc->dsadr = dma_buff_phys; | ||
120 | dma_desc->dtadr = prtd->params->dev_addr; | ||
121 | } else { | ||
122 | dma_desc->dsadr = prtd->params->dev_addr; | ||
123 | dma_desc->dtadr = dma_buff_phys; | ||
124 | } | ||
125 | if (period > totsize) | ||
126 | period = totsize; | ||
127 | dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN; | ||
128 | dma_desc++; | ||
129 | dma_buff_phys += period; | ||
130 | } while (totsize -= period); | ||
131 | dma_desc[-1].ddadr = prtd->dma_desc_array_phys; | ||
132 | |||
133 | return 0; | ||
134 | } | 56 | } |
135 | 57 | ||
136 | static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | 58 | static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) |
137 | { | 59 | { |
138 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | 60 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; |
139 | 61 | ||
140 | if (prtd && prtd->params) | 62 | __pxa2xx_pcm_hw_free(substream); |
141 | *prtd->params->drcmr = 0; | ||
142 | 63 | ||
143 | if (prtd->dma_ch) { | 64 | if (prtd->dma_ch) { |
144 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
145 | pxa_free_dma(prtd->dma_ch); | 65 | pxa_free_dma(prtd->dma_ch); |
146 | prtd->dma_ch = 0; | 66 | prtd->dma_ch = 0; |
147 | } | 67 | } |
@@ -149,185 +69,18 @@ static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
149 | return 0; | 69 | return 0; |
150 | } | 70 | } |
151 | 71 | ||
152 | static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | ||
153 | { | ||
154 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
155 | |||
156 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
157 | DCSR(prtd->dma_ch) = 0; | ||
158 | DCMD(prtd->dma_ch) = 0; | ||
159 | *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD; | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
165 | { | ||
166 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | ||
167 | int ret = 0; | ||
168 | |||
169 | switch (cmd) { | ||
170 | case SNDRV_PCM_TRIGGER_START: | ||
171 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
172 | DCSR(prtd->dma_ch) = DCSR_RUN; | ||
173 | break; | ||
174 | |||
175 | case SNDRV_PCM_TRIGGER_STOP: | ||
176 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
177 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
178 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | ||
179 | break; | ||
180 | |||
181 | case SNDRV_PCM_TRIGGER_RESUME: | ||
182 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
183 | break; | ||
184 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
185 | DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys; | ||
186 | DCSR(prtd->dma_ch) |= DCSR_RUN; | ||
187 | break; | ||
188 | |||
189 | default: | ||
190 | ret = -EINVAL; | ||
191 | } | ||
192 | |||
193 | return ret; | ||
194 | } | ||
195 | |||
196 | static snd_pcm_uframes_t | ||
197 | pxa2xx_pcm_pointer(struct snd_pcm_substream *substream) | ||
198 | { | ||
199 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
200 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
201 | |||
202 | dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
203 | DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch); | ||
204 | snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr); | ||
205 | |||
206 | if (x == runtime->buffer_size) | ||
207 | x = 0; | ||
208 | return x; | ||
209 | } | ||
210 | |||
211 | static int pxa2xx_pcm_open(struct snd_pcm_substream *substream) | ||
212 | { | ||
213 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
214 | struct pxa2xx_runtime_data *prtd; | ||
215 | int ret; | ||
216 | |||
217 | snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware); | ||
218 | |||
219 | /* | ||
220 | * For mysterious reasons (and despite what the manual says) | ||
221 | * playback samples are lost if the DMA count is not a multiple | ||
222 | * of the DMA burst size. Let's add a rule to enforce that. | ||
223 | */ | ||
224 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
225 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); | ||
226 | if (ret) | ||
227 | goto out; | ||
228 | |||
229 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
230 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); | ||
231 | if (ret) | ||
232 | goto out; | ||
233 | |||
234 | ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
235 | if (ret < 0) | ||
236 | goto out; | ||
237 | |||
238 | prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL); | ||
239 | if (prtd == NULL) { | ||
240 | ret = -ENOMEM; | ||
241 | goto out; | ||
242 | } | ||
243 | |||
244 | prtd->dma_desc_array = | ||
245 | dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
246 | &prtd->dma_desc_array_phys, GFP_KERNEL); | ||
247 | if (!prtd->dma_desc_array) { | ||
248 | ret = -ENOMEM; | ||
249 | goto err1; | ||
250 | } | ||
251 | |||
252 | runtime->private_data = prtd; | ||
253 | return 0; | ||
254 | |||
255 | err1: | ||
256 | kfree(prtd); | ||
257 | out: | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | static int pxa2xx_pcm_close(struct snd_pcm_substream *substream) | ||
262 | { | ||
263 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
264 | struct pxa2xx_runtime_data *prtd = runtime->private_data; | ||
265 | |||
266 | dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE, | ||
267 | prtd->dma_desc_array, prtd->dma_desc_array_phys); | ||
268 | kfree(prtd); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream, | ||
273 | struct vm_area_struct *vma) | ||
274 | { | ||
275 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
276 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
277 | runtime->dma_area, | ||
278 | runtime->dma_addr, | ||
279 | runtime->dma_bytes); | ||
280 | } | ||
281 | |||
282 | struct snd_pcm_ops pxa2xx_pcm_ops = { | 72 | struct snd_pcm_ops pxa2xx_pcm_ops = { |
283 | .open = pxa2xx_pcm_open, | 73 | .open = __pxa2xx_pcm_open, |
284 | .close = pxa2xx_pcm_close, | 74 | .close = __pxa2xx_pcm_close, |
285 | .ioctl = snd_pcm_lib_ioctl, | 75 | .ioctl = snd_pcm_lib_ioctl, |
286 | .hw_params = pxa2xx_pcm_hw_params, | 76 | .hw_params = pxa2xx_pcm_hw_params, |
287 | .hw_free = pxa2xx_pcm_hw_free, | 77 | .hw_free = pxa2xx_pcm_hw_free, |
288 | .prepare = pxa2xx_pcm_prepare, | 78 | .prepare = __pxa2xx_pcm_prepare, |
289 | .trigger = pxa2xx_pcm_trigger, | 79 | .trigger = pxa2xx_pcm_trigger, |
290 | .pointer = pxa2xx_pcm_pointer, | 80 | .pointer = pxa2xx_pcm_pointer, |
291 | .mmap = pxa2xx_pcm_mmap, | 81 | .mmap = pxa2xx_pcm_mmap, |
292 | }; | 82 | }; |
293 | 83 | ||
294 | static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
295 | { | ||
296 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
297 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
298 | size_t size = pxa2xx_pcm_hardware.buffer_bytes_max; | ||
299 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
300 | buf->dev.dev = pcm->card->dev; | ||
301 | buf->private_data = NULL; | ||
302 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
303 | &buf->addr, GFP_KERNEL); | ||
304 | if (!buf->area) | ||
305 | return -ENOMEM; | ||
306 | buf->bytes = size; | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
311 | { | ||
312 | struct snd_pcm_substream *substream; | ||
313 | struct snd_dma_buffer *buf; | ||
314 | int stream; | ||
315 | |||
316 | for (stream = 0; stream < 2; stream++) { | ||
317 | substream = pcm->streams[stream].substream; | ||
318 | if (!substream) | ||
319 | continue; | ||
320 | |||
321 | buf = &substream->dma_buffer; | ||
322 | if (!buf->area) | ||
323 | continue; | ||
324 | |||
325 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
326 | buf->area, buf->addr); | ||
327 | buf->area = NULL; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; | 84 | static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK; |
332 | 85 | ||
333 | static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 86 | static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
diff --git a/sound/soc/pxa/pxa2xx-pcm.h b/sound/soc/pxa/pxa2xx-pcm.h index 54c9c755e508..60c3b20aeeb4 100644 --- a/sound/soc/pxa/pxa2xx-pcm.h +++ b/sound/soc/pxa/pxa2xx-pcm.h | |||
@@ -13,21 +13,6 @@ | |||
13 | #ifndef _PXA2XX_PCM_H | 13 | #ifndef _PXA2XX_PCM_H |
14 | #define _PXA2XX_PCM_H | 14 | #define _PXA2XX_PCM_H |
15 | 15 | ||
16 | struct pxa2xx_pcm_dma_params { | ||
17 | char *name; /* stream identifier */ | ||
18 | u32 dcmd; /* DMA descriptor dcmd field */ | ||
19 | volatile u32 *drcmr; /* the DMA request channel to use */ | ||
20 | u32 dev_addr; /* device physical address for DMA */ | ||
21 | }; | ||
22 | |||
23 | struct pxa2xx_gpio { | ||
24 | u32 sys; | ||
25 | u32 rx; | ||
26 | u32 tx; | ||
27 | u32 clk; | ||
28 | u32 frm; | ||
29 | }; | ||
30 | |||
31 | /* platform data */ | 16 | /* platform data */ |
32 | extern struct snd_soc_platform pxa2xx_soc_platform; | 17 | extern struct snd_soc_platform pxa2xx_soc_platform; |
33 | 18 | ||