summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dapm.h22
-rw-r--r--sound/soc/soc-dapm.c76
-rw-r--r--sound/soc/soc-pcm.c4
3 files changed, 94 insertions, 8 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 46f2ba3ffcb7..79b4ddfb8e9e 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -214,21 +214,21 @@ struct device;
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
/* stream domain */
-#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
+#define SND_SOC_DAPM_AIF_IN(wname, stname, wchan, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
- SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
-#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
+ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
+#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wchan, wreg, wshift, winvert, \
wevent, wflags) \
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
- SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags }
-#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
+#define SND_SOC_DAPM_AIF_OUT(wname, stname, wchan, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
- SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
-#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
+ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
+#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wchan, wreg, wshift, winvert, \
wevent, wflags) \
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
- SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+ .channel = wchan, SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags }
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
@@ -407,6 +407,10 @@ int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card);
+int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
+
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_card *card);
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
@@ -627,6 +631,8 @@ struct snd_soc_dapm_widget {
int endpoints[2];
struct clk *clk;
+
+ int channel;
};
struct snd_soc_dapm_update {
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index e71cd5b660ad..36d964a52874 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2541,6 +2541,78 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
+static int dapm_update_dai_chan(struct snd_soc_dapm_path *p,
+ struct snd_soc_dapm_widget *w,
+ int channels)
+{
+ switch (w->id) {
+ case snd_soc_dapm_aif_out:
+ case snd_soc_dapm_aif_in:
+ break;
+ default:
+ return 0;
+ }
+
+ dev_dbg(w->dapm->dev, "%s DAI route %s -> %s\n",
+ w->channel < channels ? "Connecting" : "Disconnecting",
+ p->source->name, p->sink->name);
+
+ if (w->channel < channels)
+ soc_dapm_connect_path(p, true, "dai update");
+ else
+ soc_dapm_connect_path(p, false, "dai update");
+
+ return 0;
+}
+
+static int dapm_update_dai_unlocked(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ int dir = substream->stream;
+ int channels = params_channels(params);
+ struct snd_soc_dapm_path *p;
+ struct snd_soc_dapm_widget *w;
+ int ret;
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK)
+ w = dai->playback_widget;
+ else
+ w = dai->capture_widget;
+
+ dev_dbg(dai->dev, "Update DAI routes for %s %s\n", dai->name,
+ dir == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture");
+
+ snd_soc_dapm_widget_for_each_sink_path(w, p) {
+ ret = dapm_update_dai_chan(p, p->sink, channels);
+ if (ret < 0)
+ return ret;
+ }
+
+ snd_soc_dapm_widget_for_each_source_path(w, p) {
+ ret = dapm_update_dai_chan(p, p->source, channels);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ int ret;
+
+ mutex_lock_nested(&rtd->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ ret = dapm_update_dai_unlocked(substream, params, dai);
+ mutex_unlock(&rtd->card->dapm_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai);
+
/*
* dapm_update_widget_flags() - Re-compute widget sink and source flags
* @w: The widget for which to update the flags
@@ -3706,6 +3778,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
ret = soc_dai_hw_params(&substream, params, source);
if (ret < 0)
goto out;
+
+ dapm_update_dai_unlocked(&substream, params, source);
}
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
@@ -3726,6 +3800,8 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
ret = soc_dai_hw_params(&substream, params, sink);
if (ret < 0)
goto out;
+
+ dapm_update_dai_unlocked(&substream, params, sink);
}
break;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 03f36e534050..a5b40e82dea4 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -969,6 +969,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
codec_dai->channels = params_channels(&codec_params);
codec_dai->sample_bits = snd_pcm_format_physical_width(
params_format(&codec_params));
+
+ snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
}
ret = soc_dai_hw_params(substream, params, cpu_dai);
@@ -998,6 +1000,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
cpu_dai->sample_bits =
snd_pcm_format_physical_width(params_format(params));
+ snd_soc_dapm_update_dai(substream, params, cpu_dai);
+
ret = soc_pcm_params_symmetry(substream, params);
if (ret)
goto component_err;