diff options
author | Bo Shen <voice.shen@atmel.com> | 2012-11-27 22:46:12 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-12-01 23:27:44 -0500 |
commit | 92dfa61986237f849bb6ff5190380b3bf69335d2 (patch) | |
tree | c1a3fe286bd52c51a07a9045e04bb6a965cff284 /sound | |
parent | 31974361761b18e07e821d3b262e34f1a2d105cb (diff) |
ASoC: atmel-pcm: split into two file
This patch is split original atmel-pcm.c into new atmel-pcm.c and
atmel-pcm-pdc.c two files. The new atmel-pcm.c is the share routine
while will be used for pdc or dma transfer.
Using SND_ATMEL_SOC_PDC to select using PDC for audio transfer
Signed-off-by: Bo Shen <voice.shen@atmel.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/atmel/Kconfig | 5 | ||||
-rw-r--r-- | sound/soc/atmel/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/atmel/atmel-pcm-pdc.c | 401 | ||||
-rw-r--r-- | sound/soc/atmel/atmel-pcm.c | 390 | ||||
-rw-r--r-- | sound/soc/atmel/atmel-pcm.h | 21 | ||||
-rw-r--r-- | sound/soc/atmel/atmel_ssc_dai.c | 4 |
6 files changed, 441 insertions, 382 deletions
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 397ec7526a5a..6051993eca91 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
@@ -6,6 +6,10 @@ config SND_ATMEL_SOC | |||
6 | the ATMEL SSC interface. You will also need | 6 | the ATMEL SSC interface. You will also need |
7 | to select the audio interfaces to support below. | 7 | to select the audio interfaces to support below. |
8 | 8 | ||
9 | config SND_ATMEL_SOC_PDC | ||
10 | tristate | ||
11 | depends on SND_ATMEL_SOC | ||
12 | |||
9 | config SND_ATMEL_SOC_SSC | 13 | config SND_ATMEL_SOC_SSC |
10 | tristate | 14 | tristate |
11 | depends on SND_ATMEL_SOC | 15 | depends on SND_ATMEL_SOC |
@@ -17,6 +21,7 @@ config SND_ATMEL_SOC_SSC | |||
17 | config SND_AT91_SOC_SAM9G20_WM8731 | 21 | config SND_AT91_SOC_SAM9G20_WM8731 |
18 | tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" | 22 | tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" |
19 | depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS | 23 | depends on ATMEL_SSC && SND_ATMEL_SOC && AT91_PROGRAMMABLE_CLOCKS |
24 | select SND_ATMEL_SOC_PDC | ||
20 | select SND_ATMEL_SOC_SSC | 25 | select SND_ATMEL_SOC_SSC |
21 | select SND_SOC_WM8731 | 26 | select SND_SOC_WM8731 |
22 | help | 27 | help |
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index a5c0bf19da78..2e37864ee860 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile | |||
@@ -1,8 +1,10 @@ | |||
1 | # AT91 Platform Support | 1 | # AT91 Platform Support |
2 | snd-soc-atmel-pcm-objs := atmel-pcm.o | 2 | snd-soc-atmel-pcm-objs := atmel-pcm.o |
3 | snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o | ||
3 | snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o | 4 | snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o |
4 | 5 | ||
5 | obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o | 6 | obj-$(CONFIG_SND_ATMEL_SOC) += snd-soc-atmel-pcm.o |
7 | obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o | ||
6 | obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o | 8 | obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o |
7 | 9 | ||
8 | # AT91 Machine Support | 10 | # AT91 Machine Support |
diff --git a/sound/soc/atmel/atmel-pcm-pdc.c b/sound/soc/atmel/atmel-pcm-pdc.c new file mode 100644 index 000000000000..6a293c713a38 --- /dev/null +++ b/sound/soc/atmel/atmel-pcm-pdc.c | |||
@@ -0,0 +1,401 @@ | |||
1 | /* | ||
2 | * atmel-pcm.c -- ALSA PCM interface for the Atmel atmel SoC. | ||
3 | * | ||
4 | * Copyright (C) 2005 SAN People | ||
5 | * Copyright (C) 2008 Atmel | ||
6 | * | ||
7 | * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com> | ||
8 | * | ||
9 | * Based on at91-pcm. by: | ||
10 | * Frank Mandarino <fmandarino@endrelia.com> | ||
11 | * Copyright 2006 Endrelia Technologies Inc. | ||
12 | * | ||
13 | * Based on pxa2xx-pcm.c by: | ||
14 | * | ||
15 | * Author: Nicolas Pitre | ||
16 | * Created: Nov 30, 2004 | ||
17 | * Copyright: (C) 2004 MontaVista Software, Inc. | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify | ||
20 | * it under the terms of the GNU General Public License as published by | ||
21 | * the Free Software Foundation; either version 2 of the License, or | ||
22 | * (at your option) any later version. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | * GNU General Public License for more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License | ||
30 | * along with this program; if not, write to the Free Software | ||
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
32 | */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/platform_device.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/dma-mapping.h> | ||
39 | #include <linux/atmel_pdc.h> | ||
40 | #include <linux/atmel-ssc.h> | ||
41 | |||
42 | #include <sound/core.h> | ||
43 | #include <sound/pcm.h> | ||
44 | #include <sound/pcm_params.h> | ||
45 | #include <sound/soc.h> | ||
46 | |||
47 | #include "atmel-pcm.h" | ||
48 | |||
49 | |||
50 | /*--------------------------------------------------------------------------*\ | ||
51 | * Hardware definition | ||
52 | \*--------------------------------------------------------------------------*/ | ||
53 | /* TODO: These values were taken from the AT91 platform driver, check | ||
54 | * them against real values for AT32 | ||
55 | */ | ||
56 | static const struct snd_pcm_hardware atmel_pcm_hardware = { | ||
57 | .info = SNDRV_PCM_INFO_MMAP | | ||
58 | SNDRV_PCM_INFO_MMAP_VALID | | ||
59 | SNDRV_PCM_INFO_INTERLEAVED | | ||
60 | SNDRV_PCM_INFO_PAUSE, | ||
61 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
62 | .period_bytes_min = 32, | ||
63 | .period_bytes_max = 8192, | ||
64 | .periods_min = 2, | ||
65 | .periods_max = 1024, | ||
66 | .buffer_bytes_max = ATMEL_SSC_DMABUF_SIZE, | ||
67 | }; | ||
68 | |||
69 | |||
70 | /*--------------------------------------------------------------------------*\ | ||
71 | * Data types | ||
72 | \*--------------------------------------------------------------------------*/ | ||
73 | struct atmel_runtime_data { | ||
74 | struct atmel_pcm_dma_params *params; | ||
75 | dma_addr_t dma_buffer; /* physical address of dma buffer */ | ||
76 | dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ | ||
77 | size_t period_size; | ||
78 | |||
79 | dma_addr_t period_ptr; /* physical address of next period */ | ||
80 | |||
81 | /* PDC register save */ | ||
82 | u32 pdc_xpr_save; | ||
83 | u32 pdc_xcr_save; | ||
84 | u32 pdc_xnpr_save; | ||
85 | u32 pdc_xncr_save; | ||
86 | }; | ||
87 | |||
88 | /*--------------------------------------------------------------------------*\ | ||
89 | * ISR | ||
90 | \*--------------------------------------------------------------------------*/ | ||
91 | static void atmel_pcm_dma_irq(u32 ssc_sr, | ||
92 | struct snd_pcm_substream *substream) | ||
93 | { | ||
94 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
95 | struct atmel_pcm_dma_params *params = prtd->params; | ||
96 | static int count; | ||
97 | |||
98 | count++; | ||
99 | |||
100 | if (ssc_sr & params->mask->ssc_endbuf) { | ||
101 | pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n", | ||
102 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK | ||
103 | ? "underrun" : "overrun", | ||
104 | params->name, ssc_sr, count); | ||
105 | |||
106 | /* re-start the PDC */ | ||
107 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
108 | params->mask->pdc_disable); | ||
109 | prtd->period_ptr += prtd->period_size; | ||
110 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
111 | prtd->period_ptr = prtd->dma_buffer; | ||
112 | |||
113 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
114 | prtd->period_ptr); | ||
115 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
116 | prtd->period_size / params->pdc_xfer_size); | ||
117 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
118 | params->mask->pdc_enable); | ||
119 | } | ||
120 | |||
121 | if (ssc_sr & params->mask->ssc_endx) { | ||
122 | /* Load the PDC next pointer and counter registers */ | ||
123 | prtd->period_ptr += prtd->period_size; | ||
124 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
125 | prtd->period_ptr = prtd->dma_buffer; | ||
126 | |||
127 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
128 | prtd->period_ptr); | ||
129 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
130 | prtd->period_size / params->pdc_xfer_size); | ||
131 | } | ||
132 | |||
133 | snd_pcm_period_elapsed(substream); | ||
134 | } | ||
135 | |||
136 | |||
137 | /*--------------------------------------------------------------------------*\ | ||
138 | * PCM operations | ||
139 | \*--------------------------------------------------------------------------*/ | ||
140 | static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, | ||
141 | struct snd_pcm_hw_params *params) | ||
142 | { | ||
143 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
144 | struct atmel_runtime_data *prtd = runtime->private_data; | ||
145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
146 | |||
147 | /* this may get called several times by oss emulation | ||
148 | * with different params */ | ||
149 | |||
150 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
151 | runtime->dma_bytes = params_buffer_bytes(params); | ||
152 | |||
153 | prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
154 | prtd->params->dma_intr_handler = atmel_pcm_dma_irq; | ||
155 | |||
156 | prtd->dma_buffer = runtime->dma_addr; | ||
157 | prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; | ||
158 | prtd->period_size = params_period_bytes(params); | ||
159 | |||
160 | pr_debug("atmel-pcm: " | ||
161 | "hw_params: DMA for %s initialized " | ||
162 | "(dma_bytes=%u, period_size=%u)\n", | ||
163 | prtd->params->name, | ||
164 | runtime->dma_bytes, | ||
165 | prtd->period_size); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) | ||
170 | { | ||
171 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
172 | struct atmel_pcm_dma_params *params = prtd->params; | ||
173 | |||
174 | if (params != NULL) { | ||
175 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
176 | params->mask->pdc_disable); | ||
177 | prtd->params->dma_intr_handler = NULL; | ||
178 | } | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int atmel_pcm_prepare(struct snd_pcm_substream *substream) | ||
184 | { | ||
185 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
186 | struct atmel_pcm_dma_params *params = prtd->params; | ||
187 | |||
188 | ssc_writex(params->ssc->regs, SSC_IDR, | ||
189 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
190 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
191 | params->mask->pdc_disable); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int atmel_pcm_trigger(struct snd_pcm_substream *substream, | ||
196 | int cmd) | ||
197 | { | ||
198 | struct snd_pcm_runtime *rtd = substream->runtime; | ||
199 | struct atmel_runtime_data *prtd = rtd->private_data; | ||
200 | struct atmel_pcm_dma_params *params = prtd->params; | ||
201 | int ret = 0; | ||
202 | |||
203 | pr_debug("atmel-pcm:buffer_size = %ld," | ||
204 | "dma_area = %p, dma_bytes = %u\n", | ||
205 | rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); | ||
206 | |||
207 | switch (cmd) { | ||
208 | case SNDRV_PCM_TRIGGER_START: | ||
209 | prtd->period_ptr = prtd->dma_buffer; | ||
210 | |||
211 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
212 | prtd->period_ptr); | ||
213 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
214 | prtd->period_size / params->pdc_xfer_size); | ||
215 | |||
216 | prtd->period_ptr += prtd->period_size; | ||
217 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
218 | prtd->period_ptr); | ||
219 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
220 | prtd->period_size / params->pdc_xfer_size); | ||
221 | |||
222 | pr_debug("atmel-pcm: trigger: " | ||
223 | "period_ptr=%lx, xpr=%u, " | ||
224 | "xcr=%u, xnpr=%u, xncr=%u\n", | ||
225 | (unsigned long)prtd->period_ptr, | ||
226 | ssc_readx(params->ssc->regs, params->pdc->xpr), | ||
227 | ssc_readx(params->ssc->regs, params->pdc->xcr), | ||
228 | ssc_readx(params->ssc->regs, params->pdc->xnpr), | ||
229 | ssc_readx(params->ssc->regs, params->pdc->xncr)); | ||
230 | |||
231 | ssc_writex(params->ssc->regs, SSC_IER, | ||
232 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
233 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
234 | params->mask->pdc_enable); | ||
235 | |||
236 | pr_debug("sr=%u imr=%u\n", | ||
237 | ssc_readx(params->ssc->regs, SSC_SR), | ||
238 | ssc_readx(params->ssc->regs, SSC_IER)); | ||
239 | break; /* SNDRV_PCM_TRIGGER_START */ | ||
240 | |||
241 | case SNDRV_PCM_TRIGGER_STOP: | ||
242 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
243 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
244 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
245 | params->mask->pdc_disable); | ||
246 | break; | ||
247 | |||
248 | case SNDRV_PCM_TRIGGER_RESUME: | ||
249 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
250 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
251 | params->mask->pdc_enable); | ||
252 | break; | ||
253 | |||
254 | default: | ||
255 | ret = -EINVAL; | ||
256 | } | ||
257 | |||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | static snd_pcm_uframes_t atmel_pcm_pointer( | ||
262 | struct snd_pcm_substream *substream) | ||
263 | { | ||
264 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
265 | struct atmel_runtime_data *prtd = runtime->private_data; | ||
266 | struct atmel_pcm_dma_params *params = prtd->params; | ||
267 | dma_addr_t ptr; | ||
268 | snd_pcm_uframes_t x; | ||
269 | |||
270 | ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
271 | x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); | ||
272 | |||
273 | if (x == runtime->buffer_size) | ||
274 | x = 0; | ||
275 | |||
276 | return x; | ||
277 | } | ||
278 | |||
279 | static int atmel_pcm_open(struct snd_pcm_substream *substream) | ||
280 | { | ||
281 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
282 | struct atmel_runtime_data *prtd; | ||
283 | int ret = 0; | ||
284 | |||
285 | snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); | ||
286 | |||
287 | /* ensure that buffer size is a multiple of period size */ | ||
288 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
289 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
290 | if (ret < 0) | ||
291 | goto out; | ||
292 | |||
293 | prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); | ||
294 | if (prtd == NULL) { | ||
295 | ret = -ENOMEM; | ||
296 | goto out; | ||
297 | } | ||
298 | runtime->private_data = prtd; | ||
299 | |||
300 | out: | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | static int atmel_pcm_close(struct snd_pcm_substream *substream) | ||
305 | { | ||
306 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
307 | |||
308 | kfree(prtd); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static struct snd_pcm_ops atmel_pcm_ops = { | ||
313 | .open = atmel_pcm_open, | ||
314 | .close = atmel_pcm_close, | ||
315 | .ioctl = snd_pcm_lib_ioctl, | ||
316 | .hw_params = atmel_pcm_hw_params, | ||
317 | .hw_free = atmel_pcm_hw_free, | ||
318 | .prepare = atmel_pcm_prepare, | ||
319 | .trigger = atmel_pcm_trigger, | ||
320 | .pointer = atmel_pcm_pointer, | ||
321 | .mmap = atmel_pcm_mmap, | ||
322 | }; | ||
323 | |||
324 | |||
325 | /*--------------------------------------------------------------------------*\ | ||
326 | * ASoC platform driver | ||
327 | \*--------------------------------------------------------------------------*/ | ||
328 | #ifdef CONFIG_PM | ||
329 | static int atmel_pcm_suspend(struct snd_soc_dai *dai) | ||
330 | { | ||
331 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
332 | struct atmel_runtime_data *prtd; | ||
333 | struct atmel_pcm_dma_params *params; | ||
334 | |||
335 | if (!runtime) | ||
336 | return 0; | ||
337 | |||
338 | prtd = runtime->private_data; | ||
339 | params = prtd->params; | ||
340 | |||
341 | /* disable the PDC and save the PDC registers */ | ||
342 | |||
343 | ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); | ||
344 | |||
345 | prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
346 | prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); | ||
347 | prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); | ||
348 | prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int atmel_pcm_resume(struct snd_soc_dai *dai) | ||
354 | { | ||
355 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
356 | struct atmel_runtime_data *prtd; | ||
357 | struct atmel_pcm_dma_params *params; | ||
358 | |||
359 | if (!runtime) | ||
360 | return 0; | ||
361 | |||
362 | prtd = runtime->private_data; | ||
363 | params = prtd->params; | ||
364 | |||
365 | /* restore the PDC registers and enable the PDC */ | ||
366 | ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); | ||
367 | ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); | ||
368 | ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); | ||
369 | ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); | ||
370 | |||
371 | ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); | ||
372 | return 0; | ||
373 | } | ||
374 | #else | ||
375 | #define atmel_pcm_suspend NULL | ||
376 | #define atmel_pcm_resume NULL | ||
377 | #endif | ||
378 | |||
379 | static struct snd_soc_platform_driver atmel_soc_platform = { | ||
380 | .ops = &atmel_pcm_ops, | ||
381 | .pcm_new = atmel_pcm_new, | ||
382 | .pcm_free = atmel_pcm_free, | ||
383 | .suspend = atmel_pcm_suspend, | ||
384 | .resume = atmel_pcm_resume, | ||
385 | }; | ||
386 | |||
387 | int atmel_pcm_pdc_platform_register(struct device *dev) | ||
388 | { | ||
389 | return snd_soc_register_platform(dev, &atmel_soc_platform); | ||
390 | } | ||
391 | EXPORT_SYMBOL(atmel_pcm_pdc_platform_register); | ||
392 | |||
393 | void atmel_pcm_pdc_platform_unregister(struct device *dev) | ||
394 | { | ||
395 | snd_soc_unregister_platform(dev); | ||
396 | } | ||
397 | EXPORT_SYMBOL(atmel_pcm_pdc_platform_unregister); | ||
398 | |||
399 | MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); | ||
400 | MODULE_DESCRIPTION("Atmel PCM module"); | ||
401 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index 40e17d13d78a..e99f1811300a 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c | |||
@@ -32,80 +32,25 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/init.h> | ||
36 | #include <linux/platform_device.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
39 | #include <linux/atmel_pdc.h> | ||
40 | #include <linux/atmel-ssc.h> | ||
41 | |||
42 | #include <sound/core.h> | ||
43 | #include <sound/pcm.h> | 36 | #include <sound/pcm.h> |
44 | #include <sound/pcm_params.h> | ||
45 | #include <sound/soc.h> | 37 | #include <sound/soc.h> |
46 | |||
47 | #include "atmel-pcm.h" | 38 | #include "atmel-pcm.h" |
48 | 39 | ||
49 | |||
50 | /*--------------------------------------------------------------------------*\ | ||
51 | * Hardware definition | ||
52 | \*--------------------------------------------------------------------------*/ | ||
53 | /* TODO: These values were taken from the AT91 platform driver, check | ||
54 | * them against real values for AT32 | ||
55 | */ | ||
56 | static const struct snd_pcm_hardware atmel_pcm_hardware = { | ||
57 | .info = SNDRV_PCM_INFO_MMAP | | ||
58 | SNDRV_PCM_INFO_MMAP_VALID | | ||
59 | SNDRV_PCM_INFO_INTERLEAVED | | ||
60 | SNDRV_PCM_INFO_PAUSE, | ||
61 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
62 | .period_bytes_min = 32, | ||
63 | .period_bytes_max = 8192, | ||
64 | .periods_min = 2, | ||
65 | .periods_max = 1024, | ||
66 | .buffer_bytes_max = 32 * 1024, | ||
67 | }; | ||
68 | |||
69 | |||
70 | /*--------------------------------------------------------------------------*\ | ||
71 | * Data types | ||
72 | \*--------------------------------------------------------------------------*/ | ||
73 | struct atmel_runtime_data { | ||
74 | struct atmel_pcm_dma_params *params; | ||
75 | dma_addr_t dma_buffer; /* physical address of dma buffer */ | ||
76 | dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */ | ||
77 | size_t period_size; | ||
78 | |||
79 | dma_addr_t period_ptr; /* physical address of next period */ | ||
80 | |||
81 | /* PDC register save */ | ||
82 | u32 pdc_xpr_save; | ||
83 | u32 pdc_xcr_save; | ||
84 | u32 pdc_xnpr_save; | ||
85 | u32 pdc_xncr_save; | ||
86 | }; | ||
87 | |||
88 | |||
89 | /*--------------------------------------------------------------------------*\ | ||
90 | * Helper functions | ||
91 | \*--------------------------------------------------------------------------*/ | ||
92 | static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, | 40 | static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, |
93 | int stream) | 41 | int stream) |
94 | { | 42 | { |
95 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | 43 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; |
96 | struct snd_dma_buffer *buf = &substream->dma_buffer; | 44 | struct snd_dma_buffer *buf = &substream->dma_buffer; |
97 | size_t size = atmel_pcm_hardware.buffer_bytes_max; | 45 | size_t size = ATMEL_SSC_DMABUF_SIZE; |
98 | 46 | ||
99 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | 47 | buf->dev.type = SNDRV_DMA_TYPE_DEV; |
100 | buf->dev.dev = pcm->card->dev; | 48 | buf->dev.dev = pcm->card->dev; |
101 | buf->private_data = NULL; | 49 | buf->private_data = NULL; |
102 | buf->area = dma_alloc_coherent(pcm->card->dev, size, | 50 | buf->area = dma_alloc_coherent(pcm->card->dev, size, |
103 | &buf->addr, GFP_KERNEL); | 51 | &buf->addr, GFP_KERNEL); |
104 | pr_debug("atmel-pcm:" | 52 | pr_debug("atmel-pcm: alloc dma buffer: area=%p, addr=%p, size=%d\n", |
105 | "preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", | 53 | (void *)buf->area, (void *)buf->addr, size); |
106 | (void *) buf->area, | ||
107 | (void *) buf->addr, | ||
108 | size); | ||
109 | 54 | ||
110 | if (!buf->area) | 55 | if (!buf->area) |
111 | return -ENOMEM; | 56 | return -ENOMEM; |
@@ -113,258 +58,19 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, | |||
113 | buf->bytes = size; | 58 | buf->bytes = size; |
114 | return 0; | 59 | return 0; |
115 | } | 60 | } |
116 | /*--------------------------------------------------------------------------*\ | ||
117 | * ISR | ||
118 | \*--------------------------------------------------------------------------*/ | ||
119 | static void atmel_pcm_dma_irq(u32 ssc_sr, | ||
120 | struct snd_pcm_substream *substream) | ||
121 | { | ||
122 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
123 | struct atmel_pcm_dma_params *params = prtd->params; | ||
124 | static int count; | ||
125 | |||
126 | count++; | ||
127 | |||
128 | if (ssc_sr & params->mask->ssc_endbuf) { | ||
129 | pr_warning("atmel-pcm: buffer %s on %s" | ||
130 | " (SSC_SR=%#x, count=%d)\n", | ||
131 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK | ||
132 | ? "underrun" : "overrun", | ||
133 | params->name, ssc_sr, count); | ||
134 | |||
135 | /* re-start the PDC */ | ||
136 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
137 | params->mask->pdc_disable); | ||
138 | prtd->period_ptr += prtd->period_size; | ||
139 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
140 | prtd->period_ptr = prtd->dma_buffer; | ||
141 | |||
142 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
143 | prtd->period_ptr); | ||
144 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
145 | prtd->period_size / params->pdc_xfer_size); | ||
146 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
147 | params->mask->pdc_enable); | ||
148 | } | ||
149 | |||
150 | if (ssc_sr & params->mask->ssc_endx) { | ||
151 | /* Load the PDC next pointer and counter registers */ | ||
152 | prtd->period_ptr += prtd->period_size; | ||
153 | if (prtd->period_ptr >= prtd->dma_buffer_end) | ||
154 | prtd->period_ptr = prtd->dma_buffer; | ||
155 | |||
156 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
157 | prtd->period_ptr); | ||
158 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
159 | prtd->period_size / params->pdc_xfer_size); | ||
160 | } | ||
161 | |||
162 | snd_pcm_period_elapsed(substream); | ||
163 | } | ||
164 | |||
165 | |||
166 | /*--------------------------------------------------------------------------*\ | ||
167 | * PCM operations | ||
168 | \*--------------------------------------------------------------------------*/ | ||
169 | static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, | ||
170 | struct snd_pcm_hw_params *params) | ||
171 | { | ||
172 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
173 | struct atmel_runtime_data *prtd = runtime->private_data; | ||
174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
175 | |||
176 | /* this may get called several times by oss emulation | ||
177 | * with different params */ | ||
178 | |||
179 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
180 | runtime->dma_bytes = params_buffer_bytes(params); | ||
181 | |||
182 | prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
183 | prtd->params->dma_intr_handler = atmel_pcm_dma_irq; | ||
184 | |||
185 | prtd->dma_buffer = runtime->dma_addr; | ||
186 | prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes; | ||
187 | prtd->period_size = params_period_bytes(params); | ||
188 | |||
189 | pr_debug("atmel-pcm: " | ||
190 | "hw_params: DMA for %s initialized " | ||
191 | "(dma_bytes=%u, period_size=%u)\n", | ||
192 | prtd->params->name, | ||
193 | runtime->dma_bytes, | ||
194 | prtd->period_size); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int atmel_pcm_hw_free(struct snd_pcm_substream *substream) | ||
199 | { | ||
200 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
201 | struct atmel_pcm_dma_params *params = prtd->params; | ||
202 | |||
203 | if (params != NULL) { | ||
204 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
205 | params->mask->pdc_disable); | ||
206 | prtd->params->dma_intr_handler = NULL; | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int atmel_pcm_prepare(struct snd_pcm_substream *substream) | ||
213 | { | ||
214 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
215 | struct atmel_pcm_dma_params *params = prtd->params; | ||
216 | |||
217 | ssc_writex(params->ssc->regs, SSC_IDR, | ||
218 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
219 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
220 | params->mask->pdc_disable); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int atmel_pcm_trigger(struct snd_pcm_substream *substream, | ||
225 | int cmd) | ||
226 | { | ||
227 | struct snd_pcm_runtime *rtd = substream->runtime; | ||
228 | struct atmel_runtime_data *prtd = rtd->private_data; | ||
229 | struct atmel_pcm_dma_params *params = prtd->params; | ||
230 | int ret = 0; | ||
231 | |||
232 | pr_debug("atmel-pcm:buffer_size = %ld," | ||
233 | "dma_area = %p, dma_bytes = %u\n", | ||
234 | rtd->buffer_size, rtd->dma_area, rtd->dma_bytes); | ||
235 | |||
236 | switch (cmd) { | ||
237 | case SNDRV_PCM_TRIGGER_START: | ||
238 | prtd->period_ptr = prtd->dma_buffer; | ||
239 | |||
240 | ssc_writex(params->ssc->regs, params->pdc->xpr, | ||
241 | prtd->period_ptr); | ||
242 | ssc_writex(params->ssc->regs, params->pdc->xcr, | ||
243 | prtd->period_size / params->pdc_xfer_size); | ||
244 | |||
245 | prtd->period_ptr += prtd->period_size; | ||
246 | ssc_writex(params->ssc->regs, params->pdc->xnpr, | ||
247 | prtd->period_ptr); | ||
248 | ssc_writex(params->ssc->regs, params->pdc->xncr, | ||
249 | prtd->period_size / params->pdc_xfer_size); | ||
250 | |||
251 | pr_debug("atmel-pcm: trigger: " | ||
252 | "period_ptr=%lx, xpr=%u, " | ||
253 | "xcr=%u, xnpr=%u, xncr=%u\n", | ||
254 | (unsigned long)prtd->period_ptr, | ||
255 | ssc_readx(params->ssc->regs, params->pdc->xpr), | ||
256 | ssc_readx(params->ssc->regs, params->pdc->xcr), | ||
257 | ssc_readx(params->ssc->regs, params->pdc->xnpr), | ||
258 | ssc_readx(params->ssc->regs, params->pdc->xncr)); | ||
259 | |||
260 | ssc_writex(params->ssc->regs, SSC_IER, | ||
261 | params->mask->ssc_endx | params->mask->ssc_endbuf); | ||
262 | ssc_writex(params->ssc->regs, SSC_PDC_PTCR, | ||
263 | params->mask->pdc_enable); | ||
264 | |||
265 | pr_debug("sr=%u imr=%u\n", | ||
266 | ssc_readx(params->ssc->regs, SSC_SR), | ||
267 | ssc_readx(params->ssc->regs, SSC_IER)); | ||
268 | break; /* SNDRV_PCM_TRIGGER_START */ | ||
269 | |||
270 | case SNDRV_PCM_TRIGGER_STOP: | ||
271 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
272 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
273 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
274 | params->mask->pdc_disable); | ||
275 | break; | ||
276 | |||
277 | case SNDRV_PCM_TRIGGER_RESUME: | ||
278 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
279 | ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR, | ||
280 | params->mask->pdc_enable); | ||
281 | break; | ||
282 | 61 | ||
283 | default: | 62 | int atmel_pcm_mmap(struct snd_pcm_substream *substream, |
284 | ret = -EINVAL; | ||
285 | } | ||
286 | |||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | static snd_pcm_uframes_t atmel_pcm_pointer( | ||
291 | struct snd_pcm_substream *substream) | ||
292 | { | ||
293 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
294 | struct atmel_runtime_data *prtd = runtime->private_data; | ||
295 | struct atmel_pcm_dma_params *params = prtd->params; | ||
296 | dma_addr_t ptr; | ||
297 | snd_pcm_uframes_t x; | ||
298 | |||
299 | ptr = (dma_addr_t) ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
300 | x = bytes_to_frames(runtime, ptr - prtd->dma_buffer); | ||
301 | |||
302 | if (x == runtime->buffer_size) | ||
303 | x = 0; | ||
304 | |||
305 | return x; | ||
306 | } | ||
307 | |||
308 | static int atmel_pcm_open(struct snd_pcm_substream *substream) | ||
309 | { | ||
310 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
311 | struct atmel_runtime_data *prtd; | ||
312 | int ret = 0; | ||
313 | |||
314 | snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware); | ||
315 | |||
316 | /* ensure that buffer size is a multiple of period size */ | ||
317 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
318 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
319 | if (ret < 0) | ||
320 | goto out; | ||
321 | |||
322 | prtd = kzalloc(sizeof(struct atmel_runtime_data), GFP_KERNEL); | ||
323 | if (prtd == NULL) { | ||
324 | ret = -ENOMEM; | ||
325 | goto out; | ||
326 | } | ||
327 | runtime->private_data = prtd; | ||
328 | |||
329 | out: | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | static int atmel_pcm_close(struct snd_pcm_substream *substream) | ||
334 | { | ||
335 | struct atmel_runtime_data *prtd = substream->runtime->private_data; | ||
336 | |||
337 | kfree(prtd); | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int atmel_pcm_mmap(struct snd_pcm_substream *substream, | ||
342 | struct vm_area_struct *vma) | 63 | struct vm_area_struct *vma) |
343 | { | 64 | { |
344 | return remap_pfn_range(vma, vma->vm_start, | 65 | return remap_pfn_range(vma, vma->vm_start, |
345 | substream->dma_buffer.addr >> PAGE_SHIFT, | 66 | substream->dma_buffer.addr >> PAGE_SHIFT, |
346 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | 67 | vma->vm_end - vma->vm_start, vma->vm_page_prot); |
347 | } | 68 | } |
69 | EXPORT_SYMBOL_GPL(atmel_pcm_mmap); | ||
348 | 70 | ||
349 | static struct snd_pcm_ops atmel_pcm_ops = { | ||
350 | .open = atmel_pcm_open, | ||
351 | .close = atmel_pcm_close, | ||
352 | .ioctl = snd_pcm_lib_ioctl, | ||
353 | .hw_params = atmel_pcm_hw_params, | ||
354 | .hw_free = atmel_pcm_hw_free, | ||
355 | .prepare = atmel_pcm_prepare, | ||
356 | .trigger = atmel_pcm_trigger, | ||
357 | .pointer = atmel_pcm_pointer, | ||
358 | .mmap = atmel_pcm_mmap, | ||
359 | }; | ||
360 | |||
361 | |||
362 | /*--------------------------------------------------------------------------*\ | ||
363 | * ASoC platform driver | ||
364 | \*--------------------------------------------------------------------------*/ | ||
365 | static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32); | 71 | static u64 atmel_pcm_dmamask = DMA_BIT_MASK(32); |
366 | 72 | ||
367 | static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) | 73 | int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) |
368 | { | 74 | { |
369 | struct snd_card *card = rtd->card->snd_card; | 75 | struct snd_card *card = rtd->card->snd_card; |
370 | struct snd_pcm *pcm = rtd->pcm; | 76 | struct snd_pcm *pcm = rtd->pcm; |
@@ -376,6 +82,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
376 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | 82 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); |
377 | 83 | ||
378 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { | 84 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { |
85 | pr_debug("atmel-pcm: allocating PCM playback DMA buffer\n"); | ||
379 | ret = atmel_pcm_preallocate_dma_buffer(pcm, | 86 | ret = atmel_pcm_preallocate_dma_buffer(pcm, |
380 | SNDRV_PCM_STREAM_PLAYBACK); | 87 | SNDRV_PCM_STREAM_PLAYBACK); |
381 | if (ret) | 88 | if (ret) |
@@ -383,8 +90,7 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
383 | } | 90 | } |
384 | 91 | ||
385 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | 92 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { |
386 | pr_debug("atmel-pcm:" | 93 | pr_debug("atmel-pcm: allocating PCM capture DMA buffer\n"); |
387 | "Allocating PCM capture DMA buffer\n"); | ||
388 | ret = atmel_pcm_preallocate_dma_buffer(pcm, | 94 | ret = atmel_pcm_preallocate_dma_buffer(pcm, |
389 | SNDRV_PCM_STREAM_CAPTURE); | 95 | SNDRV_PCM_STREAM_CAPTURE); |
390 | if (ret) | 96 | if (ret) |
@@ -393,8 +99,9 @@ static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
393 | out: | 99 | out: |
394 | return ret; | 100 | return ret; |
395 | } | 101 | } |
102 | EXPORT_SYMBOL_GPL(atmel_pcm_new); | ||
396 | 103 | ||
397 | static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) | 104 | void atmel_pcm_free(struct snd_pcm *pcm) |
398 | { | 105 | { |
399 | struct snd_pcm_substream *substream; | 106 | struct snd_pcm_substream *substream; |
400 | struct snd_dma_buffer *buf; | 107 | struct snd_dma_buffer *buf; |
@@ -413,78 +120,5 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
413 | buf->area = NULL; | 120 | buf->area = NULL; |
414 | } | 121 | } |
415 | } | 122 | } |
123 | EXPORT_SYMBOL_GPL(atmel_pcm_free); | ||
416 | 124 | ||
417 | #ifdef CONFIG_PM | ||
418 | static int atmel_pcm_suspend(struct snd_soc_dai *dai) | ||
419 | { | ||
420 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
421 | struct atmel_runtime_data *prtd; | ||
422 | struct atmel_pcm_dma_params *params; | ||
423 | |||
424 | if (!runtime) | ||
425 | return 0; | ||
426 | |||
427 | prtd = runtime->private_data; | ||
428 | params = prtd->params; | ||
429 | |||
430 | /* disable the PDC and save the PDC registers */ | ||
431 | |||
432 | ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable); | ||
433 | |||
434 | prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr); | ||
435 | prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr); | ||
436 | prtd->pdc_xnpr_save = ssc_readx(params->ssc->regs, params->pdc->xnpr); | ||
437 | prtd->pdc_xncr_save = ssc_readx(params->ssc->regs, params->pdc->xncr); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int atmel_pcm_resume(struct snd_soc_dai *dai) | ||
443 | { | ||
444 | struct snd_pcm_runtime *runtime = dai->runtime; | ||
445 | struct atmel_runtime_data *prtd; | ||
446 | struct atmel_pcm_dma_params *params; | ||
447 | |||
448 | if (!runtime) | ||
449 | return 0; | ||
450 | |||
451 | prtd = runtime->private_data; | ||
452 | params = prtd->params; | ||
453 | |||
454 | /* restore the PDC registers and enable the PDC */ | ||
455 | ssc_writex(params->ssc->regs, params->pdc->xpr, prtd->pdc_xpr_save); | ||
456 | ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save); | ||
457 | ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save); | ||
458 | ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save); | ||
459 | |||
460 | ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable); | ||
461 | return 0; | ||
462 | } | ||
463 | #else | ||
464 | #define atmel_pcm_suspend NULL | ||
465 | #define atmel_pcm_resume NULL | ||
466 | #endif | ||
467 | |||
468 | static struct snd_soc_platform_driver atmel_soc_platform = { | ||
469 | .ops = &atmel_pcm_ops, | ||
470 | .pcm_new = atmel_pcm_new, | ||
471 | .pcm_free = atmel_pcm_free_dma_buffers, | ||
472 | .suspend = atmel_pcm_suspend, | ||
473 | .resume = atmel_pcm_resume, | ||
474 | }; | ||
475 | |||
476 | int atmel_pcm_platform_register(struct device *dev) | ||
477 | { | ||
478 | return snd_soc_register_platform(dev, &atmel_soc_platform); | ||
479 | } | ||
480 | EXPORT_SYMBOL(atmel_pcm_platform_register); | ||
481 | |||
482 | void atmel_pcm_platform_unregister(struct device *dev) | ||
483 | { | ||
484 | snd_soc_unregister_platform(dev); | ||
485 | } | ||
486 | EXPORT_SYMBOL(atmel_pcm_platform_unregister); | ||
487 | |||
488 | MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); | ||
489 | MODULE_DESCRIPTION("Atmel PCM module"); | ||
490 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h index e6d67b3dddd1..6bd63b0e95e2 100644 --- a/sound/soc/atmel/atmel-pcm.h +++ b/sound/soc/atmel/atmel-pcm.h | |||
@@ -36,6 +36,8 @@ | |||
36 | 36 | ||
37 | #include <linux/atmel-ssc.h> | 37 | #include <linux/atmel-ssc.h> |
38 | 38 | ||
39 | #define ATMEL_SSC_DMABUF_SIZE (64 * 1024) | ||
40 | |||
39 | /* | 41 | /* |
40 | * Registers and status bits that are required by the PCM driver. | 42 | * Registers and status bits that are required by the PCM driver. |
41 | */ | 43 | */ |
@@ -80,7 +82,22 @@ struct atmel_pcm_dma_params { | |||
80 | #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) | 82 | #define ssc_readx(base, reg) (__raw_readl((base) + (reg))) |
81 | #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) | 83 | #define ssc_writex(base, reg, value) __raw_writel((value), (base) + (reg)) |
82 | 84 | ||
83 | int atmel_pcm_platform_register(struct device *dev); | 85 | int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd); |
84 | void atmel_pcm_platform_unregister(struct device *dev); | 86 | void atmel_pcm_free(struct snd_pcm *pcm); |
87 | int atmel_pcm_mmap(struct snd_pcm_substream *substream, | ||
88 | struct vm_area_struct *vma); | ||
89 | |||
90 | #ifdef CONFIG_SND_ATMEL_SOC_PDC | ||
91 | int atmel_pcm_pdc_platform_register(struct device *dev); | ||
92 | void atmel_pcm_pdc_platform_unregister(struct device *dev); | ||
93 | #else | ||
94 | static inline int atmel_pcm_pdc_platform_register(struct device *dev) | ||
95 | { | ||
96 | return 0; | ||
97 | } | ||
98 | static inline void atmel_pcm_pdc_platform_unregister(struct device *dev) | ||
99 | { | ||
100 | } | ||
101 | #endif | ||
85 | 102 | ||
86 | #endif /* _ATMEL_PCM_H */ | 103 | #endif /* _ATMEL_PCM_H */ |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 7932c052b736..170561407f61 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -729,7 +729,7 @@ static int asoc_ssc_init(struct device *dev) | |||
729 | goto err; | 729 | goto err; |
730 | } | 730 | } |
731 | 731 | ||
732 | ret = atmel_pcm_platform_register(dev); | 732 | ret = atmel_pcm_pdc_platform_register(dev); |
733 | if (ret) { | 733 | if (ret) { |
734 | dev_err(dev, "Could not register PCM: %d\n", ret); | 734 | dev_err(dev, "Could not register PCM: %d\n", ret); |
735 | goto err_unregister_dai; | 735 | goto err_unregister_dai; |
@@ -745,7 +745,7 @@ err: | |||
745 | 745 | ||
746 | static void asoc_ssc_exit(struct device *dev) | 746 | static void asoc_ssc_exit(struct device *dev) |
747 | { | 747 | { |
748 | atmel_pcm_platform_unregister(dev); | 748 | atmel_pcm_pdc_platform_unregister(dev); |
749 | snd_soc_unregister_dai(dev); | 749 | snd_soc_unregister_dai(dev); |
750 | } | 750 | } |
751 | 751 | ||