aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/fsl/fsl_dma.c7
-rw-r--r--sound/soc/fsl/fsl_ssi.c74
2 files changed, 70 insertions, 11 deletions
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index da2bc5902864..7ceea2bba1f5 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -132,12 +132,17 @@ struct fsl_dma_private {
132 * Since each link descriptor has a 32-bit byte count field, we set 132 * Since each link descriptor has a 32-bit byte count field, we set
133 * period_bytes_max to the largest 32-bit number. We also have no maximum 133 * period_bytes_max to the largest 32-bit number. We also have no maximum
134 * number of periods. 134 * number of periods.
135 *
136 * Note that we specify SNDRV_PCM_INFO_JOINT_DUPLEX here, but only because a
137 * limitation in the SSI driver requires the sample rates for playback and
138 * capture to be the same.
135 */ 139 */
136static const struct snd_pcm_hardware fsl_dma_hardware = { 140static const struct snd_pcm_hardware fsl_dma_hardware = {
137 141
138 .info = SNDRV_PCM_INFO_INTERLEAVED | 142 .info = SNDRV_PCM_INFO_INTERLEAVED |
139 SNDRV_PCM_INFO_MMAP | 143 SNDRV_PCM_INFO_MMAP |
140 SNDRV_PCM_INFO_MMAP_VALID, 144 SNDRV_PCM_INFO_MMAP_VALID |
145 SNDRV_PCM_INFO_JOINT_DUPLEX,
141 .formats = FSLDMA_PCM_FORMATS, 146 .formats = FSLDMA_PCM_FORMATS,
142 .rates = FSLDMA_PCM_RATES, 147 .rates = FSLDMA_PCM_RATES,
143 .rate_min = 5512, 148 .rate_min = 5512,
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 71bff33f5528..157a7895ffa1 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -67,6 +67,8 @@
67 * @ssi: pointer to the SSI's registers 67 * @ssi: pointer to the SSI's registers
68 * @ssi_phys: physical address of the SSI registers 68 * @ssi_phys: physical address of the SSI registers
69 * @irq: IRQ of this SSI 69 * @irq: IRQ of this SSI
70 * @first_stream: pointer to the stream that was opened first
71 * @second_stream: pointer to second stream
70 * @dev: struct device pointer 72 * @dev: struct device pointer
71 * @playback: the number of playback streams opened 73 * @playback: the number of playback streams opened
72 * @capture: the number of capture streams opened 74 * @capture: the number of capture streams opened
@@ -79,6 +81,8 @@ struct fsl_ssi_private {
79 struct ccsr_ssi __iomem *ssi; 81 struct ccsr_ssi __iomem *ssi;
80 dma_addr_t ssi_phys; 82 dma_addr_t ssi_phys;
81 unsigned int irq; 83 unsigned int irq;
84 struct snd_pcm_substream *first_stream;
85 struct snd_pcm_substream *second_stream;
82 struct device *dev; 86 struct device *dev;
83 unsigned int playback; 87 unsigned int playback;
84 unsigned int capture; 88 unsigned int capture;
@@ -342,6 +346,49 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream)
342 */ 346 */
343 } 347 }
344 348
349 if (!ssi_private->first_stream)
350 ssi_private->first_stream = substream;
351 else {
352 /* This is the second stream open, so we need to impose sample
353 * rate and maybe sample size constraints. Note that this can
354 * cause a race condition if the second stream is opened before
355 * the first stream is fully initialized.
356 *
357 * We provide some protection by checking to make sure the first
358 * stream is initialized, but it's not perfect. ALSA sometimes
359 * re-initializes the driver with a different sample rate or
360 * size. If the second stream is opened before the first stream
361 * has received its final parameters, then the second stream may
362 * be constrained to the wrong sample rate or size.
363 *
364 * FIXME: This code does not handle opening and closing streams
365 * repeatedly. If you open two streams and then close the first
366 * one, you may not be able to open another stream until you
367 * close the second one as well.
368 */
369 struct snd_pcm_runtime *first_runtime =
370 ssi_private->first_stream->runtime;
371
372 if (!first_runtime->rate || !first_runtime->sample_bits) {
373 dev_err(substream->pcm->card->dev,
374 "set sample rate and size in %s stream first\n",
375 substream->stream == SNDRV_PCM_STREAM_PLAYBACK
376 ? "capture" : "playback");
377 return -EAGAIN;
378 }
379
380 snd_pcm_hw_constraint_minmax(substream->runtime,
381 SNDRV_PCM_HW_PARAM_RATE,
382 first_runtime->rate, first_runtime->rate);
383
384 snd_pcm_hw_constraint_minmax(substream->runtime,
385 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
386 first_runtime->sample_bits,
387 first_runtime->sample_bits);
388
389 ssi_private->second_stream = substream;
390 }
391
345 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 392 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
346 ssi_private->playback++; 393 ssi_private->playback++;
347 394
@@ -371,18 +418,16 @@ static int fsl_ssi_prepare(struct snd_pcm_substream *substream)
371 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data; 418 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
372 419
373 struct ccsr_ssi __iomem *ssi = ssi_private->ssi; 420 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
374 u32 wl;
375 421
376 wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format)); 422 if (substream == ssi_private->first_stream) {
423 u32 wl;
377 424
378 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); 425 /* The SSI should always be disabled at this points (SSIEN=0) */
426 wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
379 427
380 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 428 /* In synchronous mode, the SSI uses STCCR for capture */
381 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); 429 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
382 else 430 }
383 clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
384
385 setbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
386 431
387 return 0; 432 return 0;
388} 433}
@@ -407,9 +452,13 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd)
407 case SNDRV_PCM_TRIGGER_RESUME: 452 case SNDRV_PCM_TRIGGER_RESUME:
408 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 453 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
409 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 454 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
410 setbits32(&ssi->scr, CCSR_SSI_SCR_TE); 455 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
456 setbits32(&ssi->scr,
457 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
411 } else { 458 } else {
412 setbits32(&ssi->scr, CCSR_SSI_SCR_RE); 459 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
460 setbits32(&ssi->scr,
461 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
413 462
414 /* 463 /*
415 * I think we need this delay to allow time for the SSI 464 * I think we need this delay to allow time for the SSI
@@ -452,6 +501,11 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
452 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 501 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
453 ssi_private->capture--; 502 ssi_private->capture--;
454 503
504 if (ssi_private->first_stream == substream)
505 ssi_private->first_stream = ssi_private->second_stream;
506
507 ssi_private->second_stream = NULL;
508
455 /* 509 /*
456 * If this is the last active substream, disable the SSI and release 510 * If this is the last active substream, disable the SSI and release
457 * the IRQ. 511 * the IRQ.