aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorFrank Mandarino <fmandarino@endrelia.com>2006-10-06 12:40:25 -0400
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:00:29 -0500
commit0cbbec0984f10f216ed8332e0d39ac93cbe33a0b (patch)
tree91778619d942206c6bbd28344983bb3327bf38ab /sound
parentff9abf5b0a655b59d59ea61aec5be6285bf3ac30 (diff)
[ALSA] ASoC AT91RM92000 I2S support
This patch adds I2S support to the Atmel AT91RM9200 CPU. Features:- o Playback/Capture supported. o 16 Bit data size. o 8k - 48k sample rates. o ssc0, ssc1 and ssc2 supported as I2S ports. Signed-off-by: Frank Mandarino <fmandarino@endrelia.com> Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/at91/at91rm9200-i2s.c688
1 files changed, 688 insertions, 0 deletions
diff --git a/sound/soc/at91/at91rm9200-i2s.c b/sound/soc/at91/at91rm9200-i2s.c
new file mode 100644
index 000000000000..a74c5d85589b
--- /dev/null
+++ b/sound/soc/at91/at91rm9200-i2s.c
@@ -0,0 +1,688 @@
1/*
2 * at91rm9200-i2s.c -- ALSA Soc Audio Layer Platform driver and DMA engine
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 * Revision history
16 * 3rd Mar 2006 Initial version.
17 */
18
19#include <linux/init.h>
20#include <linux/module.h>
21#include <linux/interrupt.h>
22#include <linux/device.h>
23#include <linux/delay.h>
24#include <linux/clk.h>
25#include <sound/driver.h>
26#include <sound/core.h>
27#include <sound/pcm.h>
28#include <sound/initval.h>
29#include <sound/soc.h>
30
31#include <asm/arch/at91rm9200.h>
32#include <asm/arch/at91rm9200_ssc.h>
33#include <asm/arch/at91rm9200_pdc.h>
34#include <asm/arch/hardware.h>
35
36#include "at91rm9200-pcm.h"
37
38#if 0
39#define DBG(x...) printk(KERN_DEBUG "at91rm9200-i2s:" x)
40#else
41#define DBG(x...)
42#endif
43
44#define AT91RM9200_I2S_DAIFMT \
45 (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_NB_NF)
46
47#define AT91RM9200_I2S_DIR \
48 (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
49
50/* priv is (SSC_CMR.DIV << 16 | SSC_TCMR.PERIOD ) */
51static struct snd_soc_dai_mode at91rm9200_i2s[] = {
52
53 /* 8k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */
54 { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0),
55 SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_8000, AT91RM9200_I2S_DIR,
56 SND_SOC_DAI_BFS_DIV, 1500, SND_SOC_FSBD(10), (25 << 16 | 74) },
57
58 /* 16k: BCLK = (MCLK/3) ~= (60MHz/14) = 4.285714MHz */
59 { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0),
60 SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_16000, AT91RM9200_I2S_DIR,
61 SND_SOC_DAI_BFS_DIV, 750, SND_SOC_FSBD(3) , (7 << 16 | 133) },
62
63 /* 24k: BCLK = (MCLK/10) = (60MHz/50) = 1.2MHz */
64 { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0),
65 SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_22050, AT91RM9200_I2S_DIR,
66 SND_SOC_DAI_BFS_DIV, 500, SND_SOC_FSBD(10), (25 << 16 | 24) },
67
68 /* 48kHz: BCLK = (MCLK/5) ~= (60MHz/26) = 2.3076923MHz */
69 { AT91RM9200_I2S_DAIFMT, SND_SOC_DAITDM_LRDW(0,0),
70 SNDRV_PCM_FMTBIT_S16_LE, SNDRV_PCM_RATE_48000, AT91RM9200_I2S_DIR,
71 SND_SOC_DAI_BFS_DIV, 250, SND_SOC_FSBD(5), (13 << 16 | 23) },
72};
73
74
75/*
76 * SSC registers required by the PCM DMA engine.
77 */
78static struct at91rm9200_ssc_regs ssc_reg[3] = {
79 {
80 .cr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_CR),
81 .ier = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_IER),
82 .idr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_SSC_IDR),
83 },
84 {
85 .cr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_CR),
86 .ier = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_IER),
87 .idr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_SSC_IDR),
88 },
89 {
90 .cr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_CR),
91 .ier = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_IER),
92 .idr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_SSC_IDR),
93 },
94};
95
96static struct at91rm9200_pdc_regs pdc_tx_reg[3] = {
97 {
98 .xpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TPR),
99 .xcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TCR),
100 .xnpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TNPR),
101 .xncr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_TNCR),
102 .ptcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_PTCR),
103 },
104 {
105 .xpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TPR),
106 .xcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TCR),
107 .xnpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TNPR),
108 .xncr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_TNCR),
109 .ptcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_PTCR),
110 },
111 {
112 .xpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TPR),
113 .xcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TCR),
114 .xnpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TNPR),
115 .xncr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_TNCR),
116 .ptcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_PTCR),
117 },
118};
119
120static struct at91rm9200_pdc_regs pdc_rx_reg[3] = {
121 {
122 .xpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RPR),
123 .xcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RCR),
124 .xnpr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RNPR),
125 .xncr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_RNCR),
126 .ptcr = (void __iomem *) (AT91_VA_BASE_SSC0 + AT91_PDC_PTCR),
127 },
128 {
129 .xpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RPR),
130 .xcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RCR),
131 .xnpr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RNPR),
132 .xncr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_RNCR),
133 .ptcr = (void __iomem *) (AT91_VA_BASE_SSC1 + AT91_PDC_PTCR),
134 },
135 {
136 .xpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RPR),
137 .xcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RCR),
138 .xnpr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RNPR),
139 .xncr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_RNCR),
140 .ptcr = (void __iomem *) (AT91_VA_BASE_SSC2 + AT91_PDC_PTCR),
141 },
142};
143
144/*
145 * SSC & PDC status bits for transmit and receive.
146 */
147static struct at91rm9200_ssc_mask ssc_tx_mask = {
148 .ssc_enable = AT91_SSC_TXEN,
149 .ssc_disable = AT91_SSC_TXDIS,
150 .ssc_endx = AT91_SSC_ENDTX,
151 .ssc_endbuf = AT91_SSC_TXBUFE,
152 .pdc_enable = AT91_PDC_TXTEN,
153 .pdc_disable = AT91_PDC_TXTDIS,
154};
155
156static struct at91rm9200_ssc_mask ssc_rx_mask = {
157 .ssc_enable = AT91_SSC_RXEN,
158 .ssc_disable = AT91_SSC_RXDIS,
159 .ssc_endx = AT91_SSC_ENDRX,
160 .ssc_endbuf = AT91_SSC_RXBUFF,
161 .pdc_enable = AT91_PDC_RXTEN,
162 .pdc_disable = AT91_PDC_RXTDIS,
163};
164
165/*
166 * A MUTEX is used to protect an SSC initialzed flag which allows
167 * the substream hw_params() call to initialize the SSC only if
168 * there are no other substreams open. If there are other
169 * substreams open, the hw_param() call can only check that
170 * it is using the same format and rate.
171 */
172static DECLARE_MUTEX(ssc0_mutex);
173static DECLARE_MUTEX(ssc1_mutex);
174static DECLARE_MUTEX(ssc2_mutex);
175
176/*
177 * DMA parameters.
178 */
179static at91rm9200_pcm_dma_params_t ssc_dma_params[3][2] = {
180 {{
181 .name = "SSC0/I2S PCM Stereo out",
182 .ssc = &ssc_reg[0],
183 .pdc = &pdc_tx_reg[0],
184 .mask = &ssc_tx_mask,
185 },
186 {
187 .name = "SSC0/I2S PCM Stereo in",
188 .ssc = &ssc_reg[0],
189 .pdc = &pdc_rx_reg[0],
190 .mask = &ssc_rx_mask,
191 }},
192 {{
193 .name = "SSC1/I2S PCM Stereo out",
194 .ssc = &ssc_reg[1],
195 .pdc = &pdc_tx_reg[1],
196 .mask = &ssc_tx_mask,
197 },
198 {
199 .name = "SSC1/I2S PCM Stereo in",
200 .ssc = &ssc_reg[1],
201 .pdc = &pdc_rx_reg[1],
202 .mask = &ssc_rx_mask,
203 }},
204 {{
205 .name = "SSC2/I2S PCM Stereo out",
206 .ssc = &ssc_reg[2],
207 .pdc = &pdc_tx_reg[2],
208 .mask = &ssc_tx_mask,
209 },
210 {
211 .name = "SSC1/I2S PCM Stereo in",
212 .ssc = &ssc_reg[2],
213 .pdc = &pdc_rx_reg[2],
214 .mask = &ssc_rx_mask,
215 }},
216};
217
218
219struct at91rm9200_ssc_state {
220 u32 ssc_cmr;
221 u32 ssc_rcmr;
222 u32 ssc_rfmr;
223 u32 ssc_tcmr;
224 u32 ssc_tfmr;
225 u32 ssc_sr;
226 u32 ssc_imr;
227};
228
229static struct at91rm9200_ssc_info {
230 char *name;
231 void __iomem *ssc_base;
232 u32 pid;
233 spinlock_t lock; /* lock for dir_mask */
234 int dir_mask; /* 0=unused, 1=playback, 2=capture */
235 struct semaphore *mutex;
236 int initialized;
237 int pcmfmt;
238 int rate;
239 at91rm9200_pcm_dma_params_t *dma_params[2];
240 struct at91rm9200_ssc_state ssc_state;
241
242} ssc_info[3] = {
243 {
244 .name = "ssc0",
245 .ssc_base = (void __iomem *) AT91_VA_BASE_SSC0,
246 .pid = AT91_ID_SSC0,
247 .lock = SPIN_LOCK_UNLOCKED,
248 .dir_mask = 0,
249 .mutex = &ssc0_mutex,
250 .initialized = 0,
251 },
252 {
253 .name = "ssc1",
254 .ssc_base = (void __iomem *) AT91_VA_BASE_SSC1,
255 .pid = AT91_ID_SSC1,
256 .lock = SPIN_LOCK_UNLOCKED,
257 .dir_mask = 0,
258 .mutex = &ssc1_mutex,
259 .initialized = 0,
260 },
261 {
262 .name = "ssc2",
263 .ssc_base = (void __iomem *) AT91_VA_BASE_SSC2,
264 .pid = AT91_ID_SSC2,
265 .lock = SPIN_LOCK_UNLOCKED,
266 .dir_mask = 0,
267 .mutex = &ssc2_mutex,
268 .initialized = 0,
269 },
270};
271
272
273static int at91rm9200_i2s_interrupt(int irq, void *dev_id,
274 struct pt_regs *regs)
275{
276 struct at91rm9200_ssc_info *ssc_p = dev_id;
277 at91rm9200_pcm_dma_params_t *dma_params;
278 u32 ssc_sr;
279 int i;
280
281 ssc_sr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR)
282 & at91_ssc_read(ssc_p->ssc_base + AT91_SSC_IMR);
283
284 /*
285 * Loop through the substreams attached to this SSC. If
286 * a DMA-related interrupt occurred on that substream, call
287 * the DMA interrupt handler function, if one has been
288 * registered in the dma_params structure by the PCM driver.
289 */
290 for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
291 dma_params = ssc_p->dma_params[i];
292
293 if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
294 (ssc_sr &
295 (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
296
297 dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
298 }
299
300 return IRQ_HANDLED;
301}
302
303static int at91rm9200_i2s_startup(struct snd_pcm_substream *substream)
304{
305 struct snd_soc_pcm_runtime *rtd = substream->private_data;
306 struct at91rm9200_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id];
307 int dir_mask;
308
309 DBG("i2s_startup: SSC_SR=0x%08lx\n",
310 at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR));
311 dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
312
313 spin_lock_irq(&ssc_p->lock);
314 if (ssc_p->dir_mask & dir_mask) {
315 spin_unlock_irq(&ssc_p->lock);
316 return -EBUSY;
317 }
318 ssc_p->dir_mask |= dir_mask;
319 spin_unlock_irq(&ssc_p->lock);
320
321 return 0;
322}
323
324static void at91rm9200_i2s_shutdown(struct snd_pcm_substream *substream)
325{
326 struct snd_soc_pcm_runtime *rtd = substream->private_data;
327 struct at91rm9200_ssc_info *ssc_p = &ssc_info[rtd->cpu_dai->id];
328 at91rm9200_pcm_dma_params_t *dma_params = rtd->cpu_dai->dma_data;
329 int dir, dir_mask;
330
331 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
332
333 if (dma_params != NULL) {
334 at91_ssc_write(dma_params->ssc->cr, dma_params->mask->ssc_disable);
335 DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
336 at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR));
337
338 dma_params->substream = NULL;
339 ssc_p->dma_params[dir] = NULL;
340 }
341
342 dir_mask = 1 << dir;
343
344 spin_lock_irq(&ssc_p->lock);
345 ssc_p->dir_mask &= ~dir_mask;
346 if (!ssc_p->dir_mask) {
347 /* Shutdown the SSC clock. */
348 DBG("Stopping pid %d clock\n", ssc_p->pid);
349 at91_sys_write(AT91_PMC_PCDR, ssc_p->pid);
350
351 if (ssc_p->initialized)
352 free_irq(ssc_p->pid, ssc_p);
353
354 /* Reset the SSC */
355 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, AT91_SSC_SWRST);
356
357 /* Force a re-init on the next hw_params() call. */
358 ssc_p->initialized = 0;
359 }
360 spin_unlock_irq(&ssc_p->lock);
361}
362
363#ifdef CONFIG_PM
364static int at91rm9200_i2s_suspend(struct platform_device *pdev,
365 struct snd_soc_cpu_dai *dai)
366{
367 struct at91rm9200_ssc_info *ssc_p;
368
369 if(!dai->active)
370 return 0;
371
372 ssc_p = &ssc_info[dai->id];
373
374 /* Save the status register before disabling transmit and receive. */
375 ssc_p->state->ssc_sr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_SR);
376 at91_ssc_write(ssc_p->ssc_base +
377 AT91_SSC_CR, AT91_SSC_TXDIS | AT91_SSC_RXDIS);
378
379 /* Save the current interrupt mask, then disable unmasked interrupts. */
380 ssc_p->state->ssc_imr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_IMR);
381 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_IDR, ssc_p->state->ssc_imr);
382
383 ssc_p->state->ssc_cmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_CMR);
384 ssc_p->state->ssc_rcmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR);
385 ssc_p->state->ssc_rfmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR);
386 ssc_p->state->ssc_tcmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR);
387 ssc_p->state->ssc_tfmr = at91_ssc_read(ssc_p->ssc_base + AT91_SSC_RCMR);
388
389 return 0;
390}
391
392static int at91rm9200_i2s_resume(struct platform_device *pdev,
393 struct snd_soc_cpu_dai *dai)
394{
395 struct at91rm9200_ssc_info *ssc_p;
396 u32 cr_mask;
397
398 if(!dai->active)
399 return 0;
400
401 ssc_p = &ssc_info[dai->id];
402
403 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_tfmr);
404 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_tcmr);
405 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_rfmr);
406 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, ssc_p->state->ssc_rcmr);
407 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CMR, ssc_p->state->ssc_cmr);
408
409 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_IER, ssc_p->state->ssc_imr);
410
411 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR,
412 ((ssc_p->state->ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
413 ((ssc_p->state->ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
414
415 return 0;
416}
417
418#else
419#define at91rm9200_i2s_suspend NULL
420#define at91rm9200_i2s_resume NULL
421#endif
422
423static unsigned int at91rm9200_i2s_config_sysclk(
424 struct snd_soc_cpu_dai *iface, struct snd_soc_clock_info *info,
425 unsigned int clk)
426{
427 /* Currently, there is only support for USB (12Mhz) mode */
428 if (clk != 12000000)
429 return 0;
430 return 12000000;
431}
432
433static int at91rm9200_i2s_hw_params(struct snd_pcm_substream *substream,
434 struct snd_pcm_hw_params *params)
435{
436 struct snd_soc_pcm_runtime *rtd = substream->private_data;
437 int id = rtd->cpu_dai->id;
438 struct at91rm9200_ssc_info *ssc_p = &ssc_info[id];
439 at91rm9200_pcm_dma_params_t *dma_params;
440 unsigned int pcmfmt, rate;
441 int dir, channels, bits;
442 struct clk *mck_clk;
443 unsigned long bclk;
444 u32 div, period, tfmr, rfmr, tcmr, rcmr;
445 int ret;
446
447 /*
448 * Currently, there is only one set of dma params for
449 * each direction. If more are added, this code will
450 * have to be changed to select the proper set.
451 */
452 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
453
454 dma_params = &ssc_dma_params[id][dir];
455 dma_params->substream = substream;
456
457 ssc_p->dma_params[dir] = dma_params;
458 rtd->cpu_dai->dma_data = dma_params;
459
460 rate = params_rate(params);
461 channels = params_channels(params);
462
463 pcmfmt = rtd->cpu_dai->dai_runtime.pcmfmt;
464 switch (pcmfmt) {
465 case SNDRV_PCM_FMTBIT_S16_LE:
466 /* likely this is all we'll ever support, but ... */
467 bits = 16;
468 dma_params->pdc_xfer_size = 2;
469 break;
470 default:
471 printk(KERN_WARNING "at91rm9200-i2s: unsupported format %x\n",
472 pcmfmt);
473 return -EINVAL;
474 }
475
476 /* Don't allow both SSC substreams to initialize at the same time. */
477 down(ssc_p->mutex);
478
479 /*
480 * If this SSC is alreadly initialized, then this substream must use
481 * the same format and rate.
482 */
483 if (ssc_p->initialized) {
484 if (pcmfmt != ssc_p->pcmfmt || rate != ssc_p->rate) {
485 printk(KERN_WARNING "at91rm9200-i2s: "
486 "incompatible substream in other direction\n");
487 up(ssc_p->mutex);
488 return -EINVAL;
489 }
490 } else {
491 /* Enable PMC peripheral clock for this SSC */
492 DBG("Starting pid %d clock\n", ssc_p->pid);
493 at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->pid);
494
495 /* Reset the SSC */
496 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CR, AT91_SSC_SWRST);
497
498 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RPR, 0);
499 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RCR, 0);
500 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RNPR, 0);
501 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_RNCR, 0);
502 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TPR, 0);
503 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TCR, 0);
504 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TNPR, 0);
505 at91_ssc_write(ssc_p->ssc_base + AT91_PDC_TNCR, 0);
506
507 mck_clk = clk_get(NULL, "mck");
508
509 div = rtd->cpu_dai->dai_runtime.priv >> 16;
510 period = rtd->cpu_dai->dai_runtime.priv & 0xffff;
511 bclk = 60000000 / (2 * div);
512
513 DBG("mck %ld fsbd %d bfs %d bfs_real %d bclk %ld div %d period %d\n",
514 clk_get_rate(mck_clk),
515 SND_SOC_FSBD(6),
516 rtd->cpu_dai->dai_runtime.bfs,
517 SND_SOC_FSBD_REAL(rtd->cpu_dai->dai_runtime.bfs),
518 bclk,
519 div,
520 period);
521
522 clk_put(mck_clk);
523
524 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_CMR, div);
525
526 /*
527 * Setup the TFMR and RFMR for the proper data format.
528 */
529 tfmr =
530 (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
531 | (( 0 << 23) & AT91_SSC_FSDEN)
532 | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
533 | (((bits - 1) << 16) & AT91_SSC_FSLEN)
534 | (((channels - 1) << 8) & AT91_SSC_DATNB)
535 | (( 1 << 7) & AT91_SSC_MSBF)
536 | (( 0 << 5) & AT91_SSC_DATDEF)
537 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
538 DBG("SSC_TFMR=0x%08x\n", tfmr);
539 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_TFMR, tfmr);
540
541 rfmr =
542 (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
543 | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
544 | (( 0 << 16) & AT91_SSC_FSLEN)
545 | (((channels - 1) << 8) & AT91_SSC_DATNB)
546 | (( 1 << 7) & AT91_SSC_MSBF)
547 | (( 0 << 5) & AT91_SSC_LOOP)
548 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
549
550 DBG("SSC_RFMR=0x%08x\n", rfmr);
551 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RFMR, rfmr);
552
553 /*
554 * Setup the TCMR and RCMR to generate the proper BCLK
555 * and LRC signals.
556 */
557 tcmr =
558 (( period << 24) & AT91_SSC_PERIOD)
559 | (( 1 << 16) & AT91_SSC_STTDLY)
560 | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
561 | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
562 | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO)
563 | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
564
565 DBG("SSC_TCMR=0x%08x\n", tcmr);
566 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_TCMR, tcmr);
567
568 rcmr =
569 (( 0 << 24) & AT91_SSC_PERIOD)
570 | (( 1 << 16) & AT91_SSC_STTDLY)
571 | (( AT91_SSC_START_TX_RX ) & AT91_SSC_START)
572 | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
573 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
574 | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS);
575
576 DBG("SSC_RCMR=0x%08x\n", rcmr);
577 at91_ssc_write(ssc_p->ssc_base + AT91_SSC_RCMR, rcmr);
578
579 if ((ret = request_irq(ssc_p->pid, at91rm9200_i2s_interrupt,
580 0, ssc_p->name, ssc_p)) < 0) {
581 printk(KERN_WARNING "at91rm9200-i2s: request_irq failure\n");
582 return ret;
583 }
584
585 /*
586 * Save the current substream parameters in order to check
587 * that the substream in the opposite direction uses the
588 * same parameters.
589 */
590 ssc_p->pcmfmt = pcmfmt;
591 ssc_p->rate = rate;
592 ssc_p->initialized = 1;
593
594 DBG("hw_params: SSC initialized\n");
595 }
596
597 up(ssc_p->mutex);
598
599 return 0;
600}
601
602
603static int at91rm9200_i2s_prepare(struct snd_pcm_substream *substream)
604{
605 struct snd_soc_pcm_runtime *rtd = substream->private_data;
606 at91rm9200_pcm_dma_params_t *dma_params = rtd->cpu_dai->dma_data;
607
608 at91_ssc_write(dma_params->ssc->cr, dma_params->mask->ssc_enable);
609
610 DBG("%s enabled SSC_SR=0x%08lx\n",
611 substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "transmit" : "receive",
612 at91_ssc_read(ssc_info[rtd->cpu_dai->id].ssc_base + AT91_SSC_SR));
613 return 0;
614}
615
616
617struct snd_soc_cpu_dai at91rm9200_i2s_dai[] = {
618 { .name = "at91rm9200-ssc0/i2s",
619 .id = 0,
620 .type = SND_SOC_DAI_I2S,
621 .suspend = at91rm9200_i2s_suspend,
622 .resume = at91rm9200_i2s_resume,
623 .config_sysclk = at91rm9200_i2s_config_sysclk,
624 .playback = {
625 .channels_min = 1,
626 .channels_max = 2,},
627 .capture = {
628 .channels_min = 1,
629 .channels_max = 2,},
630 .ops = {
631 .startup = at91rm9200_i2s_startup,
632 .shutdown = at91rm9200_i2s_shutdown,
633 .prepare = at91rm9200_i2s_prepare,
634 .hw_params = at91rm9200_i2s_hw_params,},
635 .caps = {
636 .mode = &at91rm9200_i2s[0],
637 .num_modes = ARRAY_SIZE(at91rm9200_i2s),},
638 },
639 { .name = "at91rm9200-ssc1/i2s",
640 .id = 1,
641 .type = SND_SOC_DAI_I2S,
642 .suspend = at91rm9200_i2s_suspend,
643 .resume = at91rm9200_i2s_resume,
644 .config_sysclk = at91rm9200_i2s_config_sysclk,
645 .playback = {
646 .channels_min = 1,
647 .channels_max = 2,},
648 .capture = {
649 .channels_min = 1,
650 .channels_max = 2,},
651 .ops = {
652 .startup = at91rm9200_i2s_startup,
653 .shutdown = at91rm9200_i2s_shutdown,
654 .prepare = at91rm9200_i2s_prepare,
655 .hw_params = at91rm9200_i2s_hw_params,},
656 .caps = {
657 .mode = &at91rm9200_i2s[0],
658 .num_modes = ARRAY_SIZE(at91rm9200_i2s),},
659 },
660 { .name = "at91rm9200-ssc2/i2s",
661 .id = 2,
662 .type = SND_SOC_DAI_I2S,
663 .suspend = at91rm9200_i2s_suspend,
664 .resume = at91rm9200_i2s_resume,
665 .config_sysclk = at91rm9200_i2s_config_sysclk,
666 .playback = {
667 .channels_min = 1,
668 .channels_max = 2,},
669 .capture = {
670 .channels_min = 1,
671 .channels_max = 2,},
672 .ops = {
673 .startup = at91rm9200_i2s_startup,
674 .shutdown = at91rm9200_i2s_shutdown,
675 .prepare = at91rm9200_i2s_prepare,
676 .hw_params = at91rm9200_i2s_hw_params,},
677 .caps = {
678 .mode = &at91rm9200_i2s[0],
679 .num_modes = ARRAY_SIZE(at91rm9200_i2s),},
680 },
681};
682
683EXPORT_SYMBOL_GPL(at91rm9200_i2s_dai);
684
685/* Module information */
686MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
687MODULE_DESCRIPTION("AT91RM9200 I2S ASoC Interface");
688MODULE_LICENSE("GPL");