ASoC: TWL4030: Add constrains for second stream
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>
Fri, 27 Mar 2009 08:39:08 +0000 (10:39 +0200)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Thu, 2 Apr 2009 15:34:16 +0000 (16:34 +0100)
In case of duplex mode (capture and playback at the same time), the second
stream has to have the same parameters (rate, sample size) as the already
running stream.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/soc/codecs/twl4030.c

index b07d8d6..4199498 100644 (file)
@@ -122,6 +122,9 @@ struct twl4030_priv {
        unsigned int bypass_state;
        unsigned int codec_powered;
        unsigned int codec_muted;
+
+       struct snd_pcm_substream *master_substream;
+       struct snd_pcm_substream *slave_substream;
 };
 
 /*
@@ -1217,6 +1220,50 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+static int twl4030_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->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
+               twl4030->master_substream = substream;
+
+       return 0;
+}
+
+static void twl4030_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_codec *codec = socdev->codec;
+       struct twl4030_priv *twl4030 = codec->private_data;
+
+       if (twl4030->master_substream == substream)
+               twl4030->master_substream = twl4030->slave_substream;
+
+       twl4030->slave_substream = NULL;
+}
+
 static int twl4030_hw_params(struct snd_pcm_substream *substream,
                           struct snd_pcm_hw_params *params,
                           struct snd_soc_dai *dai)
@@ -1224,8 +1271,13 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_device *socdev = rtd->socdev;
        struct snd_soc_codec *codec = socdev->card->codec;
+       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 */
+               return 0;
+
        /* bit rate */
        old_mode = twl4030_read_reg_cache(codec,
                        TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ;
@@ -1384,6 +1436,8 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
 #define TWL4030_FORMATS         (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
 
 static struct snd_soc_dai_ops twl4030_dai_ops = {
+       .startup        = twl4030_startup,
+       .shutdown       = twl4030_shutdown,
        .hw_params      = twl4030_hw_params,
        .set_sysclk     = twl4030_set_dai_sysclk,
        .set_fmt        = twl4030_set_dai_fmt,