summaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl4030.c
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2009-04-17 14:55:08 +0200
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-04-17 17:02:23 +0200
commit6b87a91f5417226c7fe62100b0e7217e7096b789 (patch)
tree4982bad86c6346c014028806a0bdc3989fde688d /sound/soc/codecs/twl4030.c
parentMerge branch 'for-2.6.30' into for-2.6.31 (diff)
downloadlinux-6b87a91f5417226c7fe62100b0e7217e7096b789.tar.xz
linux-6b87a91f5417226c7fe62100b0e7217e7096b789.zip
ASoC: TWL4030: Fix for the constraint handling
The original implementation of the constraints were good against sane applications. If the opening sequence is: stream1_open, stream1_hw_params, stream2_open, stream2_hw_params -> the constraints are set correctly for stream2. But if the sequence is: stream1_open, stream2_open, stream2_hw_params, stream1_hw_params -> than stream2 would receive constraint rate = 0, sample_bits = 0, since the stream1 has not yet called hw_params... The command to trigger this event: gst-launch-0.10 alsasrc device=hw:0 ! alsasink device=hw:0 sync=false This patch does some 'black magic' in order to always set the correct constraints and sets it only when it is needed for the other stream. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r--sound/soc/codecs/twl4030.c85
1 files changed, 66 insertions, 19 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 921b205de28a..a1b76d7fd130 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -125,6 +125,11 @@ struct twl4030_priv {
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
+
+ unsigned int configured;
+ unsigned int rate;
+ unsigned int sample_bits;
+ unsigned int channels;
};
/*
@@ -1220,6 +1225,36 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
+static void twl4030_constraints(struct twl4030_priv *twl4030,
+ struct snd_pcm_substream *mst_substream)
+{
+ struct snd_pcm_substream *slv_substream;
+
+ /* Pick the stream, which need to be constrained */
+ if (mst_substream == twl4030->master_substream)
+ slv_substream = twl4030->slave_substream;
+ else if (mst_substream == twl4030->slave_substream)
+ slv_substream = twl4030->master_substream;
+ else /* This should not happen.. */
+ return;
+
+ /* Set the constraints according to the already configured stream */
+ snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+ SNDRV_PCM_HW_PARAM_RATE,
+ twl4030->rate,
+ twl4030->rate);
+
+ snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ twl4030->sample_bits,
+ twl4030->sample_bits);
+
+ snd_pcm_hw_constraint_minmax(slv_substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ twl4030->channels,
+ twl4030->channels);
+}
+
static int twl4030_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -1228,26 +1263,16 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = socdev->card->codec;
struct twl4030_priv *twl4030 = codec->private_data;
- /* If we already have a playback or capture going then constrain
- * this substream to match it.
- */
if (twl4030->master_substream) {
- struct snd_pcm_runtime *master_runtime;
- master_runtime = twl4030->master_substream->runtime;
-
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_RATE,
- master_runtime->rate,
- master_runtime->rate);
-
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
- master_runtime->sample_bits,
- master_runtime->sample_bits);
-
twl4030->slave_substream = substream;
- } else
+ /* The DAI has one configuration for playback and capture, so
+ * if the DAI has been already configured then constrain this
+ * substream to match it. */
+ if (twl4030->configured)
+ twl4030_constraints(twl4030, twl4030->master_substream);
+ } else {
twl4030->master_substream = substream;
+ }
return 0;
}
@@ -1264,6 +1289,13 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
twl4030->master_substream = twl4030->slave_substream;
twl4030->slave_substream = NULL;
+
+ /* If all streams are closed, or the remaining stream has not yet
+ * been configured than set the DAI as not configured. */
+ if (!twl4030->master_substream)
+ twl4030->configured = 0;
+ else if (!twl4030->master_substream->runtime->channels)
+ twl4030->configured = 0;
}
static int twl4030_hw_params(struct snd_pcm_substream *substream,
@@ -1276,8 +1308,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
struct twl4030_priv *twl4030 = codec->private_data;
u8 mode, old_mode, format, old_format;
- if (substream == twl4030->slave_substream)
- /* Ignoring hw_params for slave substream */
+ if (twl4030->configured)
+ /* Ignoring hw_params for already configured DAI */
return 0;
/* bit rate */
@@ -1357,6 +1389,21 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
/* set CODECPDZ afterwards */
twl4030_codec_enable(codec, 1);
}
+
+ /* Store the important parameters for the DAI configuration and set
+ * the DAI as configured */
+ twl4030->configured = 1;
+ twl4030->rate = params_rate(params);
+ twl4030->sample_bits = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
+ twl4030->channels = params_channels(params);
+
+ /* If both playback and capture streams are open, and one of them
+ * is setting the hw parameters right now (since we are here), set
+ * constraints to the other stream to match the current one. */
+ if (twl4030->slave_substream)
+ twl4030_constraints(twl4030, substream);
+
return 0;
}