diff options
Diffstat (limited to 'sound/soc/fsl/fsl_ssi.c')
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 74 |
1 files changed, 64 insertions, 10 deletions
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. |