Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 107359
b: refs/heads/master
c: be41e94
h: refs/heads/master
i:
  107357: 8b0e9d0
  107355: 3f1a48b
  107351: e1653b8
  107343: 5a08567
  107327: 812fb04
v: v3
  • Loading branch information
Timur Tabi authored and Takashi Iwai committed Jul 29, 2008
1 parent 8c5b658 commit bbca085
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 12 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a7b815169aae65072017efb1fba9dcecc82ba7c1
refs/heads/master: be41e941d5f1a48bde7f44d09d56e8d2605f98e1
7 changes: 6 additions & 1 deletion trunk/sound/soc/fsl/fsl_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,17 @@ struct fsl_dma_private {
* Since each link descriptor has a 32-bit byte count field, we set
* period_bytes_max to the largest 32-bit number. We also have no maximum
* number of periods.
*
* Note that we specify SNDRV_PCM_INFO_JOINT_DUPLEX here, but only because a
* limitation in the SSI driver requires the sample rates for playback and
* capture to be the same.
*/
static const struct snd_pcm_hardware fsl_dma_hardware = {

.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID,
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_JOINT_DUPLEX,
.formats = FSLDMA_PCM_FORMATS,
.rates = FSLDMA_PCM_RATES,
.rate_min = 5512,
Expand Down
74 changes: 64 additions & 10 deletions trunk/sound/soc/fsl/fsl_ssi.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
* @ssi: pointer to the SSI's registers
* @ssi_phys: physical address of the SSI registers
* @irq: IRQ of this SSI
* @first_stream: pointer to the stream that was opened first
* @second_stream: pointer to second stream
* @dev: struct device pointer
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
Expand All @@ -79,6 +81,8 @@ struct fsl_ssi_private {
struct ccsr_ssi __iomem *ssi;
dma_addr_t ssi_phys;
unsigned int irq;
struct snd_pcm_substream *first_stream;
struct snd_pcm_substream *second_stream;
struct device *dev;
unsigned int playback;
unsigned int capture;
Expand Down Expand Up @@ -342,6 +346,49 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream)
*/
}

if (!ssi_private->first_stream)
ssi_private->first_stream = substream;
else {
/* This is the second stream open, so we need to impose sample
* rate and maybe sample size constraints. Note that this can
* cause a race condition if the second stream is opened before
* the first stream is fully initialized.
*
* We provide some protection by checking to make sure the first
* stream is initialized, but it's not perfect. ALSA sometimes
* re-initializes the driver with a different sample rate or
* size. If the second stream is opened before the first stream
* has received its final parameters, then the second stream may
* be constrained to the wrong sample rate or size.
*
* FIXME: This code does not handle opening and closing streams
* repeatedly. If you open two streams and then close the first
* one, you may not be able to open another stream until you
* close the second one as well.
*/
struct snd_pcm_runtime *first_runtime =
ssi_private->first_stream->runtime;

if (!first_runtime->rate || !first_runtime->sample_bits) {
dev_err(substream->pcm->card->dev,
"set sample rate and size in %s stream first\n",
substream->stream == SNDRV_PCM_STREAM_PLAYBACK
? "capture" : "playback");
return -EAGAIN;
}

snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
first_runtime->rate, first_runtime->rate);

snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
first_runtime->sample_bits,
first_runtime->sample_bits);

ssi_private->second_stream = substream;
}

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ssi_private->playback++;

Expand Down Expand Up @@ -371,18 +418,16 @@ static int fsl_ssi_prepare(struct snd_pcm_substream *substream)
struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;

struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
u32 wl;

wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
if (substream == ssi_private->first_stream) {
u32 wl;

clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
/* The SSI should always be disabled at this points (SSIEN=0) */
wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
/* In synchronous mode, the SSI uses STCCR for capture */
clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
else
clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);

setbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
}

return 0;
}
Expand All @@ -407,9 +452,13 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
setbits32(&ssi->scr, CCSR_SSI_SCR_TE);
clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
} else {
setbits32(&ssi->scr, CCSR_SSI_SCR_RE);
clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
setbits32(&ssi->scr,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);

/*
* I think we need this delay to allow time for the SSI
Expand Down Expand Up @@ -452,6 +501,11 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ssi_private->capture--;

if (ssi_private->first_stream == substream)
ssi_private->first_stream = ssi_private->second_stream;

ssi_private->second_stream = NULL;

/*
* If this is the last active substream, disable the SSI and release
* the IRQ.
Expand Down

0 comments on commit bbca085

Please sign in to comment.