blob: 5d44515e62e0b58e6d316e517d749bfd8cca681e [file] [log] [blame]
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +01001/*
Frank Mandarino36b8a8b2007-04-16 17:18:52 +02002 * at91-ssc.c -- ALSA SoC AT91 SSC Audio Layer Platform driver
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +01003 *
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 *
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010015 */
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>
Frank Mandarinofa8f8782007-02-12 14:06:22 +010023#include <linux/atmel_pdc.h>
24
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010025#include <sound/core.h>
26#include <sound/pcm.h>
Frank Mandarino36b8a8b2007-04-16 17:18:52 +020027#include <sound/pcm_params.h>
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010028#include <sound/initval.h>
29#include <sound/soc.h>
30
Russell Kinga09e64f2008-08-05 16:14:15 +010031#include <mach/hardware.h>
32#include <mach/at91_pmc.h>
33#include <mach/at91_ssc.h>
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010034
35#include "at91-pcm.h"
Frank Mandarino36b8a8b2007-04-16 17:18:52 +020036#include "at91-ssc.h"
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010037
38#if 0
Frank Mandarino36b8a8b2007-04-16 17:18:52 +020039#define DBG(x...) printk(KERN_DEBUG "at91-ssc:" x)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010040#else
41#define DBG(x...)
42#endif
43
sedji gaouaou61352662008-07-10 10:15:35 +010044#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010045#define NUM_SSC_DEVICES 1
46#else
47#define NUM_SSC_DEVICES 3
48#endif
49
50
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010051/*
52 * SSC PDC registers required by the PCM DMA engine.
53 */
54static struct at91_pdc_regs pdc_tx_reg = {
Frank Mandarinofa8f8782007-02-12 14:06:22 +010055 .xpr = ATMEL_PDC_TPR,
56 .xcr = ATMEL_PDC_TCR,
57 .xnpr = ATMEL_PDC_TNPR,
58 .xncr = ATMEL_PDC_TNCR,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010059};
60
61static struct at91_pdc_regs pdc_rx_reg = {
Frank Mandarinofa8f8782007-02-12 14:06:22 +010062 .xpr = ATMEL_PDC_RPR,
63 .xcr = ATMEL_PDC_RCR,
64 .xnpr = ATMEL_PDC_RNPR,
65 .xncr = ATMEL_PDC_RNCR,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010066};
67
68/*
69 * SSC & PDC status bits for transmit and receive.
70 */
71static struct at91_ssc_mask ssc_tx_mask = {
72 .ssc_enable = AT91_SSC_TXEN,
73 .ssc_disable = AT91_SSC_TXDIS,
74 .ssc_endx = AT91_SSC_ENDTX,
75 .ssc_endbuf = AT91_SSC_TXBUFE,
Frank Mandarinofa8f8782007-02-12 14:06:22 +010076 .pdc_enable = ATMEL_PDC_TXTEN,
77 .pdc_disable = ATMEL_PDC_TXTDIS,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010078};
79
80static struct at91_ssc_mask ssc_rx_mask = {
81 .ssc_enable = AT91_SSC_RXEN,
82 .ssc_disable = AT91_SSC_RXDIS,
83 .ssc_endx = AT91_SSC_ENDRX,
84 .ssc_endbuf = AT91_SSC_RXBUFF,
Frank Mandarinofa8f8782007-02-12 14:06:22 +010085 .pdc_enable = ATMEL_PDC_RXTEN,
86 .pdc_disable = ATMEL_PDC_RXTDIS,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010087};
88
89
90/*
91 * DMA parameters.
92 */
93static struct at91_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
94 {{
Frank Mandarino36b8a8b2007-04-16 17:18:52 +020095 .name = "SSC0 PCM out",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +010096 .pdc = &pdc_tx_reg,
97 .mask = &ssc_tx_mask,
98 },
99 {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200100 .name = "SSC0 PCM in",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100101 .pdc = &pdc_rx_reg,
102 .mask = &ssc_rx_mask,
103 }},
104#if NUM_SSC_DEVICES == 3
105 {{
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200106 .name = "SSC1 PCM out",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100107 .pdc = &pdc_tx_reg,
108 .mask = &ssc_tx_mask,
109 },
110 {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200111 .name = "SSC1 PCM in",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100112 .pdc = &pdc_rx_reg,
113 .mask = &ssc_rx_mask,
114 }},
115 {{
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200116 .name = "SSC2 PCM out",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100117 .pdc = &pdc_tx_reg,
118 .mask = &ssc_tx_mask,
119 },
120 {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200121 .name = "SSC2 PCM in",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100122 .pdc = &pdc_rx_reg,
123 .mask = &ssc_rx_mask,
124 }},
125#endif
126};
127
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100128struct at91_ssc_state {
129 u32 ssc_cmr;
130 u32 ssc_rcmr;
131 u32 ssc_rfmr;
132 u32 ssc_tcmr;
133 u32 ssc_tfmr;
134 u32 ssc_sr;
135 u32 ssc_imr;
136};
137
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100138static struct at91_ssc_info {
139 char *name;
140 struct at91_ssc_periph ssc;
141 spinlock_t lock; /* lock for dir_mask */
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100142 unsigned short dir_mask; /* 0=unused, 1=playback, 2=capture */
143 unsigned short initialized; /* 1=SSC has been initialized */
144 unsigned short daifmt;
145 unsigned short cmr_div;
146 unsigned short tcmr_period;
147 unsigned short rcmr_period;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100148 struct at91_pcm_dma_params *dma_params[2];
149 struct at91_ssc_state ssc_state;
150
151} ssc_info[NUM_SSC_DEVICES] = {
152 {
153 .name = "ssc0",
Milind Arun Choudharyc9758b22007-04-19 15:22:56 +0200154 .lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100155 .dir_mask = 0,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100156 .initialized = 0,
157 },
158#if NUM_SSC_DEVICES == 3
159 {
160 .name = "ssc1",
Milind Arun Choudharyc9758b22007-04-19 15:22:56 +0200161 .lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100162 .dir_mask = 0,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100163 .initialized = 0,
164 },
165 {
166 .name = "ssc2",
Milind Arun Choudharyc9758b22007-04-19 15:22:56 +0200167 .lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100168 .dir_mask = 0,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100169 .initialized = 0,
170 },
171#endif
172};
173
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200174static unsigned int at91_ssc_sysclk;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100175
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100176/*
177 * SSC interrupt handler. Passes PDC interrupts to the DMA
178 * interrupt handler in the PCM driver.
179 */
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200180static irqreturn_t at91_ssc_interrupt(int irq, void *dev_id)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100181{
182 struct at91_ssc_info *ssc_p = dev_id;
183 struct at91_pcm_dma_params *dma_params;
184 u32 ssc_sr;
185 int i;
186
187 ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR)
188 & at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
189
190 /*
191 * Loop through the substreams attached to this SSC. If
192 * a DMA-related interrupt occurred on that substream, call
193 * the DMA interrupt handler function, if one has been
194 * registered in the dma_params structure by the PCM driver.
195 */
196 for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
197 dma_params = ssc_p->dma_params[i];
198
199 if (dma_params != NULL && dma_params->dma_intr_handler != NULL &&
200 (ssc_sr &
201 (dma_params->mask->ssc_endx | dma_params->mask->ssc_endbuf)))
202
203 dma_params->dma_intr_handler(ssc_sr, dma_params->substream);
204 }
205
206 return IRQ_HANDLED;
207}
208
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100209/*
210 * Startup. Only that one substream allowed in each direction.
211 */
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200212static int at91_ssc_startup(struct snd_pcm_substream *substream)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100213{
214 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100215 struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100216 int dir_mask;
217
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200218 DBG("ssc_startup: SSC_SR=0x%08lx\n",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100219 at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
220 dir_mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0x1 : 0x2;
221
222 spin_lock_irq(&ssc_p->lock);
223 if (ssc_p->dir_mask & dir_mask) {
224 spin_unlock_irq(&ssc_p->lock);
225 return -EBUSY;
226 }
227 ssc_p->dir_mask |= dir_mask;
228 spin_unlock_irq(&ssc_p->lock);
229
230 return 0;
231}
232
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100233/*
234 * Shutdown. Clear DMA parameters and shutdown the SSC if there
235 * are no other substreams open.
236 */
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200237static void at91_ssc_shutdown(struct snd_pcm_substream *substream)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100238{
239 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100240 struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
241 struct at91_pcm_dma_params *dma_params;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100242 int dir, dir_mask;
243
244 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100245 dma_params = ssc_p->dma_params[dir];
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100246
247 if (dma_params != NULL) {
248 at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
249 dma_params->mask->ssc_disable);
250 DBG("%s disabled SSC_SR=0x%08lx\n", (dir ? "receive" : "transmit"),
251 at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR));
252
253 dma_params->ssc_base = NULL;
254 dma_params->substream = NULL;
255 ssc_p->dma_params[dir] = NULL;
256 }
257
258 dir_mask = 1 << dir;
259
260 spin_lock_irq(&ssc_p->lock);
261 ssc_p->dir_mask &= ~dir_mask;
262 if (!ssc_p->dir_mask) {
263 /* Shutdown the SSC clock. */
264 DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
265 at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
266
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100267 if (ssc_p->initialized) {
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100268 free_irq(ssc_p->ssc.pid, ssc_p);
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100269 ssc_p->initialized = 0;
270 }
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100271
272 /* Reset the SSC */
273 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
274
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100275 /* Clear the SSC dividers */
276 ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100277 }
278 spin_unlock_irq(&ssc_p->lock);
279}
280
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100281/*
282 * Record the SSC system clock rate.
283 */
Liam Girdwoodd37ae532008-07-07 16:07:37 +0100284static int at91_ssc_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100285 int clk_id, unsigned int freq, int dir)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100286{
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100287 /*
288 * The only clock supplied to the SSC is the AT91 master clock,
289 * which is only used if the SSC is generating BCLK and/or
290 * LRC clocks.
291 */
292 switch (clk_id) {
293 case AT91_SYSCLK_MCK:
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200294 at91_ssc_sysclk = freq;
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100295 break;
296 default:
297 return -EINVAL;
298 }
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100299
300 return 0;
301}
302
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100303/*
304 * Record the DAI format for use in hw_params().
305 */
Liam Girdwoodd37ae532008-07-07 16:07:37 +0100306static int at91_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100307 unsigned int fmt)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100308{
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100309 struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100310
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100311 ssc_p->daifmt = fmt;
312 return 0;
313}
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100314
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100315/*
316 * Record SSC clock dividers for use in hw_params().
317 */
Liam Girdwoodd37ae532008-07-07 16:07:37 +0100318static int at91_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100319 int div_id, int div)
320{
321 struct at91_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100322
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100323 switch (div_id) {
324 case AT91SSC_CMR_DIV:
325 /*
326 * The same master clock divider is used for both
327 * transmit and receive, so if a value has already
328 * been set, it must match this value.
329 */
330 if (ssc_p->cmr_div == 0)
331 ssc_p->cmr_div = div;
332 else
333 if (div != ssc_p->cmr_div)
334 return -EBUSY;
335 break;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100336
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100337 case AT91SSC_TCMR_PERIOD:
338 ssc_p->tcmr_period = div;
339 break;
340
341 case AT91SSC_RCMR_PERIOD:
342 ssc_p->rcmr_period = div;
343 break;
344
345 default:
346 return -EINVAL;
347 }
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100348
349 return 0;
350}
351
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100352/*
353 * Configure the SSC.
354 */
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200355static int at91_ssc_hw_params(struct snd_pcm_substream *substream,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100356 struct snd_pcm_hw_params *params)
357{
358 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100359 int id = rtd->dai->cpu_dai->id;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100360 struct at91_ssc_info *ssc_p = &ssc_info[id];
361 struct at91_pcm_dma_params *dma_params;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100362 int dir, channels, bits;
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100363 u32 tfmr, rfmr, tcmr, rcmr;
364 int start_event;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100365 int ret;
366
367 /*
368 * Currently, there is only one set of dma params for
369 * each direction. If more are added, this code will
370 * have to be changed to select the proper set.
371 */
372 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
373
374 dma_params = &ssc_dma_params[id][dir];
375 dma_params->ssc_base = ssc_p->ssc.base;
376 dma_params->substream = substream;
377
378 ssc_p->dma_params[dir] = dma_params;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100379
380 /*
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100381 * The cpu_dai->dma_data field is only used to communicate the
382 * appropriate DMA parameters to the pcm driver hw_params()
383 * function. It should not be used for other purposes
384 * as it is common to all substreams.
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100385 */
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100386 rtd->dai->cpu_dai->dma_data = dma_params;
387
388 channels = params_channels(params);
389
390 /*
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200391 * Determine sample size in bits and the PDC increment.
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100392 */
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200393 switch(params_format(params)) {
394 case SNDRV_PCM_FORMAT_S8:
395 bits = 8;
396 dma_params->pdc_xfer_size = 1;
397 break;
398 case SNDRV_PCM_FORMAT_S16_LE:
399 bits = 16;
400 dma_params->pdc_xfer_size = 2;
401 break;
402 case SNDRV_PCM_FORMAT_S24_LE:
403 bits = 24;
404 dma_params->pdc_xfer_size = 4;
405 break;
406 case SNDRV_PCM_FORMAT_S32_LE:
407 bits = 32;
408 dma_params->pdc_xfer_size = 4;
409 break;
410 default:
411 printk(KERN_WARNING "at91-ssc: unsupported PCM format");
412 return -EINVAL;
413 }
414
415 /*
416 * The SSC only supports up to 16-bit samples in I2S format, due
417 * to the size of the Frame Mode Register FSLEN field.
418 */
419 if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
420 && bits > 16) {
421 printk(KERN_WARNING
422 "at91-ssc: sample size %d is too large for I2S\n", bits);
423 return -EINVAL;
424 }
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100425
426 /*
427 * Compute SSC register settings.
428 */
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200429 switch (ssc_p->daifmt
430 & (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
431
432 case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100433 /*
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200434 * I2S format, SSC provides BCLK and LRC clocks.
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100435 *
436 * The SSC transmit and receive clocks are generated from the
437 * MCK divider, and the BCLK signal is output on the SSC TK line.
438 */
439 rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD)
440 | (( 1 << 16) & AT91_SSC_STTDLY)
441 | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
442 | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
443 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
444 | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
445
446 rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
447 | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
448 | (((bits - 1) << 16) & AT91_SSC_FSLEN)
449 | (((channels - 1) << 8) & AT91_SSC_DATNB)
450 | (( 1 << 7) & AT91_SSC_MSBF)
451 | (( 0 << 5) & AT91_SSC_LOOP)
452 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
453
454 tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD)
455 | (( 1 << 16) & AT91_SSC_STTDLY)
456 | (( AT91_SSC_START_FALLING_RF ) & AT91_SSC_START)
457 | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
458 | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO)
459 | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
460
461 tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
462 | (( 0 << 23) & AT91_SSC_FSDEN)
463 | (( AT91_SSC_FSOS_NEGATIVE ) & AT91_SSC_FSOS)
464 | (((bits - 1) << 16) & AT91_SSC_FSLEN)
465 | (((channels - 1) << 8) & AT91_SSC_DATNB)
466 | (( 1 << 7) & AT91_SSC_MSBF)
467 | (( 0 << 5) & AT91_SSC_DATDEF)
468 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
469 break;
470
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200471 case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100472 /*
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200473 * I2S format, CODEC supplies BCLK and LRC clocks.
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100474 *
475 * The SSC transmit clock is obtained from the BCLK signal on
476 * on the TK line, and the SSC receive clock is generated from the
477 * transmit clock.
478 *
479 * For single channel data, one sample is transferred on the falling
480 * edge of the LRC clock. For two channel data, one sample is
481 * transferred on both edges of the LRC clock.
482 */
483 start_event = channels == 1
484 ? AT91_SSC_START_FALLING_RF
485 : AT91_SSC_START_EDGE_RF;
486
487 rcmr = (( 0 << 24) & AT91_SSC_PERIOD)
488 | (( 1 << 16) & AT91_SSC_STTDLY)
489 | (( start_event ) & AT91_SSC_START)
490 | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
491 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
492 | (( AT91_SSC_CKS_CLOCK ) & AT91_SSC_CKS);
493
494 rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
495 | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
496 | (( 0 << 16) & AT91_SSC_FSLEN)
497 | (( 0 << 8) & AT91_SSC_DATNB)
498 | (( 1 << 7) & AT91_SSC_MSBF)
499 | (( 0 << 5) & AT91_SSC_LOOP)
500 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
501
502 tcmr = (( 0 << 24) & AT91_SSC_PERIOD)
503 | (( 1 << 16) & AT91_SSC_STTDLY)
504 | (( start_event ) & AT91_SSC_START)
505 | (( AT91_SSC_CKI_FALLING ) & AT91_SSC_CKI)
506 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
507 | (( AT91_SSC_CKS_PIN ) & AT91_SSC_CKS);
508
509 tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
510 | (( 0 << 23) & AT91_SSC_FSDEN)
511 | (( AT91_SSC_FSOS_NONE ) & AT91_SSC_FSOS)
512 | (( 0 << 16) & AT91_SSC_FSLEN)
513 | (( 0 << 8) & AT91_SSC_DATNB)
514 | (( 1 << 7) & AT91_SSC_MSBF)
515 | (( 0 << 5) & AT91_SSC_DATDEF)
516 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
517 break;
518
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200519 case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
520 /*
521 * DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
522 *
523 * The SSC transmit and receive clocks are generated from the
524 * MCK divider, and the BCLK signal is output on the SSC TK line.
525 */
526 rcmr = (( ssc_p->rcmr_period << 24) & AT91_SSC_PERIOD)
527 | (( 1 << 16) & AT91_SSC_STTDLY)
528 | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START)
529 | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
530 | (( AT91_SSC_CKO_NONE ) & AT91_SSC_CKO)
531 | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
532
533 rfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
534 | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS)
535 | (( 0 << 16) & AT91_SSC_FSLEN)
536 | (((channels - 1) << 8) & AT91_SSC_DATNB)
537 | (( 1 << 7) & AT91_SSC_MSBF)
538 | (( 0 << 5) & AT91_SSC_LOOP)
539 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
540
541 tcmr = (( ssc_p->tcmr_period << 24) & AT91_SSC_PERIOD)
542 | (( 1 << 16) & AT91_SSC_STTDLY)
543 | (( AT91_SSC_START_RISING_RF ) & AT91_SSC_START)
544 | (( AT91_SSC_CK_RISING ) & AT91_SSC_CKI)
545 | (( AT91_SSC_CKO_CONTINUOUS ) & AT91_SSC_CKO)
546 | (( AT91_SSC_CKS_DIV ) & AT91_SSC_CKS);
547
548 tfmr = (( AT91_SSC_FSEDGE_POSITIVE ) & AT91_SSC_FSEDGE)
549 | (( 0 << 23) & AT91_SSC_FSDEN)
550 | (( AT91_SSC_FSOS_POSITIVE ) & AT91_SSC_FSOS)
551 | (( 0 << 16) & AT91_SSC_FSLEN)
552 | (((channels - 1) << 8) & AT91_SSC_DATNB)
553 | (( 1 << 7) & AT91_SSC_MSBF)
554 | (( 0 << 5) & AT91_SSC_DATDEF)
555 | (((bits - 1) << 0) & AT91_SSC_DATALEN);
556
557
558
559 break;
560
561 case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100562 default:
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200563 printk(KERN_WARNING "at91-ssc: unsupported DAI format 0x%x.\n",
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100564 ssc_p->daifmt);
565 return -EINVAL;
566 break;
567 }
568 DBG("RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n", rcmr, rfmr, tcmr, tfmr);
569
570 if (!ssc_p->initialized) {
571
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100572 /* Enable PMC peripheral clock for this SSC */
573 DBG("Starting pid %d clock\n", ssc_p->ssc.pid);
574 at91_sys_write(AT91_PMC_PCER, 1<<ssc_p->ssc.pid);
575
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100576 /* Reset the SSC and its PDC registers */
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100577 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR, AT91_SSC_SWRST);
578
Frank Mandarinofa8f8782007-02-12 14:06:22 +0100579 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RPR, 0);
580 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RCR, 0);
581 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNPR, 0);
582 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_RNCR, 0);
583 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TPR, 0);
584 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TCR, 0);
585 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNPR, 0);
586 at91_ssc_write(ssc_p->ssc.base + ATMEL_PDC_TNCR, 0);
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100587
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200588 if ((ret = request_irq(ssc_p->ssc.pid, at91_ssc_interrupt,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100589 0, ssc_p->name, ssc_p)) < 0) {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200590 printk(KERN_WARNING "at91-ssc: request_irq failure\n");
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100591
592 DBG("Stopping pid %d clock\n", ssc_p->ssc.pid);
Patrik Sevalliuse3a2efa2008-05-08 14:04:08 +0200593 at91_sys_write(AT91_PMC_PCDR, 1<<ssc_p->ssc.pid);
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100594 return ret;
595 }
596
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100597 ssc_p->initialized = 1;
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100598 }
599
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100600 /* set SSC clock mode register */
601 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->cmr_div);
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100602
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100603 /* set receive clock mode and format */
604 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, rcmr);
605 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, rfmr);
606
607 /* set transmit clock mode and format */
608 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, tcmr);
609 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, tfmr);
610
611 DBG("hw_params: SSC initialized\n");
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100612 return 0;
613}
614
615
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200616static int at91_ssc_prepare(struct snd_pcm_substream *substream)
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100617{
618 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100619 struct at91_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
620 struct at91_pcm_dma_params *dma_params;
621 int dir;
622
623 dir = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
624 dma_params = ssc_p->dma_params[dir];
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100625
626 at91_ssc_write(dma_params->ssc_base + AT91_SSC_CR,
627 dma_params->mask->ssc_enable);
628
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100629 DBG("%s enabled SSC_SR=0x%08lx\n", dir ? "receive" : "transmit",
630 at91_ssc_read(dma_params->ssc_base + AT91_SSC_SR));
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100631 return 0;
632}
633
634
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100635#ifdef CONFIG_PM
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200636static int at91_ssc_suspend(struct platform_device *pdev,
Liam Girdwoodd37ae532008-07-07 16:07:37 +0100637 struct snd_soc_dai *cpu_dai)
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100638{
639 struct at91_ssc_info *ssc_p;
640
641 if(!cpu_dai->active)
642 return 0;
643
644 ssc_p = &ssc_info[cpu_dai->id];
645
646 /* Save the status register before disabling transmit and receive. */
647 ssc_p->ssc_state.ssc_sr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_SR);
648 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
649 AT91_SSC_TXDIS | AT91_SSC_RXDIS);
650
651 /* Save the current interrupt mask, then disable unmasked interrupts. */
652 ssc_p->ssc_state.ssc_imr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_IMR);
653 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IDR, ssc_p->ssc_state.ssc_imr);
654
655 ssc_p->ssc_state.ssc_cmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_CMR);
656 ssc_p->ssc_state.ssc_rcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RCMR);
657 ssc_p->ssc_state.ssc_rfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_RFMR);
658 ssc_p->ssc_state.ssc_tcmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TCMR);
659 ssc_p->ssc_state.ssc_tfmr = at91_ssc_read(ssc_p->ssc.base + AT91_SSC_TFMR);
660
661 return 0;
662}
663
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200664static int at91_ssc_resume(struct platform_device *pdev,
Liam Girdwoodd37ae532008-07-07 16:07:37 +0100665 struct snd_soc_dai *cpu_dai)
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100666{
667 struct at91_ssc_info *ssc_p;
668
669 if(!cpu_dai->active)
670 return 0;
671
672 ssc_p = &ssc_info[cpu_dai->id];
673
674 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TFMR, ssc_p->ssc_state.ssc_tfmr);
675 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_TCMR, ssc_p->ssc_state.ssc_tcmr);
676 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RFMR, ssc_p->ssc_state.ssc_rfmr);
677 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_RCMR, ssc_p->ssc_state.ssc_rcmr);
678 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CMR, ssc_p->ssc_state.ssc_cmr);
679
680 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_IER, ssc_p->ssc_state.ssc_imr);
681
682 at91_ssc_write(ssc_p->ssc.base + AT91_SSC_CR,
683 ((ssc_p->ssc_state.ssc_sr & AT91_SSC_RXENA) ? AT91_SSC_RXEN : 0) |
684 ((ssc_p->ssc_state.ssc_sr & AT91_SSC_TXENA) ? AT91_SSC_TXEN : 0));
685
686 return 0;
687}
688
689#else
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200690#define at91_ssc_suspend NULL
691#define at91_ssc_resume NULL
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100692#endif
693
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200694#define AT91_SSC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100695 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
696 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
697 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
698 SNDRV_PCM_RATE_96000)
699
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200700#define AT91_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
701 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
702
Liam Girdwoodd37ae532008-07-07 16:07:37 +0100703struct snd_soc_dai at91_ssc_dai[NUM_SSC_DEVICES] = {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200704 { .name = "at91-ssc0",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100705 .id = 0,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200706 .type = SND_SOC_DAI_PCM,
707 .suspend = at91_ssc_suspend,
708 .resume = at91_ssc_resume,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100709 .playback = {
710 .channels_min = 1,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100711 .channels_max = 2,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200712 .rates = AT91_SSC_RATES,
713 .formats = AT91_SSC_FORMATS,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100714 .capture = {
715 .channels_min = 1,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100716 .channels_max = 2,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200717 .rates = AT91_SSC_RATES,
718 .formats = AT91_SSC_FORMATS,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100719 .ops = {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200720 .startup = at91_ssc_startup,
721 .shutdown = at91_ssc_shutdown,
722 .prepare = at91_ssc_prepare,
723 .hw_params = at91_ssc_hw_params,},
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100724 .dai_ops = {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200725 .set_sysclk = at91_ssc_set_dai_sysclk,
726 .set_fmt = at91_ssc_set_dai_fmt,
727 .set_clkdiv = at91_ssc_set_dai_clkdiv,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100728 .private_data = &ssc_info[0].ssc,
729 },
730#if NUM_SSC_DEVICES == 3
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200731 { .name = "at91-ssc1",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100732 .id = 1,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200733 .type = SND_SOC_DAI_PCM,
734 .suspend = at91_ssc_suspend,
735 .resume = at91_ssc_resume,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100736 .playback = {
737 .channels_min = 1,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100738 .channels_max = 2,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200739 .rates = AT91_SSC_RATES,
740 .formats = AT91_SSC_FORMATS,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100741 .capture = {
742 .channels_min = 1,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100743 .channels_max = 2,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200744 .rates = AT91_SSC_RATES,
745 .formats = AT91_SSC_FORMATS,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100746 .ops = {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200747 .startup = at91_ssc_startup,
748 .shutdown = at91_ssc_shutdown,
749 .prepare = at91_ssc_prepare,
750 .hw_params = at91_ssc_hw_params,},
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100751 .dai_ops = {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200752 .set_sysclk = at91_ssc_set_dai_sysclk,
753 .set_fmt = at91_ssc_set_dai_fmt,
754 .set_clkdiv = at91_ssc_set_dai_clkdiv,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100755 .private_data = &ssc_info[1].ssc,
756 },
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200757 { .name = "at91-ssc2",
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100758 .id = 2,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200759 .type = SND_SOC_DAI_PCM,
760 .suspend = at91_ssc_suspend,
761 .resume = at91_ssc_resume,
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100762 .playback = {
763 .channels_min = 1,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100764 .channels_max = 2,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200765 .rates = AT91_SSC_RATES,
766 .formats = AT91_SSC_FORMATS,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100767 .capture = {
768 .channels_min = 1,
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100769 .channels_max = 2,
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200770 .rates = AT91_SSC_RATES,
771 .formats = AT91_SSC_FORMATS,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100772 .ops = {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200773 .startup = at91_ssc_startup,
774 .shutdown = at91_ssc_shutdown,
775 .prepare = at91_ssc_prepare,
776 .hw_params = at91_ssc_hw_params,},
Frank Mandarino171eb8f2007-02-02 17:18:38 +0100777 .dai_ops = {
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200778 .set_sysclk = at91_ssc_set_dai_sysclk,
779 .set_fmt = at91_ssc_set_dai_fmt,
780 .set_clkdiv = at91_ssc_set_dai_clkdiv,},
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100781 .private_data = &ssc_info[2].ssc,
782 },
783#endif
784};
785
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200786EXPORT_SYMBOL_GPL(at91_ssc_dai);
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100787
788/* Module information */
789MODULE_AUTHOR("Frank Mandarino, fmandarino@endrelia.com, www.endrelia.com");
Frank Mandarino36b8a8b2007-04-16 17:18:52 +0200790MODULE_DESCRIPTION("AT91 SSC ASoC Interface");
Frank Mandarino9f0ac6e2006-11-24 15:49:39 +0100791MODULE_LICENSE("GPL");