Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 270576
b: refs/heads/master
c: 5e538ec
h: refs/heads/master
v: v3
  • Loading branch information
Timur Tabi authored and Mark Brown committed Sep 15, 2011
1 parent 6b222dc commit 73411bb
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 78 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: 32d2a0c17d81016215381d337dad876dc972ee83
refs/heads/master: 5e538ecade22a5ec4c8e18d494db0ecf924254eb
145 changes: 68 additions & 77 deletions trunk/sound/soc/fsl/fsl_ssi.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
* @second_stream: pointer to second stream
* @playback: the number of playback streams opened
* @capture: the number of capture streams opened
* @asynchronous: 0=synchronous mode, 1=asynchronous mode
* @cpu_dai: the CPU DAI for this device
* @dev_attr: the sysfs device attribute structure
* @stats: SSI statistics
Expand All @@ -90,9 +89,6 @@ struct fsl_ssi_private {
unsigned int irq;
struct snd_pcm_substream *first_stream;
struct snd_pcm_substream *second_stream;
unsigned int playback;
unsigned int capture;
int asynchronous;
unsigned int fifo_depth;
struct snd_soc_dai_driver cpu_dai_drv;
struct device_attribute dev_attr;
Expand Down Expand Up @@ -281,15 +277,19 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
struct fsl_ssi_private *ssi_private =
snd_soc_dai_get_drvdata(rtd->cpu_dai);
int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;

/*
* If this is the first stream opened, then request the IRQ
* and initialize the SSI registers.
*/
if (!ssi_private->playback && !ssi_private->capture) {
if (!ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;

ssi_private->first_stream = substream;

/*
* Section 16.5 of the MPC8610 reference manual says that the
* SSI needs to be disabled before updating the registers we set
Expand All @@ -306,7 +306,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
clrsetbits_be32(&ssi->scr,
CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
| (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
| (synchronous ? CCSR_SSI_SCR_SYN : 0));

out_be32(&ssi->stcr,
CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
Expand All @@ -323,7 +323,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* master.
*/

/* 4. Enable the interrupts and DMA requests */
/* Enable the interrupts and DMA requests */
out_be32(&ssi->sier, SIER_FLAGS);

/*
Expand Down Expand Up @@ -352,58 +352,47 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* this is bad is because at this point, the PCM driver has not
* finished initializing the DMA controller.
*/
}

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->sample_bits) {
dev_err(substream->pcm->card->dev,
"set sample size in %s stream first\n",
substream->stream == SNDRV_PCM_STREAM_PLAYBACK
? "capture" : "playback");
return -EAGAIN;
}
} else {
if (synchronous) {
struct snd_pcm_runtime *first_runtime =
ssi_private->first_stream->runtime;
/*
* This is the second stream open, and we're in
* synchronous mode, so we need to impose sample
* sample size constraints. This is because STCCR is
* used for playback and capture in synchronous mode,
* so there's no way to specify different word
* lengths.
*
* 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.
*/
if (!first_runtime->sample_bits) {
dev_err(substream->pcm->card->dev,
"set sample size in %s stream first\n",
substream->stream ==
SNDRV_PCM_STREAM_PLAYBACK
? "capture" : "playback");
return -EAGAIN;
}

/* If we're in synchronous mode, then we need to constrain
* the sample size as well. We don't support independent sample
* rates in asynchronous mode.
*/
if (!ssi_private->asynchronous)
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++;

if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ssi_private->capture++;

return 0;
}

Expand All @@ -424,24 +413,35 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai);
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
unsigned int sample_size =
snd_pcm_format_width(params_format(hw_params));
u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
int enabled = in_be32(&ssi->scr) & CCSR_SSI_SCR_SSIEN;

if (substream == ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
unsigned int sample_size =
snd_pcm_format_width(params_format(hw_params));
u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
/*
* If we're in synchronous mode, and the SSI is already enabled,
* then STCCR is already set properly.
*/
if (enabled && ssi_private->cpu_dai_drv.symmetric_rates)
return 0;

/* The SSI should always be disabled at this points (SSIEN=0) */
/*
* FIXME: The documentation says that SxCCR[WL] should not be
* modified while the SSI is enabled. The only time this can
* happen is if we're trying to do simultaneous playback and
* capture in asynchronous mode. Unfortunately, I have been enable
* to get that to work at all on the P1022DS. Therefore, we don't
* bother to disable/enable the SSI when setting SxCCR[WL], because
* the SSI will stop anyway. Maybe one day, this will get fixed.
*/

/* In synchronous mode, the SSI uses STCCR for capture */
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
!ssi_private->asynchronous)
clrsetbits_be32(&ssi->stccr,
CCSR_SSI_SxCCR_WL_MASK, wl);
else
clrsetbits_be32(&ssi->srccr,
CCSR_SSI_SxCCR_WL_MASK, wl);
}
/* In synchronous mode, the SSI uses STCCR for capture */
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
ssi_private->cpu_dai_drv.symmetric_rates)
clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
else
clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);

return 0;
}
Expand All @@ -464,7 +464,6 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
setbits32(&ssi->scr,
Expand Down Expand Up @@ -500,12 +499,6 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);

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

if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ssi_private->capture--;

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

Expand All @@ -514,7 +507,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
/*
* If this is the last active substream, disable the SSI.
*/
if (!ssi_private->playback && !ssi_private->capture) {
if (!ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;

clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
Expand Down Expand Up @@ -688,9 +681,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
}

/* Are the RX and the TX clocks locked? */
if (of_find_property(np, "fsl,ssi-asynchronous", NULL))
ssi_private->asynchronous = 1;
else
if (!of_find_property(np, "fsl,ssi-asynchronous", NULL))
ssi_private->cpu_dai_drv.symmetric_rates = 1;

/* Determine the FIFO depth. */
Expand Down

0 comments on commit 73411bb

Please sign in to comment.