summaryrefslogtreecommitdiff
path: root/sound/soc/soc-pcm.c
diff options
context:
space:
mode:
authorJerome Brunet <jbrunet@baylibre.com>2018-07-05 12:13:49 +0200
committerMark Brown <broonie@kernel.org>2018-07-11 11:58:41 +0100
commitbaacd8d100d571aa713c3c60b1471b9962e6ec8a (patch)
tree6c085dd5f4cfb219f3a2b177630b528300c4f2ff /sound/soc/soc-pcm.c
parent435ffb76f8b35be108a52bf1c43233a57b3c72b4 (diff)
ASoC: dpcm: add rate merge to the BE stream merge
As done for format and channels, add the possibility to merge the backend rates on the frontend rates. This useful if the backend does not support all rates supported by the frontend, or if several backends (cpu and codecs) with different capabilities are connected to the same frontend. Signed-off-by: Jerome Brunet <jbrunet@baylibre.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r--sound/soc/soc-pcm.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 114e6c060cae..4019bc10897c 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1769,6 +1769,64 @@ static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
}
}
+static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
+ unsigned int *rates,
+ unsigned int *rate_min,
+ unsigned int *rate_max)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ struct snd_soc_dpcm *dpcm;
+ int stream = substream->stream;
+
+ if (!fe->dai_link->dpcm_merged_rate)
+ return;
+
+ /*
+ * It returns merged BE codec channel;
+ * if FE want to use it (= dpcm_merged_chan)
+ */
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_soc_dai_driver *cpu_dai_drv = be->cpu_dai->driver;
+ struct snd_soc_dai_driver *codec_dai_drv;
+ struct snd_soc_pcm_stream *codec_stream;
+ struct snd_soc_pcm_stream *cpu_stream;
+ int i;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_stream = &cpu_dai_drv->playback;
+ else
+ cpu_stream = &cpu_dai_drv->capture;
+
+ *rate_min = max(*rate_min, cpu_stream->rate_min);
+ *rate_max = min_not_zero(*rate_max, cpu_stream->rate_max);
+ *rates = snd_pcm_rate_mask_intersect(*rates, cpu_stream->rates);
+
+ for (i = 0; i < be->num_codecs; i++) {
+ /*
+ * Skip CODECs which don't support the current stream
+ * type. See soc_pcm_init_runtime_hw() for more details
+ */
+ if (!snd_soc_dai_stream_valid(be->codec_dais[i],
+ stream))
+ continue;
+
+ codec_dai_drv = be->codec_dais[i]->driver;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ codec_stream = &codec_dai_drv->playback;
+ else
+ codec_stream = &codec_dai_drv->capture;
+
+ *rate_min = max(*rate_min, codec_stream->rate_min);
+ *rate_max = min_not_zero(*rate_max,
+ codec_stream->rate_max);
+ *rates = snd_pcm_rate_mask_intersect(*rates,
+ codec_stream->rates);
+ }
+ }
+}
+
static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1784,6 +1842,8 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
dpcm_runtime_merge_format(substream, &runtime->hw.formats);
dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
&runtime->hw.channels_max);
+ dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
+ &runtime->hw.rate_min, &runtime->hw.rate_max);
}
static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);