aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/at91
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/at91')
-rw-r--r--sound/soc/at91/Kconfig32
-rw-r--r--sound/soc/at91/Makefile11
-rw-r--r--sound/soc/at91/at91-i2s.c720
-rw-r--r--sound/soc/at91/at91-i2s.h27
-rw-r--r--sound/soc/at91/at91-pcm.c432
-rw-r--r--sound/soc/at91/at91-pcm.h72
-rw-r--r--sound/soc/at91/eti_b1_wm8731.c375
7 files changed, 1669 insertions, 0 deletions
diff --git a/sound/soc/at91/Kconfig b/sound/soc/at91/Kconfig
new file mode 100644
index 000000000000..5bcf08b728b0
--- /dev/null
+++ b/sound/soc/at91/Kconfig
@@ -0,0 +1,32 @@
1menu "SoC Audio for the Atmel AT91"
2
3config SND_AT91_SOC
4 tristate "SoC Audio for the Atmel AT91 System-on-Chip"
5 depends on ARCH_AT91 && SND
6 select SND_PCM
7 help
8 Say Y or M if you want to add support for codecs attached to
9 the AT91 SSC interface. You will also need
10 to select the audio interfaces to support below.
11
12config SND_AT91_SOC_I2S
13 tristate
14
15config SND_AT91_SOC_ETI_B1_WM8731
16 tristate "SoC I2S Audio support for WM8731-based Endrelia ETI-B1 boards"
17 depends on SND_AT91_SOC && (MACH_ETI_B1 || MACH_ETI_C1)
18 select SND_AT91_SOC_I2S
19 select SND_SOC_WM8731
20 help
21 Say Y if you want to add support for SoC audio on WM8731-based
22 Endrelia Technologies Inc ETI-B1 or ETI-C1 boards.
23
24config SND_AT91_SOC_ETI_SLAVE
25 bool "Run codec in slave Mode on Endrelia boards"
26 depends on SND_AT91_SOC_ETI_B1_WM8731
27 default n
28 help
29 Say Y if you want to run with the AT91 SSC generating the BCLK
30 and LRC signals on Endrelia boards.
31
32endmenu
diff --git a/sound/soc/at91/Makefile b/sound/soc/at91/Makefile
new file mode 100644
index 000000000000..b77b01ab2028
--- /dev/null
+++ b/sound/soc/at91/Makefile
@@ -0,0 +1,11 @@
1# AT91 Platform Support
2snd-soc-at91-objs := at91-pcm.o
3snd-soc-at91-i2s-objs := at91-i2s.o
4
5obj-$(CONFIG_SND_AT91_SOC) += snd-soc-at91.o
6obj-$(CONFIG_SND_AT91_SOC_I2S) += snd-soc-at91-i2s.o
7
8# AT91 Machine Support
9snd-soc-eti-b1-wm8731-objs := eti_b1_wm8731.o
10
11obj-$(CONFIG_SND_AT91_SOC_ETI_B1_WM8731) += snd-soc-eti-b1-wm8731.o
diff --git a/sound/soc/at91/at91-i2s.c b/sound/soc/at91/at91-i2s.c
new file mode 100644
index 000000000000..fcc544a96ba3
--- /dev/null
+++ b/sound/soc/at91/at91-i2s.c
@@ -0,0 +1,720 @@
1/*
2 * at91-i2s.c -- ALSA SoC I2S Audio Layer Platform driver
3 *
4 * Author: Frank Mandarino <fmandarino@endrelia.com>
5 * Endrelia Technologies Inc.
6 *
7 * Based on pxa2xx Platform drivers by
8 * Liam Girdwood <liam.girdwood@wolfsonmicro.com>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#include <linux/init.h>
18#include <linux/module.h>
19#include <linux/interrupt.h>
20#include <linux/device.h>
21#include <linux/delay.h>
22#include <linux/clk.h>
23#include <sound/driver.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/initval.h>
27#include <sound/soc.h>
28
29#include <asm/arch/hardware.h>
30#include <asm/arch/at91_pmc.h>
31#include <asm/arch/at91_ssc.h>
32#include <asm/arch/at91_pdc.h>
33
34#include "at91-pcm.h"
35#include "at91-i2s.h"
36
37#if 0
38#define DBG(x...) printk(KERN_DEBUG "at91-i2s:" x)
39#else
40#define DBG(x...)
41#endif
42
43#if defined(CONFIG_ARCH_AT91SAM9260)
44#define NUM_SSC_DEVICES 1
45#else
46#define NUM_SSC_DEVICES 3
47#endif
48
49
50/*
51 * SSC PDC registers required by the PCM DMA engine.
52 */
53static struct at91_pdc_regs pdc_tx_reg = {
54 .xpr = AT91_PDC_TPR,
55 .xcr = AT91_PDC_TCR,
56 .xnpr = AT91_PDC_TNPR,
57 .xncr = AT91_PDC_TNCR,
58};
59
60static struct at91_pdc_regs pdc_rx_reg = {
61 .xpr = AT91_PDC_RPR,
62 .xcr = AT91_PDC_RCR,
63 .xnpr = AT91_PDC_RNPR,
64 .xncr = AT91_PDC_RNCR,
65};
66
67/*
68 * SSC & PDC status bits for transmit and receive.
69 */
70static struct at91_ssc_mask ssc_tx_mask = {
71 .ssc_enable = AT91_SSC_TXEN,
72 .ssc_disable = AT91_SSC_TXDIS,
73 .ssc_endx = AT91_SSC_ENDTX,
74 .ssc_endbuf = AT91_SSC_TXBUFE,
75 .pdc_enable = AT91_PDC_TXTEN,
76 .pdc_disable = AT91_PDC_TXTDIS,
77};
78
79static struct at91_ssc_mask ssc_rx_mask = {
80 .ssc_enable = AT91_SSC_RXEN,
81 .ssc_disable = AT91_SSC_RXDIS,
82 .ssc_endx = AT91_SSC_ENDRX,
83 .ssc_endbuf = AT91_SSC_RXBUFF,
84 .pdc_enable = AT91_PDC_RXTEN,
85 .pdc_disable = AT91_PDC_RXTDIS,
86};
87
88
89/*
90 * DMA parameters.
91 */
92static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
93 {{
94 .name = "SSC0/I2S PCM Stereo out",
95 .pdc = &pdc_tx_reg,
96 .mask = &ssc_tx_mask,
97 },
98 {
99 .name = "SSC0/I2S PCM Stereo in",
100 .pdc = &pdc_rx_reg,
101 .mask = &ssc_rx_mask,
102 }},
103#if NUM_SSC_DEVICES == 3
104 {{
105 .name = "SSC1/I2S PCM Stereo out",
106 .pdc = &pdc_tx_reg,
107 .mask = &ssc_tx_mask,
108 },
109 {
110 .name = "SSC1/I2S PCM Stereo in",
111 .pdc = &pdc_rx_reg,
112 .mask = &ssc_rx_mask,
113 }},
114 {{
115 .name = "SSC2/I2S PCM Stereo out",
116 .pdc = &pdc_tx_reg,
117 .mask = &ssc_tx_mask,
118 },
119 {
120 .name = "SSC1/I2S PCM Stereo in",
121 .pdc = &pdc_rx_reg,
122 .mask = &ssc_rx_mask,
123 }},
124#endif
125};
126
127struct at91_ssc_state {
128 u32 ssc_cmr;
129 u32 ssc_rcmr;
130 u32 ssc_rfmr;
131 u32 ssc_tcmr;
132 u32 ssc_tfmr;
133 u32 ssc_sr;
134 u32 ssc_imr;
135};
136
137static struct at91_ssc_info {
138 char *name;
139 struct at91_ssc_periph ssc;
140 spinlock_t lock; /* lock for dir_mask */
141 unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */
142 unsigned short initialized; /* 1=SSC has been initialized */
143 unsigned short daifmt;
144 unsigned short cmr_div;
145 unsigned short tcmr_period;
146 unsigned short rcmr_period;
147 struct at91_pcm_dma_params *dma_params[2];
148 struct at91_ssc_state ssc_state;
149
150} ssc_info[NUM_SSC_DEVICES] = {
151 {
152 .name = "ssc0",
153 .lock = SPIN_LOCK_UNLOCKED,
154 .dir_mask = 0,
155 .initialized = 0,
156 },
157#if NUM_SSC_DEVICES == 3
158 {
159 .name = "ssc1",
160 .lock = SPIN_LOCK_UNLOCKED,
161 .dir_mask = 0,
162 .initialized = 0,
163 },
164 {
165 .name = "ssc2",
166 .lock = SPIN_LOCK_UNLOCKED,
167 .dir_mask = 0,
168 .initialized = 0,
169 },
170#endif
171};
172
173static unsigned int at91_i2s_sysclk;
174
175/*
176 * SSC interrupt handler. Passes PDC interrupts to the DMA
177 * interrupt handler in the PCM driver.
178 */
179static irqreturn_t at91_i2s_interrupt(int irq, void *dev_id)
180{
181 struct at91_ssc_info *ssc_p = dev_id;
182 struct at91_pcm_dma_params *dma_params;
183 u32 ssc_sr;
184 int i;
185
186 ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)
187 & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
188
189 /*
190 * Loop through the substreams attached to this SSC. If
191 * a DMA-related interrupt occurred on that substream, call
192 * the DMA interrupt handler function, if one has been
193 * registered in the dma_params structure by the PCM driver.
194 */
195 for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
196 dma_params = ssc_p->dma_params[i];
197
198 if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
199 (ssc_sr &
200 (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
201
202 dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
203 }
204
205 return IRQ_HANDLED;
206}
207
208/*
209 * Startup. Only that one substream allowed in each direction.
210 */
211static int at91_i2s_startup(struct snd_pcm_substream *substream)
212{
213 struct snd_soc_pcm_runtime *rtd = substream->private_data;
214 struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
215 int dir_mask;
216
217 DBG("i2s_startup: SSC_SR=0x%08lx\n",
218 at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
219 dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
220
221 spin_lock_irq(&ssc_p->lock);
222 if (ssc_p->dir_mask & dir_mask) {
223 spin_unlock_irq(&ssc_p->lock);
224 return -EBUSY;
225 }
226 ssc_p->dir_mask |= dir_mask;
227 spin_unlock_irq(&ssc_p->lock);
228
229 return 0;
230}
231
232/*
233 * Shutdown. Clear DMA parameters and shutdown the SSC if there
234 * are no other substreams open.
235 */
236static void at91_i2s_shutdown(struct snd_pcm_substream *substream)
237{
238 struct snd_soc_pcm_runtime *rtd = substream->private_data;
239 struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
240 struct at91_pcm_dma_params *dma_params;
241 int dir, dir_mask;
242
243 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
244 dma_params = ssc_p->dma_params[dir];
245
246 if (dma_params != NULL) {
247 at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
248 dma_params->mask->ssc_disable);
249 DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
250 at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
251
252 dma_params->ssc_base = NULL;
253 dma_params->substream = NULL;
254 ssc_p->dma_params[dir] = NULL;
255 }
256
257 dir_mask = 1 << dir;
258
259 spin_lock_irq(&ssc_p->lock);
260 ssc_p->dir_mask &= ~dir_mask;
261 if (!ssc_p->dir_mask) {
262 /* Shutdown the SSC clock. */
263 DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
264 at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
265
266 if (ssc_p->initialized) {
267 free_irq(ssc_p->ssc.pid, ssc_p);
268 ssc_p->initialized = 0;
269 }
270
271 /* Reset the SSC */
272 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
273
274 /* Clear the SSC dividers */
275 ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
276 }
277 spin_unlock_irq(&ssc_p->lock);
278}
279
280/*
281 * Record the SSC system clock rate.
282 */
283static int at91_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
284 int clk_id, unsigned int freq, int dir)
285{
286 /*
287 * The only clock supplied to the SSC is the AT91 master clock,
288 * which is only used if the SSC is generating BCLK and/or
289 * LRC clocks.
290 */
291 switch (clk_id) {
292 case AT91_SYSCLK_MCK:
293 at91_i2s_sysclk = freq;
294 break;
295 default:
296 return -EINVAL;
297 }
298
299 return 0;
300}
301
302/*
303 * Record the DAI format for use in hw_params().
304 */
305static int at91_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
306 unsigned int fmt)
307{
308 struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
309
310 if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) != SND_SOC_DAIFMT_I2S)
311 return -EINVAL;
312
313 ssc_p->daifmt = fmt;
314 return 0;
315}
316
317/*
318 * Record SSC clock dividers for use in hw_params().
319 */
320static int at91_i2s_set_dai_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
321 int div_id, int div)
322{
323 struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
324
325 switch (div_id) {
326 case AT91SSC_CMR_DIV:
327 /*
328 * The same master clock divider is used for both
329 * transmit and receive, so if a value has already
330 * been set, it must match this value.
331 */
332 if (ssc_p->cmr_div == 0)
333 ssc_p->cmr_div = div;
334 else
335 if (div != ssc_p->cmr_div)
336 return -EBUSY;
337 break;
338
339 case AT91SSC_TCMR_PERIOD:
340 ssc_p->tcmr_period = div;
341 break;
342
343 case AT91SSC_RCMR_PERIOD:
344 ssc_p->rcmr_period = div;
345 break;
346
347 default:
348 return -EINVAL;
349 }
350
351 return 0;
352}
353
354/*
355 * Configure the SSC.
356 */
357static int at91_i2s_hw_params(struct snd_pcm_substream *substream,
358 struct snd_pcm_hw_params *params)
359{
360 struct snd_soc_pcm_runtime *rtd = substream->private_data;
361 int id = rtd->dai->cpu_dai->id;
362 struct at91_ssc_info *ssc_p = &ssc_info[id];
363 struct at91_pcm_dma_params *dma_params;
364 int dir, channels, bits;
365 u32 tfmr, rfmr, tcmr, rcmr;
366 int start_event;
367 int ret;
368
369 /*
370 * Currently, there is only one set of dma params for
371 * each direction. If more are added, this code will
372 * have to be changed to select the proper set.
373 */
374 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
375
376 dma_params = &ssc_dma_params[id][dir];
377 dma_params->ssc_base = ssc_p->ssc.base;
378 dma_params->substream = substream;
379
380 ssc_p->dma_params[dir] = dma_params;
381
382 /*
383 * The cpu_dai->dma_data field is only used to communicate the
384 * appropriate DMA parameters to the pcm driver hw_params()
385 * function. It should not be used for other purposes
386 * as it is common to all substreams.
387 */
388 rtd->dai->cpu_dai->dma_data = dma_params;
389
390 channels = params_channels(params);
391
392 /*
393 * The SSC only supports up to 16-bit samples in I2S format, due
394 * to the size of the Frame Mode Register FSLEN field. Also, I2S
395 * implies signed data.
396 */
397 bits = 16;
398 dma_params->pdc_xfer_size = 2;
399
400 /*
401 * Compute SSC register settings.
402 */
403 switch (ssc_p->daifmt) {
404 case SND_SOC_DAIFMT_CBS_CFS:
405 /*
406 * SSC provides BCLK and LRC clocks.
407 *
408 * The SSC transmit and receive clocks are generated from the
409 * MCK divider, and the BCLK signal is output on the SSC TK line.
410 */
411 rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD)
412 | (( 1 << 16) & AT91_SSC_STTDLY)
413 | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
414 | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
415 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
416 | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
417
418 rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
419 | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
420 | (((bits - 1) << 16) & AT91_SSC_FSLEN)
421 | (((channels - 1) << 8) & AT91_SSC_DATNB)
422 | (( 1 << 7) & AT91_SSC_MSBF)
423 | (( 0 << 5) & AT91_SSC_LOOP)
424 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
425
426 tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD)
427 | (( 1 << 16) & AT91_SSC_STTDLY)
428 | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
429 | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
430 | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO)
431 | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
432
433 tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
434 | (( 0 << 23) & AT91_SSC_FSDEN)
435 | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
436 | (((bits - 1) << 16) & AT91_SSC_FSLEN)
437 | (((channels - 1) << 8) & AT91_SSC_DATNB)
438 | (( 1 << 7) & AT91_SSC_MSBF)
439 | (( 0 << 5) & AT91_SSC_DATDEF)
440 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
441 break;
442
443 case SND_SOC_DAIFMT_CBM_CFM:
444
445 /*
446 * CODEC supplies BCLK and LRC clocks.
447 *
448 * The SSC transmit clock is obtained from the BCLK signal on
449 * on the TK line, and the SSC receive clock is generated from the
450 * transmit clock.
451 *
452 * For single channel data, one sample is transferred on the falling
453 * edge of the LRC clock. For two channel data, one sample is
454 * transferred on both edges of the LRC clock.
455 */
456 start_event = channels == 1
457 ? AT91_SSC_START_FALLING_RF
458 : AT91_SSC_START_EDGE_RF;
459
460 rcmr = (( 0 << 24) & AT91_SSC_PERIOD)
461 | (( 1 << 16) & AT91_SSC_STTDLY)
462 | (( start_event ) & AT91_SSC_START)
463 | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
464 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
465 | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS);
466
467 rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
468 | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
469 | (( 0 << 16) & AT91_SSC_FSLEN)
470 | (( 0 << 8) & AT91_SSC_DATNB)
471 | (( 1 << 7) & AT91_SSC_MSBF)
472 | (( 0 << 5) & AT91_SSC_LOOP)
473 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
474
475 tcmr = (( 0 << 24) & AT91_SSC_PERIOD)
476 | (( 1 << 16) & AT91_SSC_STTDLY)
477 | (( start_event ) & AT91_SSC_START)
478 | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
479 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
480 | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS);
481
482 tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
483 | (( 0 << 23) & AT91_SSC_FSDEN)
484 | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
485 | (( 0 << 16) & AT91_SSC_FSLEN)
486 | (( 0 << 8) & AT91_SSC_DATNB)
487 | (( 1 << 7) & AT91_SSC_MSBF)
488 | (( 0 << 5) & AT91_SSC_DATDEF)
489 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
490 break;
491
492 case SND_SOC_DAIFMT_CBS_CFM:
493 case SND_SOC_DAIFMT_CBM_CFS:
494 default:
495 printk(KERN_WARNING "at91-i2s: unsupported DAI format 0x%x.\n",
496 ssc_p->daifmt);
497 return -EINVAL;
498 break;
499 }
500 DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr);
501
502 if (!ssc_p->initialized) {
503
504 /* Enable PMC peripheral clock for this SSC */
505 DBG("Starting pid %d clock\n", ssc_p->ssc.pid);
506 at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
507
508 /* Reset the SSC and its PDC registers */
509 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
510
511 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RPR, 0);
512 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RCR, 0);
513 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNPR, 0);
514 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_RNCR, 0);
515 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TPR, 0);
516 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TCR, 0);
517 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNPR, 0);
518 at91_ssc_write(ssc_p->ssc.base + AT91_PDC_TNCR, 0);
519
520 if ((ret = request_irq(ssc_p->ssc.pid, at91_i2s_interrupt,
521 0, ssc_p->name, ssc_p)) < 0) {
522 printk(KERN_WARNING "at91-i2s: request_irq failure\n");
523
524 DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
525 at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
526 return ret;
527 }
528
529 ssc_p->initialized = 1;
530 }
531
532 /* set SSC clock mode register */
533 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div);
534
535 /* set receive clock mode and format */
536 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);
537 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);
538
539 /* set transmit clock mode and format */
540 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);
541 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);
542
543 DBG("hw_params: SSC initialized\n");
544 return 0;
545}
546
547
548static int at91_i2s_prepare(struct snd_pcm_substream *substream)
549{
550 struct snd_soc_pcm_runtime *rtd = substream->private_data;
551 struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
552 struct at91_pcm_dma_params *dma_params;
553 int dir;
554
555 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
556 dma_params = ssc_p->dma_params[dir];
557
558 at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
559 dma_params->mask->ssc_enable);
560
561 DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit",
562 at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR));
563 return 0;
564}
565
566
567#ifdef CONFIG_PM
568static int at91_i2s_suspend(struct platform_device *pdev,
569 struct snd_soc_cpu_dai *cpu_dai)
570{
571 struct at91_ssc_info *ssc_p;
572
573 if(!cpu_dai->active)
574 return 0;
575
576 ssc_p = &ssc_info[cpu_dai->id];
577
578 /* Save the status register before disabling transmit and receive. */
579 ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);
580 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
581 AT91_SSC_TXDIS | AT91_SSC_RXDIS);
582
583 /* Save the current interrupt mask, then disable unmasked interrupts. */
584 ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
585 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr);
586
587 ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);
588 ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
589 ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR);
590 ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR);
591 ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR);
592
593 return 0;
594}
595
596static int at91_i2s_resume(struct platform_device *pdev,
597 struct snd_soc_cpu_dai *cpu_dai)
598{
599 struct at91_ssc_info *ssc_p;
600
601 if(!cpu_dai->active)
602 return 0;
603
604 ssc_p = &ssc_info[cpu_dai->id];
605
606 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr);
607 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr);
608 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr);
609 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr);
610 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr);
611
612 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr);
613
614 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
615 ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
616 ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
617
618 return 0;
619}
620
621#else
622#define at91_i2s_suspend NULL
623#define at91_i2s_resume NULL
624#endif
625
626#define AT91_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
627 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
628 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
629 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
630 SNDRV_PCM_RATE_96000)
631
632struct snd_soc_cpu_dai at91_i2s_dai[NUM_SSC_DEVICES] = {
633 { .name = "at91_ssc0/i2s",
634 .id = 0,
635 .type = SND_SOC_DAI_I2S,
636 .suspend = at91_i2s_suspend,
637 .resume = at91_i2s_resume,
638 .playback = {
639 .channels_min = 1,
640 .channels_max = 2,
641 .rates = AT91_I2S_RATES,
642 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
643 .capture = {
644 .channels_min = 1,
645 .channels_max = 2,
646 .rates = AT91_I2S_RATES,
647 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
648 .ops = {
649 .startup = at91_i2s_startup,
650 .shutdown = at91_i2s_shutdown,
651 .prepare = at91_i2s_prepare,
652 .hw_params = at91_i2s_hw_params,},
653 .dai_ops = {
654 .set_sysclk = at91_i2s_set_dai_sysclk,
655 .set_fmt = at91_i2s_set_dai_fmt,
656 .set_clkdiv = at91_i2s_set_dai_clkdiv,},
657 .private_data = &ssc_info[0].ssc,
658 },
659#if NUM_SSC_DEVICES == 3
660 { .name = "at91_ssc1/i2s",
661 .id = 1,
662 .type = SND_SOC_DAI_I2S,
663 .suspend = at91_i2s_suspend,
664 .resume = at91_i2s_resume,
665 .playback = {
666 .channels_min = 1,
667 .channels_max = 2,
668 .rates = AT91_I2S_RATES,
669 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
670 .capture = {
671 .channels_min = 1,
672 .channels_max = 2,
673 .rates = AT91_I2S_RATES,
674 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
675 .ops = {
676 .startup = at91_i2s_startup,
677 .shutdown = at91_i2s_shutdown,
678 .prepare = at91_i2s_prepare,
679 .hw_params = at91_i2s_hw_params,},
680 .dai_ops = {
681 .set_sysclk = at91_i2s_set_dai_sysclk,
682 .set_fmt = at91_i2s_set_dai_fmt,
683 .set_clkdiv = at91_i2s_set_dai_clkdiv,},
684 .private_data = &ssc_info[1].ssc,
685 },
686 { .name = "at91_ssc2/i2s",
687 .id = 2,
688 .type = SND_SOC_DAI_I2S,
689 .suspend = at91_i2s_suspend,
690 .resume = at91_i2s_resume,
691 .playback = {
692 .channels_min = 1,
693 .channels_max = 2,
694 .rates = AT91_I2S_RATES,
695 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
696 .capture = {
697 .channels_min = 1,
698 .channels_max = 2,
699 .rates = AT91_I2S_RATES,
700 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
701 .ops = {
702 .startup = at91_i2s_startup,
703 .shutdown = at91_i2s_shutdown,
704 .prepare = at91_i2s_prepare,
705 .hw_params = at91_i2s_hw_params,},
706 .dai_ops = {
707 .set_sysclk = at91_i2s_set_dai_sysclk,
708 .set_fmt = at91_i2s_set_dai_fmt,
709 .set_clkdiv = at91_i2s_set_dai_clkdiv,},
710 .private_data = &ssc_info[2].ssc,
711 },
712#endif
713};
714
715EXPORT_SYMBOL_GPL(at91_i2s_dai);
716
717/* Module information */
718MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
719MODULE_DESCRIPTION("AT91 I2S ASoC Interface");
720MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-i2s.h b/sound/soc/at91/at91-i2s.h
new file mode 100644
index 000000000000..f8a875ba0ccc
--- /dev/null
+++ b/sound/soc/at91/at91-i2s.h
@@ -0,0 +1,27 @@
1/*
2 * at91-i2s.h - ALSA I2S interface for the Atmel AT91 SoC
3 *
4 * Author: Frank Mandarino <fmandarino@endrelia.com>
5 * Endrelia Technologies Inc.
6 * Created: Jan 9, 2007
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
13#ifndef _AT91_I2S_H
14#define _AT91_I2S_H
15
16/* I2S system clock ids */
17#define AT91_SYSCLK_MCK 0 /* SSC uses AT91 MCK as system clock */
18
19/* I2S divider ids */
20#define AT91SSC_CMR_DIV 0 /* MCK divider for BCLK */
21#define AT91SSC_TCMR_PERIOD 1 /* BCLK divider for transmit FS */
22#define AT91SSC_RCMR_PERIOD 2 /* BCLK divider for receive FS */
23
24extern struct snd_soc_cpu_dai at91_i2s_dai[];
25
26#endif /* _AT91_I2S_H */
27
diff --git a/sound/soc/at91/at91-pcm.c b/sound/soc/at91/at91-pcm.c
new file mode 100644
index 000000000000..e88b12e7cc40
--- /dev/null
+++ b/sound/soc/at91/at91-pcm.c
@@ -0,0 +1,432 @@
1/*
2 * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC
3 *
4 * Author: Frank Mandarino <fmandarino@endrelia.com>
5 * Endrelia Technologies Inc.
6 * Created: Mar 3, 2006
7 *
8 * Based on pxa2xx-pcm.c by:
9 *
10 * Author: Nicolas Pitre
11 * Created: Nov 30, 2004
12 * Copyright: (C) 2004 MontaVista Software, Inc.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/dma-mapping.h>
24
25#include <sound/driver.h>
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include <sound/pcm_params.h>
29#include <sound/soc.h>
30
31#include <asm/arch/hardware.h>
32#include <asm/arch/at91_ssc.h>
33#include <asm/arch/at91_pdc.h>
34
35#include "at91-pcm.h"
36
37#if 0
38#define DBG(x...) printk(KERN_INFO "at91-pcm: " x)
39#else
40#define DBG(x...)
41#endif
42
43static const struct snd_pcm_hardware at91_pcm_hardware = {
44 .info = SNDRV_PCM_INFO_MMAP |
45 SNDRV_PCM_INFO_MMAP_VALID |
46 SNDRV_PCM_INFO_INTERLEAVED |
47 SNDRV_PCM_INFO_PAUSE,
48 .formats = SNDRV_PCM_FMTBIT_S16_LE,
49 .period_bytes_min = 32,
50 .period_bytes_max = 8192,
51 .periods_min = 2,
52 .periods_max = 1024,
53 .buffer_bytes_max = 32 * 1024,
54};
55
56struct at91_runtime_data {
57 struct at91_pcm_dma_params *params;
58 dma_addr_t dma_buffer; /* physical address of dma buffer */
59 dma_addr_t dma_buffer_end; /* first address beyond DMA buffer */
60 size_t period_size;
61 dma_addr_t period_ptr; /* physical address of next period */
62 u32 pdc_xpr_save; /* PDC register save */
63 u32 pdc_xcr_save;
64 u32 pdc_xnpr_save;
65 u32 pdc_xncr_save;
66};
67
68static void at91_pcm_dma_irq(u32 ssc_sr,
69 struct snd_pcm_substream *substream)
70{
71 struct at91_runtime_data *prtd = substream->runtime->private_data;
72 struct at91_pcm_dma_params *params = prtd->params;
73 static int count = 0;
74
75 count++;
76
77 if (ssc_sr & params->mask->ssc_endbuf) {
78
79 printk(KERN_WARNING
80 "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
81 substream->stream == SNDRV_PCM_STREAM_PLAYBACK
82 ? "underrun" : "overrun",
83 params->name, ssc_sr, count);
84
85 /* re-start the PDC */
86 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
87
88 prtd->period_ptr += prtd->period_size;
89 if (prtd->period_ptr >= prtd->dma_buffer_end) {
90 prtd->period_ptr = prtd->dma_buffer;
91 }
92
93 at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
94 at91_ssc_write(params->ssc_base + params->pdc->xcr,
95 prtd->period_size / params->pdc_xfer_size);
96
97 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
98 }
99
100 if (ssc_sr & params->mask->ssc_endx) {
101
102 /* Load the PDC next pointer and counter registers */
103 prtd->period_ptr += prtd->period_size;
104 if (prtd->period_ptr >= prtd->dma_buffer_end) {
105 prtd->period_ptr = prtd->dma_buffer;
106 }
107 at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
108 at91_ssc_write(params->ssc_base + params->pdc->xncr,
109 prtd->period_size / params->pdc_xfer_size);
110 }
111
112 snd_pcm_period_elapsed(substream);
113}
114
115static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
116 struct snd_pcm_hw_params *params)
117{
118 struct snd_pcm_runtime *runtime = substream->runtime;
119 struct at91_runtime_data *prtd = runtime->private_data;
120 struct snd_soc_pcm_runtime *rtd = substream->private_data;
121
122 /* this may get called several times by oss emulation
123 * with different params */
124
125 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
126 runtime->dma_bytes = params_buffer_bytes(params);
127
128 prtd->params = rtd->dai->cpu_dai->dma_data;
129 prtd->params->dma_intr_handler = at91_pcm_dma_irq;
130
131 prtd->dma_buffer = runtime->dma_addr;
132 prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
133 prtd->period_size = params_period_bytes(params);
134
135 DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
136 prtd->params->name, runtime->dma_bytes, prtd->period_size);
137 return 0;
138}
139
140static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
141{
142 struct at91_runtime_data *prtd = substream->runtime->private_data;
143 struct at91_pcm_dma_params *params = prtd->params;
144
145 if (params != NULL) {
146 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
147 prtd->params->dma_intr_handler = NULL;
148 }
149
150 return 0;
151}
152
153static int at91_pcm_prepare(struct snd_pcm_substream *substream)
154{
155 struct at91_runtime_data *prtd = substream->runtime->private_data;
156 struct at91_pcm_dma_params *params = prtd->params;
157
158 at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
159 params->mask->ssc_endx | params->mask->ssc_endbuf);
160
161 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
162 return 0;
163}
164
165static int at91_pcm_trigger(struct snd_pcm_substream *substream,
166 int cmd)
167{
168 struct at91_runtime_data *prtd = substream->runtime->private_data;
169 struct at91_pcm_dma_params *params = prtd->params;
170 int ret = 0;
171
172 switch (cmd) {
173 case SNDRV_PCM_TRIGGER_START:
174 prtd->period_ptr = prtd->dma_buffer;
175
176 at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
177 at91_ssc_write(params->ssc_base + params->pdc->xcr,
178 prtd->period_size / params->pdc_xfer_size);
179
180 prtd->period_ptr += prtd->period_size;
181 at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
182 at91_ssc_write(params->ssc_base + params->pdc->xncr,
183 prtd->period_size / params->pdc_xfer_size);
184
185 DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
186 (unsigned long) prtd->period_ptr,
187 at91_ssc_read(params->ssc_base + params->pdc->xpr),
188 at91_ssc_read(params->ssc_base + params->pdc->xcr),
189 at91_ssc_read(params->ssc_base + params->pdc->xnpr),
190 at91_ssc_read(params->ssc_base + params->pdc->xncr));
191
192 at91_ssc_write(params->ssc_base + AT91_SSC_IER,
193 params->mask->ssc_endx | params->mask->ssc_endbuf);
194
195 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
196
197 DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR),
198 at91_ssc_read(params->ssc_base + AT91_SSC_IER));
199 break;
200
201 case SNDRV_PCM_TRIGGER_STOP:
202 case SNDRV_PCM_TRIGGER_SUSPEND:
203 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
204 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
205 break;
206
207 case SNDRV_PCM_TRIGGER_RESUME:
208 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
209 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
210 break;
211
212 default:
213 ret = -EINVAL;
214 }
215
216 return ret;
217}
218
219static snd_pcm_uframes_t at91_pcm_pointer(
220 struct snd_pcm_substream *substream)
221{
222 struct snd_pcm_runtime *runtime = substream->runtime;
223 struct at91_runtime_data *prtd = runtime->private_data;
224 struct at91_pcm_dma_params *params = prtd->params;
225 dma_addr_t ptr;
226 snd_pcm_uframes_t x;
227
228 ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
229 x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
230
231 if (x == runtime->buffer_size)
232 x = 0;
233 return x;
234}
235
236static int at91_pcm_open(struct snd_pcm_substream *substream)
237{
238 struct snd_pcm_runtime *runtime = substream->runtime;
239 struct at91_runtime_data *prtd;
240 int ret = 0;
241
242 snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
243
244 /* ensure that buffer size is a multiple of period size */
245 ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
246 if (ret < 0)
247 goto out;
248
249 prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
250 if (prtd == NULL) {
251 ret = -ENOMEM;
252 goto out;
253 }
254 runtime->private_data = prtd;
255
256 out:
257 return ret;
258}
259
260static int at91_pcm_close(struct snd_pcm_substream *substream)
261{
262 struct at91_runtime_data *prtd = substream->runtime->private_data;
263
264 kfree(prtd);
265 return 0;
266}
267
268static int at91_pcm_mmap(struct snd_pcm_substream *substream,
269 struct vm_area_struct *vma)
270{
271 struct snd_pcm_runtime *runtime = substream->runtime;
272
273 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
274 runtime->dma_area,
275 runtime->dma_addr,
276 runtime->dma_bytes);
277}
278
279struct snd_pcm_ops at91_pcm_ops = {
280 .open = at91_pcm_open,
281 .close = at91_pcm_close,
282 .ioctl = snd_pcm_lib_ioctl,
283 .hw_params = at91_pcm_hw_params,
284 .hw_free = at91_pcm_hw_free,
285 .prepare = at91_pcm_prepare,
286 .trigger = at91_pcm_trigger,
287 .pointer = at91_pcm_pointer,
288 .mmap = at91_pcm_mmap,
289};
290
291static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
292 int stream)
293{
294 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
295 struct snd_dma_buffer *buf = &substream->dma_buffer;
296 size_t size = at91_pcm_hardware.buffer_bytes_max;
297
298 buf->dev.type = SNDRV_DMA_TYPE_DEV;
299 buf->dev.dev = pcm->card->dev;
300 buf->private_data = NULL;
301 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
302 &buf->addr, GFP_KERNEL);
303
304 DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
305 (void *) buf->area,
306 (void *) buf->addr,
307 size);
308
309 if (!buf->area)
310 return -ENOMEM;
311
312 buf->bytes = size;
313 return 0;
314}
315
316static u64 at91_pcm_dmamask = 0xffffffff;
317
318static int at91_pcm_new(struct snd_card *card,
319 struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
320{
321 int ret = 0;
322
323 if (!card->dev->dma_mask)
324 card->dev->dma_mask = &at91_pcm_dmamask;
325 if (!card->dev->coherent_dma_mask)
326 card->dev->coherent_dma_mask = 0xffffffff;
327
328 if (dai->playback.channels_min) {
329 ret = at91_pcm_preallocate_dma_buffer(pcm,
330 SNDRV_PCM_STREAM_PLAYBACK);
331 if (ret)
332 goto out;
333 }
334
335 if (dai->capture.channels_min) {
336 ret = at91_pcm_preallocate_dma_buffer(pcm,
337 SNDRV_PCM_STREAM_CAPTURE);
338 if (ret)
339 goto out;
340 }
341 out:
342 return ret;
343}
344
345static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
346{
347 struct snd_pcm_substream *substream;
348 struct snd_dma_buffer *buf;
349 int stream;
350
351 for (stream = 0; stream < 2; stream++) {
352 substream = pcm->streams[stream].substream;
353 if (!substream)
354 continue;
355
356 buf = &substream->dma_buffer;
357 if (!buf->area)
358 continue;
359
360 dma_free_writecombine(pcm->card->dev, buf->bytes,
361 buf->area, buf->addr);
362 buf->area = NULL;
363 }
364}
365
366#ifdef CONFIG_PM
367static int at91_pcm_suspend(struct platform_device *pdev,
368 struct snd_soc_cpu_dai *dai)
369{
370 struct snd_pcm_runtime *runtime = dai->runtime;
371 struct at91_runtime_data *prtd;
372 struct at91_pcm_dma_params *params;
373
374 if (!runtime)
375 return 0;
376
377 prtd = runtime->private_data;
378 params = prtd->params;
379
380 /* disable the PDC and save the PDC registers */
381
382 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_disable);
383
384 prtd->pdc_xpr_save = at91_ssc_read(params->ssc_base + params->pdc->xpr);
385 prtd->pdc_xcr_save = at91_ssc_read(params->ssc_base + params->pdc->xcr);
386 prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
387 prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
388
389 return 0;
390}
391
392static int at91_pcm_resume(struct platform_device *pdev,
393 struct snd_soc_cpu_dai *dai)
394{
395 struct snd_pcm_runtime *runtime = dai->runtime;
396 struct at91_runtime_data *prtd;
397 struct at91_pcm_dma_params *params;
398
399 if (!runtime)
400 return 0;
401
402 prtd = runtime->private_data;
403 params = prtd->params;
404
405 /* restore the PDC registers and enable the PDC */
406 at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->pdc_xpr_save);
407 at91_ssc_write(params->ssc_base + params->pdc->xcr, prtd->pdc_xcr_save);
408 at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
409 at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
410
411 at91_ssc_write(params->ssc_base + AT91_PDC_PTCR, params->mask->pdc_enable);
412 return 0;
413}
414#else
415#define at91_pcm_suspend NULL
416#define at91_pcm_resume NULL
417#endif
418
419struct snd_soc_platform at91_soc_platform = {
420 .name = "at91-audio",
421 .pcm_ops = &at91_pcm_ops,
422 .pcm_new = at91_pcm_new,
423 .pcm_free = at91_pcm_free_dma_buffers,
424 .suspend = at91_pcm_suspend,
425 .resume = at91_pcm_resume,
426};
427
428EXPORT_SYMBOL_GPL(at91_soc_platform);
429
430MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
431MODULE_DESCRIPTION("Atmel AT91 PCM module");
432MODULE_LICENSE("GPL");
diff --git a/sound/soc/at91/at91-pcm.h b/sound/soc/at91/at91-pcm.h
new file mode 100644
index 000000000000..58d0f00a07b2
--- /dev/null
+++ b/sound/soc/at91/at91-pcm.h
@@ -0,0 +1,72 @@
1/*
2 * at91-pcm.h - ALSA PCM interface for the Atmel AT91 SoC
3 *
4 * Author: Frank Mandarino <fmandarino@endrelia.com>
5 * Endrelia Technologies Inc.
6 * Created: Mar 3, 2006
7 *
8 * Based on pxa2xx-pcm.h by:
9 *
10 * Author: Nicolas Pitre
11 * Created: Nov 30, 2004
12 * Copyright: MontaVista Software, Inc.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
19#ifndef _AT91_PCM_H
20#define _AT91_PCM_H
21
22#include <asm/arch/hardware.h>
23
24struct at91_ssc_periph {
25 void __iomem *base;
26 u32 pid;
27};
28
29/*
30 * Registers and status bits that are required by the PCM driver.
31 */
32struct at91_pdc_regs {
33 unsigned int xpr; /* PDC recv/trans pointer */
34 unsigned int xcr; /* PDC recv/trans counter */
35 unsigned int xnpr; /* PDC next recv/trans pointer */
36 unsigned int xncr; /* PDC next recv/trans counter */
37 unsigned int ptcr; /* PDC transfer control */
38};
39
40struct at91_ssc_mask {
41 u32 ssc_enable; /* SSC recv/trans enable */
42 u32 ssc_disable; /* SSC recv/trans disable */
43 u32 ssc_endx; /* SSC ENDTX or ENDRX */
44 u32 ssc_endbuf; /* SSC TXBUFE or RXBUFF */
45 u32 pdc_enable; /* PDC recv/trans enable */
46 u32 pdc_disable; /* PDC recv/trans disable */
47};
48
49/*
50 * This structure, shared between the PCM driver and the interface,
51 * contains all information required by the PCM driver to perform the
52 * PDC DMA operation. All fields except dma_intr_handler() are initialized
53 * by the interface. The dms_intr_handler() pointer is set by the PCM
54 * driver and called by the interface SSC interrupt handler if it is
55 * non-NULL.
56 */
57struct at91_pcm_dma_params {
58 char *name; /* stream identifier */
59 int pdc_xfer_size; /* PDC counter increment in bytes */
60 void __iomem *ssc_base; /* SSC base address */
61 struct at91_pdc_regs *pdc; /* PDC receive or transmit registers */
62 struct at91_ssc_mask *mask;/* SSC & PDC status bits */
63 struct snd_pcm_substream *substream;
64 void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
65};
66
67extern struct snd_soc_platform at91_soc_platform;
68
69#define at91_ssc_read(a) ((unsigned long) __raw_readl(a))
70#define at91_ssc_write(a,v) __raw_writel((v),(a))
71
72#endif /* _AT91_PCM_H */
diff --git a/sound/soc/at91/eti_b1_wm8731.c b/sound/soc/at91/eti_b1_wm8731.c
new file mode 100644
index 000000000000..8179df3bb2f3
--- /dev/null
+++ b/sound/soc/at91/eti_b1_wm8731.c
@@ -0,0 +1,375 @@
1/*
2 * eti_b1_wm8731 -- SoC audio for AT91RM9200-based Endrelia ETI_B1 board.
3 *
4 * Author: Frank Mandarino <fmandarino@endrelia.com>
5 * Endrelia Technologies Inc.
6 * Created: Mar 29, 2006
7 *
8 * Based on corgi.c by:
9 *
10 * Copyright 2005 Wolfson Microelectronics PLC.
11 * Copyright 2005 Openedhand Ltd.
12 *
13 * Authors: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
14 * Richard Purdie <richard@openedhand.com>
15 *
16 * This program is free software; you can redistribute it and/or modify it
17 * under the terms of the GNU General Public License as published by the
18 * Free Software Foundation; either version 2 of the License, or (at your
19 * option) any later version.
20 *
21 */
22
23#include <linux/module.h>
24#include <linux/moduleparam.h>
25#include <linux/version.h>
26#include <linux/kernel.h>
27#include <linux/clk.h>
28#include <linux/timer.h>
29#include <linux/interrupt.h>
30#include <linux/platform_device.h>
31#include <sound/driver.h>
32#include <sound/core.h>
33#include <sound/pcm.h>
34#include <sound/soc.h>
35#include <sound/soc-dapm.h>
36
37#include <asm/arch/hardware.h>
38#include <asm/arch/at91_pio.h>
39#include <asm/arch/gpio.h>
40
41#include "../codecs/wm8731.h"
42#include "at91-pcm.h"
43#include "at91-i2s.h"
44
45#if 0
46#define DBG(x...) printk(KERN_INFO "eti_b1_wm8731: " x)
47#else
48#define DBG(x...)
49#endif
50
51#define AT91_PIO_TF1 (1 << (AT91_PIN_PB6 - PIN_BASE) % 32)
52#define AT91_PIO_TK1 (1 << (AT91_PIN_PB7 - PIN_BASE) % 32)
53#define AT91_PIO_TD1 (1 << (AT91_PIN_PB8 - PIN_BASE) % 32)
54#define AT91_PIO_RD1 (1 << (AT91_PIN_PB9 - PIN_BASE) % 32)
55#define AT91_PIO_RK1 (1 << (AT91_PIN_PB10 - PIN_BASE) % 32)
56#define AT91_PIO_RF1 (1 << (AT91_PIN_PB11 - PIN_BASE) % 32)
57
58static struct clk *pck1_clk;
59static struct clk *pllb_clk;
60
61
62static int eti_b1_startup(struct snd_pcm_substream *substream)
63{
64 struct snd_soc_pcm_runtime *rtd = substream->private_data;
65 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
66 struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
67 int ret;
68
69 /* cpu clock is the AT91 master clock sent to the SSC */
70 ret = cpu_dai->dai_ops.set_sysclk(cpu_dai, AT91_SYSCLK_MCK,
71 60000000, SND_SOC_CLOCK_IN);
72 if (ret < 0)
73 return ret;
74
75 /* codec system clock is supplied by PCK1, set to 12MHz */
76 ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8731_SYSCLK,
77 12000000, SND_SOC_CLOCK_IN);
78 if (ret < 0)
79 return ret;
80
81 /* Start PCK1 clock. */
82 clk_enable(pck1_clk);
83 DBG("pck1 started\n");
84
85 return 0;
86}
87
88static void eti_b1_shutdown(struct snd_pcm_substream *substream)
89{
90 /* Stop PCK1 clock. */
91 clk_disable(pck1_clk);
92 DBG("pck1 stopped\n");
93}
94
95static int eti_b1_hw_params(struct snd_pcm_substream *substream,
96 struct snd_pcm_hw_params *params)
97{
98 struct snd_soc_pcm_runtime *rtd = substream->private_data;
99 struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
100 struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
101 int ret;
102
103#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
104 unsigned int rate;
105 int cmr_div, period;
106
107 /* set codec DAI configuration */
108 ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
109 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
110 if (ret < 0)
111 return ret;
112
113 /* set cpu DAI configuration */
114 ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
115 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
116 if (ret < 0)
117 return ret;
118
119 /*
120 * The SSC clock dividers depend on the sample rate. The CMR.DIV
121 * field divides the system master clock MCK to drive the SSC TK
122 * signal which provides the codec BCLK. The TCMR.PERIOD and
123 * RCMR.PERIOD fields further divide the BCLK signal to drive
124 * the SSC TF and RF signals which provide the codec DACLRC and
125 * ADCLRC clocks.
126 *
127 * The dividers were determined through trial and error, where a
128 * CMR.DIV value is chosen such that the resulting BCLK value is
129 * divisible, or almost divisible, by (2 * sample rate), and then
130 * the TCMR.PERIOD or RCMR.PERIOD is BCLK / (2 * sample rate) - 1.
131 */
132 rate = params_rate(params);
133
134 switch (rate) {
135 case 8000:
136 cmr_div = 25; /* BCLK = 60MHz/(2*25) = 1.2MHz */
137 period = 74; /* LRC = BCLK/(2*(74+1)) = 8000Hz */
138 break;
139 case 32000:
140 cmr_div = 7; /* BCLK = 60MHz/(2*7) ~= 4.28571428MHz */
141 period = 66; /* LRC = BCLK/(2*(66+1)) = 31982.942Hz */
142 break;
143 case 48000:
144 cmr_div = 13; /* BCLK = 60MHz/(2*13) ~= 2.3076923MHz */
145 period = 23; /* LRC = BCLK/(2*(23+1)) = 48076.923Hz */
146 break;
147 default:
148 printk(KERN_WARNING "unsupported rate %d on ETI-B1 board\n", rate);
149 return -EINVAL;
150 }
151
152 /* set the MCK divider for BCLK */
153 ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, AT91SSC_CMR_DIV, cmr_div);
154 if (ret < 0)
155 return ret;
156
157 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
158 /* set the BCLK divider for DACLRC */
159 ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
160 AT91SSC_TCMR_PERIOD, period);
161 } else {
162 /* set the BCLK divider for ADCLRC */
163 ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai,
164 AT91SSC_RCMR_PERIOD, period);
165 }
166 if (ret < 0)
167 return ret;
168
169#else /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
170 /*
171 * Codec in Master Mode.
172 */
173
174 /* set codec DAI configuration */
175 ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
176 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
177 if (ret < 0)
178 return ret;
179
180 /* set cpu DAI configuration */
181 ret = cpu_dai->dai_ops.set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
182 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
183 if (ret < 0)
184 return ret;
185
186#endif /* CONFIG_SND_AT91_SOC_ETI_SLAVE */
187
188 return 0;
189}
190
191static struct snd_soc_ops eti_b1_ops = {
192 .startup = eti_b1_startup,
193 .hw_params = eti_b1_hw_params,
194 .shutdown = eti_b1_shutdown,
195};
196
197
198static const struct snd_soc_dapm_widget eti_b1_dapm_widgets[] = {
199 SND_SOC_DAPM_MIC("Int Mic", NULL),
200 SND_SOC_DAPM_SPK("Ext Spk", NULL),
201};
202
203static const char *intercon[][3] = {
204
205 /* speaker connected to LHPOUT */
206 {"Ext Spk", NULL, "LHPOUT"},
207
208 /* mic is connected to Mic Jack, with WM8731 Mic Bias */
209 {"MICIN", NULL, "Mic Bias"},
210 {"Mic Bias", NULL, "Int Mic"},
211
212 /* terminator */
213 {NULL, NULL, NULL},
214};
215
216/*
217 * Logic for a wm8731 as connected on a Endrelia ETI-B1 board.
218 */
219static int eti_b1_wm8731_init(struct snd_soc_codec *codec)
220{
221 int i;
222
223 DBG("eti_b1_wm8731_init() called\n");
224
225 /* Add specific widgets */
226 for(i = 0; i < ARRAY_SIZE(eti_b1_dapm_widgets); i++) {
227 snd_soc_dapm_new_control(codec, &eti_b1_dapm_widgets[i]);
228 }
229
230 /* Set up specific audio path interconnects */
231 for(i = 0; intercon[i][0] != NULL; i++) {
232 snd_soc_dapm_connect_input(codec, intercon[i][0],
233 intercon[i][1], intercon[i][2]);
234 }
235
236 /* not connected */
237 snd_soc_dapm_set_endpoint(codec, "RLINEIN", 0);
238 snd_soc_dapm_set_endpoint(codec, "LLINEIN", 0);
239
240 /* always connected */
241 snd_soc_dapm_set_endpoint(codec, "Int Mic", 1);
242 snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
243
244 snd_soc_dapm_sync_endpoints(codec);
245
246 return 0;
247}
248
249static struct snd_soc_dai_link eti_b1_dai = {
250 .name = "WM8731",
251 .stream_name = "WM8731",
252 .cpu_dai = &at91_i2s_dai[1],
253 .codec_dai = &wm8731_dai,
254 .init = eti_b1_wm8731_init,
255 .ops = &eti_b1_ops,
256};
257
258static struct snd_soc_machine snd_soc_machine_eti_b1 = {
259 .name = "ETI_B1",
260 .dai_link = &eti_b1_dai,
261 .num_links = 1,
262};
263
264static struct wm8731_setup_data eti_b1_wm8731_setup = {
265 .i2c_address = 0x1a,
266};
267
268static struct snd_soc_device eti_b1_snd_devdata = {
269 .machine = &snd_soc_machine_eti_b1,
270 .platform = &at91_soc_platform,
271 .codec_dev = &soc_codec_dev_wm8731,
272 .codec_data = &eti_b1_wm8731_setup,
273};
274
275static struct platform_device *eti_b1_snd_device;
276
277static int __init eti_b1_init(void)
278{
279 int ret;
280 u32 ssc_pio_lines;
281 struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
282
283 if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
284 DBG("SSC1 memory region is busy\n");
285 return -EBUSY;
286 }
287
288 ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
289 if (!ssc->base) {
290 DBG("SSC1 memory ioremap failed\n");
291 ret = -ENOMEM;
292 goto fail_release_mem;
293 }
294
295 ssc->pid = AT91RM9200_ID_SSC1;
296
297 eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
298 if (!eti_b1_snd_device) {
299 DBG("platform device allocation failed\n");
300 ret = -ENOMEM;
301 goto fail_io_unmap;
302 }
303
304 platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
305 eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
306
307 ret = platform_device_add(eti_b1_snd_device);
308 if (ret) {
309 DBG("platform device add failed\n");
310 platform_device_put(eti_b1_snd_device);
311 goto fail_io_unmap;
312 }
313
314 ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1
315 | AT91_PIO_RD1 /* | AT91_PIO_RK1 */ | AT91_PIO_RF1;
316
317 /* Reset all PIO registers and assign lines to peripheral A */
318 at91_sys_write(AT91_PIOB + PIO_PDR, ssc_pio_lines);
319 at91_sys_write(AT91_PIOB + PIO_ODR, ssc_pio_lines);
320 at91_sys_write(AT91_PIOB + PIO_IFDR, ssc_pio_lines);
321 at91_sys_write(AT91_PIOB + PIO_CODR, ssc_pio_lines);
322 at91_sys_write(AT91_PIOB + PIO_IDR, ssc_pio_lines);
323 at91_sys_write(AT91_PIOB + PIO_MDDR, ssc_pio_lines);
324 at91_sys_write(AT91_PIOB + PIO_PUDR, ssc_pio_lines);
325 at91_sys_write(AT91_PIOB + PIO_ASR, ssc_pio_lines);
326 at91_sys_write(AT91_PIOB + PIO_OWDR, ssc_pio_lines);
327
328 /*
329 * Set PCK1 parent to PLLB and its rate to 12 Mhz.
330 */
331 pllb_clk = clk_get(NULL, "pllb");
332 pck1_clk = clk_get(NULL, "pck1");
333
334 clk_set_parent(pck1_clk, pllb_clk);
335 clk_set_rate(pck1_clk, 12000000);
336
337 DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
338
339 /* assign the GPIO pin to PCK1 */
340 at91_set_B_periph(AT91_PIN_PA24, 0);
341
342#ifdef CONFIG_SND_AT91_SOC_ETI_SLAVE
343 printk(KERN_INFO "eti_b1_wm8731: Codec in Slave Mode\n");
344#else
345 printk(KERN_INFO "eti_b1_wm8731: Codec in Master Mode\n");
346#endif
347 return ret;
348
349fail_io_unmap:
350 iounmap(ssc->base);
351fail_release_mem:
352 release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
353 return ret;
354}
355
356static void __exit eti_b1_exit(void)
357{
358 struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
359
360 clk_put(pck1_clk);
361 clk_put(pllb_clk);
362
363 platform_device_unregister(eti_b1_snd_device);
364
365 iounmap(ssc->base);
366 release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
367}
368
369module_init(eti_b1_init);
370module_exit(eti_b1_exit);
371
372/* Module information */
373MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
374MODULE_DESCRIPTION("ALSA SoC ETI-B1-WM8731");
375MODULE_LICENSE("GPL");