Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/soc/atmel/atmel_ssc_dai.c
10817 views
1
/*
2
* atmel_ssc_dai.c -- ALSA SoC ATMEL SSC Audio Layer Platform driver
3
*
4
* Copyright (C) 2005 SAN People
5
* Copyright (C) 2008 Atmel
6
*
7
* Author: Sedji Gaouaou <[email protected]>
8
* ATMEL CORP.
9
*
10
* Based on at91-ssc.c by
11
* Frank Mandarino <[email protected]>
12
* Based on pxa2xx Platform drivers by
13
* Liam Girdwood <[email protected]>
14
*
15
* This program is free software; you can redistribute it and/or modify
16
* it under the terms of the GNU General Public License as published by
17
* the Free Software Foundation; either version 2 of the License, or
18
* (at your option) any later version.
19
*
20
* This program is distributed in the hope that it will be useful,
21
* but WITHOUT ANY WARRANTY; without even the implied warranty of
22
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
* GNU General Public License for more details.
24
*
25
* You should have received a copy of the GNU General Public License
26
* along with this program; if not, write to the Free Software
27
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
*/
29
30
#include <linux/init.h>
31
#include <linux/module.h>
32
#include <linux/interrupt.h>
33
#include <linux/device.h>
34
#include <linux/delay.h>
35
#include <linux/clk.h>
36
#include <linux/atmel_pdc.h>
37
38
#include <linux/atmel-ssc.h>
39
#include <sound/core.h>
40
#include <sound/pcm.h>
41
#include <sound/pcm_params.h>
42
#include <sound/initval.h>
43
#include <sound/soc.h>
44
45
#include <mach/hardware.h>
46
47
#include "atmel-pcm.h"
48
#include "atmel_ssc_dai.h"
49
50
51
#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
52
#define NUM_SSC_DEVICES 1
53
#else
54
#define NUM_SSC_DEVICES 3
55
#endif
56
57
/*
58
* SSC PDC registers required by the PCM DMA engine.
59
*/
60
static struct atmel_pdc_regs pdc_tx_reg = {
61
.xpr = ATMEL_PDC_TPR,
62
.xcr = ATMEL_PDC_TCR,
63
.xnpr = ATMEL_PDC_TNPR,
64
.xncr = ATMEL_PDC_TNCR,
65
};
66
67
static struct atmel_pdc_regs pdc_rx_reg = {
68
.xpr = ATMEL_PDC_RPR,
69
.xcr = ATMEL_PDC_RCR,
70
.xnpr = ATMEL_PDC_RNPR,
71
.xncr = ATMEL_PDC_RNCR,
72
};
73
74
/*
75
* SSC & PDC status bits for transmit and receive.
76
*/
77
static struct atmel_ssc_mask ssc_tx_mask = {
78
.ssc_enable = SSC_BIT(CR_TXEN),
79
.ssc_disable = SSC_BIT(CR_TXDIS),
80
.ssc_endx = SSC_BIT(SR_ENDTX),
81
.ssc_endbuf = SSC_BIT(SR_TXBUFE),
82
.pdc_enable = ATMEL_PDC_TXTEN,
83
.pdc_disable = ATMEL_PDC_TXTDIS,
84
};
85
86
static struct atmel_ssc_mask ssc_rx_mask = {
87
.ssc_enable = SSC_BIT(CR_RXEN),
88
.ssc_disable = SSC_BIT(CR_RXDIS),
89
.ssc_endx = SSC_BIT(SR_ENDRX),
90
.ssc_endbuf = SSC_BIT(SR_RXBUFF),
91
.pdc_enable = ATMEL_PDC_RXTEN,
92
.pdc_disable = ATMEL_PDC_RXTDIS,
93
};
94
95
96
/*
97
* DMA parameters.
98
*/
99
static struct atmel_pcm_dma_params ssc_dma_params[NUM_SSC_DEVICES][2] = {
100
{{
101
.name = "SSC0 PCM out",
102
.pdc = &pdc_tx_reg,
103
.mask = &ssc_tx_mask,
104
},
105
{
106
.name = "SSC0 PCM in",
107
.pdc = &pdc_rx_reg,
108
.mask = &ssc_rx_mask,
109
} },
110
#if NUM_SSC_DEVICES == 3
111
{{
112
.name = "SSC1 PCM out",
113
.pdc = &pdc_tx_reg,
114
.mask = &ssc_tx_mask,
115
},
116
{
117
.name = "SSC1 PCM in",
118
.pdc = &pdc_rx_reg,
119
.mask = &ssc_rx_mask,
120
} },
121
{{
122
.name = "SSC2 PCM out",
123
.pdc = &pdc_tx_reg,
124
.mask = &ssc_tx_mask,
125
},
126
{
127
.name = "SSC2 PCM in",
128
.pdc = &pdc_rx_reg,
129
.mask = &ssc_rx_mask,
130
} },
131
#endif
132
};
133
134
135
static struct atmel_ssc_info ssc_info[NUM_SSC_DEVICES] = {
136
{
137
.name = "ssc0",
138
.lock = __SPIN_LOCK_UNLOCKED(ssc_info[0].lock),
139
.dir_mask = SSC_DIR_MASK_UNUSED,
140
.initialized = 0,
141
},
142
#if NUM_SSC_DEVICES == 3
143
{
144
.name = "ssc1",
145
.lock = __SPIN_LOCK_UNLOCKED(ssc_info[1].lock),
146
.dir_mask = SSC_DIR_MASK_UNUSED,
147
.initialized = 0,
148
},
149
{
150
.name = "ssc2",
151
.lock = __SPIN_LOCK_UNLOCKED(ssc_info[2].lock),
152
.dir_mask = SSC_DIR_MASK_UNUSED,
153
.initialized = 0,
154
},
155
#endif
156
};
157
158
159
/*
160
* SSC interrupt handler. Passes PDC interrupts to the DMA
161
* interrupt handler in the PCM driver.
162
*/
163
static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
164
{
165
struct atmel_ssc_info *ssc_p = dev_id;
166
struct atmel_pcm_dma_params *dma_params;
167
u32 ssc_sr;
168
u32 ssc_substream_mask;
169
int i;
170
171
ssc_sr = (unsigned long)ssc_readl(ssc_p->ssc->regs, SR)
172
& (unsigned long)ssc_readl(ssc_p->ssc->regs, IMR);
173
174
/*
175
* Loop through the substreams attached to this SSC. If
176
* a DMA-related interrupt occurred on that substream, call
177
* the DMA interrupt handler function, if one has been
178
* registered in the dma_params structure by the PCM driver.
179
*/
180
for (i = 0; i < ARRAY_SIZE(ssc_p->dma_params); i++) {
181
dma_params = ssc_p->dma_params[i];
182
183
if ((dma_params != NULL) &&
184
(dma_params->dma_intr_handler != NULL)) {
185
ssc_substream_mask = (dma_params->mask->ssc_endx |
186
dma_params->mask->ssc_endbuf);
187
if (ssc_sr & ssc_substream_mask) {
188
dma_params->dma_intr_handler(ssc_sr,
189
dma_params->
190
substream);
191
}
192
}
193
}
194
195
return IRQ_HANDLED;
196
}
197
198
199
/*-------------------------------------------------------------------------*\
200
* DAI functions
201
\*-------------------------------------------------------------------------*/
202
/*
203
* Startup. Only that one substream allowed in each direction.
204
*/
205
static int atmel_ssc_startup(struct snd_pcm_substream *substream,
206
struct snd_soc_dai *dai)
207
{
208
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
209
int dir_mask;
210
211
pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
212
ssc_readl(ssc_p->ssc->regs, SR));
213
214
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
215
dir_mask = SSC_DIR_MASK_PLAYBACK;
216
else
217
dir_mask = SSC_DIR_MASK_CAPTURE;
218
219
spin_lock_irq(&ssc_p->lock);
220
if (ssc_p->dir_mask & dir_mask) {
221
spin_unlock_irq(&ssc_p->lock);
222
return -EBUSY;
223
}
224
ssc_p->dir_mask |= dir_mask;
225
spin_unlock_irq(&ssc_p->lock);
226
227
return 0;
228
}
229
230
/*
231
* Shutdown. Clear DMA parameters and shutdown the SSC if there
232
* are no other substreams open.
233
*/
234
static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
235
struct snd_soc_dai *dai)
236
{
237
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
238
struct atmel_pcm_dma_params *dma_params;
239
int dir, dir_mask;
240
241
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
242
dir = 0;
243
else
244
dir = 1;
245
246
dma_params = ssc_p->dma_params[dir];
247
248
if (dma_params != NULL) {
249
ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
250
pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n",
251
(dir ? "receive" : "transmit"),
252
ssc_readl(ssc_p->ssc->regs, SR));
253
254
dma_params->ssc = NULL;
255
dma_params->substream = NULL;
256
ssc_p->dma_params[dir] = NULL;
257
}
258
259
dir_mask = 1 << dir;
260
261
spin_lock_irq(&ssc_p->lock);
262
ssc_p->dir_mask &= ~dir_mask;
263
if (!ssc_p->dir_mask) {
264
if (ssc_p->initialized) {
265
/* Shutdown the SSC clock. */
266
pr_debug("atmel_ssc_dau: Stopping clock\n");
267
clk_disable(ssc_p->ssc->clk);
268
269
free_irq(ssc_p->ssc->irq, ssc_p);
270
ssc_p->initialized = 0;
271
}
272
273
/* Reset the SSC */
274
ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
275
/* Clear the SSC dividers */
276
ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
277
}
278
spin_unlock_irq(&ssc_p->lock);
279
}
280
281
282
/*
283
* Record the DAI format for use in hw_params().
284
*/
285
static int atmel_ssc_set_dai_fmt(struct snd_soc_dai *cpu_dai,
286
unsigned int fmt)
287
{
288
struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
289
290
ssc_p->daifmt = fmt;
291
return 0;
292
}
293
294
/*
295
* Record SSC clock dividers for use in hw_params().
296
*/
297
static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
298
int div_id, int div)
299
{
300
struct atmel_ssc_info *ssc_p = &ssc_info[cpu_dai->id];
301
302
switch (div_id) {
303
case ATMEL_SSC_CMR_DIV:
304
/*
305
* The same master clock divider is used for both
306
* transmit and receive, so if a value has already
307
* been set, it must match this value.
308
*/
309
if (ssc_p->cmr_div == 0)
310
ssc_p->cmr_div = div;
311
else
312
if (div != ssc_p->cmr_div)
313
return -EBUSY;
314
break;
315
316
case ATMEL_SSC_TCMR_PERIOD:
317
ssc_p->tcmr_period = div;
318
break;
319
320
case ATMEL_SSC_RCMR_PERIOD:
321
ssc_p->rcmr_period = div;
322
break;
323
324
default:
325
return -EINVAL;
326
}
327
328
return 0;
329
}
330
331
/*
332
* Configure the SSC.
333
*/
334
static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
335
struct snd_pcm_hw_params *params,
336
struct snd_soc_dai *dai)
337
{
338
struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
339
int id = dai->id;
340
struct atmel_ssc_info *ssc_p = &ssc_info[id];
341
struct atmel_pcm_dma_params *dma_params;
342
int dir, channels, bits;
343
u32 tfmr, rfmr, tcmr, rcmr;
344
int start_event;
345
int ret;
346
347
/*
348
* Currently, there is only one set of dma params for
349
* each direction. If more are added, this code will
350
* have to be changed to select the proper set.
351
*/
352
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
353
dir = 0;
354
else
355
dir = 1;
356
357
dma_params = &ssc_dma_params[id][dir];
358
dma_params->ssc = ssc_p->ssc;
359
dma_params->substream = substream;
360
361
ssc_p->dma_params[dir] = dma_params;
362
363
/*
364
* The snd_soc_pcm_stream->dma_data field is only used to communicate
365
* the appropriate DMA parameters to the pcm driver hw_params()
366
* function. It should not be used for other purposes
367
* as it is common to all substreams.
368
*/
369
snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
370
371
channels = params_channels(params);
372
373
/*
374
* Determine sample size in bits and the PDC increment.
375
*/
376
switch (params_format(params)) {
377
case SNDRV_PCM_FORMAT_S8:
378
bits = 8;
379
dma_params->pdc_xfer_size = 1;
380
break;
381
case SNDRV_PCM_FORMAT_S16_LE:
382
bits = 16;
383
dma_params->pdc_xfer_size = 2;
384
break;
385
case SNDRV_PCM_FORMAT_S24_LE:
386
bits = 24;
387
dma_params->pdc_xfer_size = 4;
388
break;
389
case SNDRV_PCM_FORMAT_S32_LE:
390
bits = 32;
391
dma_params->pdc_xfer_size = 4;
392
break;
393
default:
394
printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format");
395
return -EINVAL;
396
}
397
398
/*
399
* The SSC only supports up to 16-bit samples in I2S format, due
400
* to the size of the Frame Mode Register FSLEN field.
401
*/
402
if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S
403
&& bits > 16) {
404
printk(KERN_WARNING
405
"atmel_ssc_dai: sample size %d"
406
"is too large for I2S\n", bits);
407
return -EINVAL;
408
}
409
410
/*
411
* Compute SSC register settings.
412
*/
413
switch (ssc_p->daifmt
414
& (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
415
416
case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
417
/*
418
* I2S format, SSC provides BCLK and LRC clocks.
419
*
420
* The SSC transmit and receive clocks are generated
421
* from the MCK divider, and the BCLK signal
422
* is output on the SSC TK line.
423
*/
424
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
425
| SSC_BF(RCMR_STTDLY, START_DELAY)
426
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
427
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
428
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
429
| SSC_BF(RCMR_CKS, SSC_CKS_DIV);
430
431
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
432
| SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
433
| SSC_BF(RFMR_FSLEN, (bits - 1))
434
| SSC_BF(RFMR_DATNB, (channels - 1))
435
| SSC_BIT(RFMR_MSBF)
436
| SSC_BF(RFMR_LOOP, 0)
437
| SSC_BF(RFMR_DATLEN, (bits - 1));
438
439
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
440
| SSC_BF(TCMR_STTDLY, START_DELAY)
441
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
442
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
443
| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
444
| SSC_BF(TCMR_CKS, SSC_CKS_DIV);
445
446
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
447
| SSC_BF(TFMR_FSDEN, 0)
448
| SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
449
| SSC_BF(TFMR_FSLEN, (bits - 1))
450
| SSC_BF(TFMR_DATNB, (channels - 1))
451
| SSC_BIT(TFMR_MSBF)
452
| SSC_BF(TFMR_DATDEF, 0)
453
| SSC_BF(TFMR_DATLEN, (bits - 1));
454
break;
455
456
case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
457
/*
458
* I2S format, CODEC supplies BCLK and LRC clocks.
459
*
460
* The SSC transmit clock is obtained from the BCLK signal on
461
* on the TK line, and the SSC receive clock is
462
* generated from the transmit clock.
463
*
464
* For single channel data, one sample is transferred
465
* on the falling edge of the LRC clock.
466
* For two channel data, one sample is
467
* transferred on both edges of the LRC clock.
468
*/
469
start_event = ((channels == 1)
470
? SSC_START_FALLING_RF
471
: SSC_START_EDGE_RF);
472
473
rcmr = SSC_BF(RCMR_PERIOD, 0)
474
| SSC_BF(RCMR_STTDLY, START_DELAY)
475
| SSC_BF(RCMR_START, start_event)
476
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
477
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
478
| SSC_BF(RCMR_CKS, SSC_CKS_CLOCK);
479
480
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
481
| SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
482
| SSC_BF(RFMR_FSLEN, 0)
483
| SSC_BF(RFMR_DATNB, 0)
484
| SSC_BIT(RFMR_MSBF)
485
| SSC_BF(RFMR_LOOP, 0)
486
| SSC_BF(RFMR_DATLEN, (bits - 1));
487
488
tcmr = SSC_BF(TCMR_PERIOD, 0)
489
| SSC_BF(TCMR_STTDLY, START_DELAY)
490
| SSC_BF(TCMR_START, start_event)
491
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
492
| SSC_BF(TCMR_CKO, SSC_CKO_NONE)
493
| SSC_BF(TCMR_CKS, SSC_CKS_PIN);
494
495
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
496
| SSC_BF(TFMR_FSDEN, 0)
497
| SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
498
| SSC_BF(TFMR_FSLEN, 0)
499
| SSC_BF(TFMR_DATNB, 0)
500
| SSC_BIT(TFMR_MSBF)
501
| SSC_BF(TFMR_DATDEF, 0)
502
| SSC_BF(TFMR_DATLEN, (bits - 1));
503
break;
504
505
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
506
/*
507
* DSP/PCM Mode A format, SSC provides BCLK and LRC clocks.
508
*
509
* The SSC transmit and receive clocks are generated from the
510
* MCK divider, and the BCLK signal is output
511
* on the SSC TK line.
512
*/
513
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
514
| SSC_BF(RCMR_STTDLY, 1)
515
| SSC_BF(RCMR_START, SSC_START_RISING_RF)
516
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
517
| SSC_BF(RCMR_CKO, SSC_CKO_NONE)
518
| SSC_BF(RCMR_CKS, SSC_CKS_DIV);
519
520
rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
521
| SSC_BF(RFMR_FSOS, SSC_FSOS_POSITIVE)
522
| SSC_BF(RFMR_FSLEN, 0)
523
| SSC_BF(RFMR_DATNB, (channels - 1))
524
| SSC_BIT(RFMR_MSBF)
525
| SSC_BF(RFMR_LOOP, 0)
526
| SSC_BF(RFMR_DATLEN, (bits - 1));
527
528
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
529
| SSC_BF(TCMR_STTDLY, 1)
530
| SSC_BF(TCMR_START, SSC_START_RISING_RF)
531
| SSC_BF(TCMR_CKI, SSC_CKI_RISING)
532
| SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
533
| SSC_BF(TCMR_CKS, SSC_CKS_DIV);
534
535
tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
536
| SSC_BF(TFMR_FSDEN, 0)
537
| SSC_BF(TFMR_FSOS, SSC_FSOS_POSITIVE)
538
| SSC_BF(TFMR_FSLEN, 0)
539
| SSC_BF(TFMR_DATNB, (channels - 1))
540
| SSC_BIT(TFMR_MSBF)
541
| SSC_BF(TFMR_DATDEF, 0)
542
| SSC_BF(TFMR_DATLEN, (bits - 1));
543
break;
544
545
case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
546
default:
547
printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
548
ssc_p->daifmt);
549
return -EINVAL;
550
}
551
pr_debug("atmel_ssc_hw_params: "
552
"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
553
rcmr, rfmr, tcmr, tfmr);
554
555
if (!ssc_p->initialized) {
556
557
/* Enable PMC peripheral clock for this SSC */
558
pr_debug("atmel_ssc_dai: Starting clock\n");
559
clk_enable(ssc_p->ssc->clk);
560
561
/* Reset the SSC and its PDC registers */
562
ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
563
564
ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
565
ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
566
ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
567
ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
568
569
ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
570
ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
571
ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
572
ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
573
574
ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
575
ssc_p->name, ssc_p);
576
if (ret < 0) {
577
printk(KERN_WARNING
578
"atmel_ssc_dai: request_irq failure\n");
579
pr_debug("Atmel_ssc_dai: Stoping clock\n");
580
clk_disable(ssc_p->ssc->clk);
581
return ret;
582
}
583
584
ssc_p->initialized = 1;
585
}
586
587
/* set SSC clock mode register */
588
ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
589
590
/* set receive clock mode and format */
591
ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
592
ssc_writel(ssc_p->ssc->regs, RFMR, rfmr);
593
594
/* set transmit clock mode and format */
595
ssc_writel(ssc_p->ssc->regs, TCMR, tcmr);
596
ssc_writel(ssc_p->ssc->regs, TFMR, tfmr);
597
598
pr_debug("atmel_ssc_dai,hw_params: SSC initialized\n");
599
return 0;
600
}
601
602
603
static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
604
struct snd_soc_dai *dai)
605
{
606
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
607
struct atmel_pcm_dma_params *dma_params;
608
int dir;
609
610
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
611
dir = 0;
612
else
613
dir = 1;
614
615
dma_params = ssc_p->dma_params[dir];
616
617
ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
618
619
pr_debug("%s enabled SSC_SR=0x%08x\n",
620
dir ? "receive" : "transmit",
621
ssc_readl(ssc_p->ssc->regs, SR));
622
return 0;
623
}
624
625
626
#ifdef CONFIG_PM
627
static int atmel_ssc_suspend(struct snd_soc_dai *cpu_dai)
628
{
629
struct atmel_ssc_info *ssc_p;
630
631
if (!cpu_dai->active)
632
return 0;
633
634
ssc_p = &ssc_info[cpu_dai->id];
635
636
/* Save the status register before disabling transmit and receive */
637
ssc_p->ssc_state.ssc_sr = ssc_readl(ssc_p->ssc->regs, SR);
638
ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_TXDIS) | SSC_BIT(CR_RXDIS));
639
640
/* Save the current interrupt mask, then disable unmasked interrupts */
641
ssc_p->ssc_state.ssc_imr = ssc_readl(ssc_p->ssc->regs, IMR);
642
ssc_writel(ssc_p->ssc->regs, IDR, ssc_p->ssc_state.ssc_imr);
643
644
ssc_p->ssc_state.ssc_cmr = ssc_readl(ssc_p->ssc->regs, CMR);
645
ssc_p->ssc_state.ssc_rcmr = ssc_readl(ssc_p->ssc->regs, RCMR);
646
ssc_p->ssc_state.ssc_rfmr = ssc_readl(ssc_p->ssc->regs, RFMR);
647
ssc_p->ssc_state.ssc_tcmr = ssc_readl(ssc_p->ssc->regs, TCMR);
648
ssc_p->ssc_state.ssc_tfmr = ssc_readl(ssc_p->ssc->regs, TFMR);
649
650
return 0;
651
}
652
653
654
655
static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
656
{
657
struct atmel_ssc_info *ssc_p;
658
u32 cr;
659
660
if (!cpu_dai->active)
661
return 0;
662
663
ssc_p = &ssc_info[cpu_dai->id];
664
665
/* restore SSC register settings */
666
ssc_writel(ssc_p->ssc->regs, TFMR, ssc_p->ssc_state.ssc_tfmr);
667
ssc_writel(ssc_p->ssc->regs, TCMR, ssc_p->ssc_state.ssc_tcmr);
668
ssc_writel(ssc_p->ssc->regs, RFMR, ssc_p->ssc_state.ssc_rfmr);
669
ssc_writel(ssc_p->ssc->regs, RCMR, ssc_p->ssc_state.ssc_rcmr);
670
ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->ssc_state.ssc_cmr);
671
672
/* re-enable interrupts */
673
ssc_writel(ssc_p->ssc->regs, IER, ssc_p->ssc_state.ssc_imr);
674
675
/* Re-enable receive and transmit as appropriate */
676
cr = 0;
677
cr |=
678
(ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_RXEN)) ? SSC_BIT(CR_RXEN) : 0;
679
cr |=
680
(ssc_p->ssc_state.ssc_sr & SSC_BIT(SR_TXEN)) ? SSC_BIT(CR_TXEN) : 0;
681
ssc_writel(ssc_p->ssc->regs, CR, cr);
682
683
return 0;
684
}
685
#else /* CONFIG_PM */
686
# define atmel_ssc_suspend NULL
687
# define atmel_ssc_resume NULL
688
#endif /* CONFIG_PM */
689
690
static int atmel_ssc_probe(struct snd_soc_dai *dai)
691
{
692
struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
693
int ret = 0;
694
695
snd_soc_dai_set_drvdata(dai, ssc_p);
696
697
/*
698
* Request SSC device
699
*/
700
ssc_p->ssc = ssc_request(dai->id);
701
if (IS_ERR(ssc_p->ssc)) {
702
printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
703
ret = PTR_ERR(ssc_p->ssc);
704
}
705
706
return ret;
707
}
708
709
static int atmel_ssc_remove(struct snd_soc_dai *dai)
710
{
711
struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
712
713
ssc_free(ssc_p->ssc);
714
return 0;
715
}
716
717
#define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
718
719
#define ATMEL_SSC_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |\
720
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
721
722
static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
723
.startup = atmel_ssc_startup,
724
.shutdown = atmel_ssc_shutdown,
725
.prepare = atmel_ssc_prepare,
726
.hw_params = atmel_ssc_hw_params,
727
.set_fmt = atmel_ssc_set_dai_fmt,
728
.set_clkdiv = atmel_ssc_set_dai_clkdiv,
729
};
730
731
static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
732
{
733
.name = "atmel-ssc-dai.0",
734
.probe = atmel_ssc_probe,
735
.remove = atmel_ssc_remove,
736
.suspend = atmel_ssc_suspend,
737
.resume = atmel_ssc_resume,
738
.playback = {
739
.channels_min = 1,
740
.channels_max = 2,
741
.rates = ATMEL_SSC_RATES,
742
.formats = ATMEL_SSC_FORMATS,},
743
.capture = {
744
.channels_min = 1,
745
.channels_max = 2,
746
.rates = ATMEL_SSC_RATES,
747
.formats = ATMEL_SSC_FORMATS,},
748
.ops = &atmel_ssc_dai_ops,
749
},
750
#if NUM_SSC_DEVICES == 3
751
{
752
.name = "atmel-ssc-dai.1",
753
.probe = atmel_ssc_probe,
754
.remove = atmel_ssc_remove,
755
.suspend = atmel_ssc_suspend,
756
.resume = atmel_ssc_resume,
757
.playback = {
758
.channels_min = 1,
759
.channels_max = 2,
760
.rates = ATMEL_SSC_RATES,
761
.formats = ATMEL_SSC_FORMATS,},
762
.capture = {
763
.channels_min = 1,
764
.channels_max = 2,
765
.rates = ATMEL_SSC_RATES,
766
.formats = ATMEL_SSC_FORMATS,},
767
.ops = &atmel_ssc_dai_ops,
768
},
769
{
770
.name = "atmel-ssc-dai.2",
771
.probe = atmel_ssc_probe,
772
.remove = atmel_ssc_remove,
773
.suspend = atmel_ssc_suspend,
774
.resume = atmel_ssc_resume,
775
.playback = {
776
.channels_min = 1,
777
.channels_max = 2,
778
.rates = ATMEL_SSC_RATES,
779
.formats = ATMEL_SSC_FORMATS,},
780
.capture = {
781
.channels_min = 1,
782
.channels_max = 2,
783
.rates = ATMEL_SSC_RATES,
784
.formats = ATMEL_SSC_FORMATS,},
785
.ops = &atmel_ssc_dai_ops,
786
},
787
#endif
788
};
789
790
static __devinit int asoc_ssc_probe(struct platform_device *pdev)
791
{
792
BUG_ON(pdev->id < 0);
793
BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
794
return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
795
}
796
797
static int __devexit asoc_ssc_remove(struct platform_device *pdev)
798
{
799
snd_soc_unregister_dai(&pdev->dev);
800
return 0;
801
}
802
803
static struct platform_driver asoc_ssc_driver = {
804
.driver = {
805
.name = "atmel-ssc-dai",
806
.owner = THIS_MODULE,
807
},
808
809
.probe = asoc_ssc_probe,
810
.remove = __devexit_p(asoc_ssc_remove),
811
};
812
813
/**
814
* atmel_ssc_set_audio - Allocate the specified SSC for audio use.
815
*/
816
int atmel_ssc_set_audio(int ssc_id)
817
{
818
struct ssc_device *ssc;
819
static struct platform_device *dma_pdev;
820
struct platform_device *ssc_pdev;
821
int ret;
822
823
if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
824
return -EINVAL;
825
826
/* Allocate a dummy device for DMA if we don't have one already */
827
if (!dma_pdev) {
828
dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
829
if (!dma_pdev)
830
return -ENOMEM;
831
832
ret = platform_device_add(dma_pdev);
833
if (ret < 0) {
834
platform_device_put(dma_pdev);
835
dma_pdev = NULL;
836
return ret;
837
}
838
}
839
840
ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
841
if (!ssc_pdev) {
842
ssc_free(ssc);
843
return -ENOMEM;
844
}
845
846
/* If we can grab the SSC briefly to parent the DAI device off it */
847
ssc = ssc_request(ssc_id);
848
if (IS_ERR(ssc))
849
pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
850
PTR_ERR(ssc));
851
else {
852
ssc_pdev->dev.parent = &(ssc->pdev->dev);
853
ssc_free(ssc);
854
}
855
856
ret = platform_device_add(ssc_pdev);
857
if (ret < 0)
858
platform_device_put(ssc_pdev);
859
860
return ret;
861
}
862
EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
863
864
static int __init snd_atmel_ssc_init(void)
865
{
866
return platform_driver_register(&asoc_ssc_driver);
867
}
868
module_init(snd_atmel_ssc_init);
869
870
static void __exit snd_atmel_ssc_exit(void)
871
{
872
platform_driver_unregister(&asoc_ssc_driver);
873
}
874
module_exit(snd_atmel_ssc_exit);
875
876
/* Module information */
877
MODULE_AUTHOR("Sedji Gaouaou, [email protected], www.atmel.com");
878
MODULE_DESCRIPTION("ATMEL SSC ASoC Interface");
879
MODULE_LICENSE("GPL");
880
881