forked from Minki/linux
ASoC: dapm: Add support for multi-CODEC CODEC to CODEC links
Currently multi-CODEC is not supported on CODEC to CODEC links. There are common applications where this would be useful, such as connecting two mono amplifiers to an audio CODEC. Adding support simply requires an update of snd_soc_dai_link_event to loop over the attached CODEC DAIs. Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
778ff5bb86
commit
4a75aae17b
@ -3614,7 +3614,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
|
|||||||
static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
|
static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
|
||||||
struct snd_kcontrol *kcontrol, int event)
|
struct snd_kcontrol *kcontrol, int event)
|
||||||
{
|
{
|
||||||
struct snd_soc_dapm_path *source_p, *sink_p;
|
struct snd_soc_dapm_path *path;
|
||||||
struct snd_soc_dai *source, *sink;
|
struct snd_soc_dai *source, *sink;
|
||||||
struct snd_soc_pcm_runtime *rtd = w->priv;
|
struct snd_soc_pcm_runtime *rtd = w->priv;
|
||||||
const struct snd_soc_pcm_stream *config = w->params + w->params_select;
|
const struct snd_soc_pcm_stream *config = w->params + w->params_select;
|
||||||
@ -3629,17 +3629,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
|
|||||||
list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
|
list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* We only support a single source and sink, pick the first */
|
|
||||||
source_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_OUT],
|
|
||||||
struct snd_soc_dapm_path,
|
|
||||||
list_node[SND_SOC_DAPM_DIR_OUT]);
|
|
||||||
sink_p = list_first_entry(&w->edges[SND_SOC_DAPM_DIR_IN],
|
|
||||||
struct snd_soc_dapm_path,
|
|
||||||
list_node[SND_SOC_DAPM_DIR_IN]);
|
|
||||||
|
|
||||||
source = source_p->source->priv;
|
|
||||||
sink = sink_p->sink->priv;
|
|
||||||
|
|
||||||
/* Be a little careful as we don't want to overflow the mask array */
|
/* Be a little careful as we don't want to overflow the mask array */
|
||||||
if (config->formats) {
|
if (config->formats) {
|
||||||
fmt = ffs(config->formats) - 1;
|
fmt = ffs(config->formats) - 1;
|
||||||
@ -3681,59 +3670,90 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
case SND_SOC_DAPM_PRE_PMU:
|
case SND_SOC_DAPM_PRE_PMU:
|
||||||
substream.stream = SNDRV_PCM_STREAM_CAPTURE;
|
substream.stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||||
if (source->driver->ops->startup) {
|
snd_soc_dapm_widget_for_each_source_path(w, path) {
|
||||||
ret = source->driver->ops->startup(&substream, source);
|
source = path->source->priv;
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(source->dev,
|
if (source->driver->ops->startup) {
|
||||||
"ASoC: startup() failed: %d\n", ret);
|
ret = source->driver->ops->startup(&substream,
|
||||||
goto out;
|
source);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(source->dev,
|
||||||
|
"ASoC: startup() failed: %d\n",
|
||||||
|
ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
source->active++;
|
||||||
}
|
}
|
||||||
source->active++;
|
ret = soc_dai_hw_params(&substream, params, source);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
ret = soc_dai_hw_params(&substream, params, source);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
|
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||||
if (sink->driver->ops->startup) {
|
snd_soc_dapm_widget_for_each_sink_path(w, path) {
|
||||||
ret = sink->driver->ops->startup(&substream, sink);
|
sink = path->sink->priv;
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(sink->dev,
|
if (sink->driver->ops->startup) {
|
||||||
"ASoC: startup() failed: %d\n", ret);
|
ret = sink->driver->ops->startup(&substream,
|
||||||
goto out;
|
sink);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(sink->dev,
|
||||||
|
"ASoC: startup() failed: %d\n",
|
||||||
|
ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
sink->active++;
|
||||||
}
|
}
|
||||||
sink->active++;
|
ret = soc_dai_hw_params(&substream, params, sink);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
ret = soc_dai_hw_params(&substream, params, sink);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SND_SOC_DAPM_POST_PMU:
|
case SND_SOC_DAPM_POST_PMU:
|
||||||
ret = snd_soc_dai_digital_mute(sink, 0,
|
snd_soc_dapm_widget_for_each_sink_path(w, path) {
|
||||||
SNDRV_PCM_STREAM_PLAYBACK);
|
sink = path->sink->priv;
|
||||||
if (ret != 0 && ret != -ENOTSUPP)
|
|
||||||
dev_warn(sink->dev, "ASoC: Failed to unmute: %d\n", ret);
|
ret = snd_soc_dai_digital_mute(sink, 0,
|
||||||
ret = 0;
|
SNDRV_PCM_STREAM_PLAYBACK);
|
||||||
|
if (ret != 0 && ret != -ENOTSUPP)
|
||||||
|
dev_warn(sink->dev,
|
||||||
|
"ASoC: Failed to unmute: %d\n", ret);
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SND_SOC_DAPM_PRE_PMD:
|
case SND_SOC_DAPM_PRE_PMD:
|
||||||
ret = snd_soc_dai_digital_mute(sink, 1,
|
snd_soc_dapm_widget_for_each_sink_path(w, path) {
|
||||||
SNDRV_PCM_STREAM_PLAYBACK);
|
sink = path->sink->priv;
|
||||||
if (ret != 0 && ret != -ENOTSUPP)
|
|
||||||
dev_warn(sink->dev, "ASoC: Failed to mute: %d\n", ret);
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
source->active--;
|
ret = snd_soc_dai_digital_mute(sink, 1,
|
||||||
if (source->driver->ops->shutdown) {
|
SNDRV_PCM_STREAM_PLAYBACK);
|
||||||
substream.stream = SNDRV_PCM_STREAM_CAPTURE;
|
if (ret != 0 && ret != -ENOTSUPP)
|
||||||
source->driver->ops->shutdown(&substream, source);
|
dev_warn(sink->dev,
|
||||||
|
"ASoC: Failed to mute: %d\n", ret);
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sink->active--;
|
snd_soc_dapm_widget_for_each_source_path(w, path) {
|
||||||
if (sink->driver->ops->shutdown) {
|
source = path->source->priv;
|
||||||
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
|
|
||||||
sink->driver->ops->shutdown(&substream, sink);
|
source->active--;
|
||||||
|
if (source->driver->ops->shutdown) {
|
||||||
|
substream.stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||||
|
source->driver->ops->shutdown(&substream,
|
||||||
|
source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_soc_dapm_widget_for_each_sink_path(w, path) {
|
||||||
|
sink = path->sink->priv;
|
||||||
|
|
||||||
|
sink->active--;
|
||||||
|
if (sink->driver->ops->shutdown) {
|
||||||
|
substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||||
|
sink->driver->ops->shutdown(&substream, sink);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -4043,9 +4063,6 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (rtd->dai_link->params) {
|
if (rtd->dai_link->params) {
|
||||||
if (rtd->num_codecs > 1)
|
|
||||||
dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n");
|
|
||||||
|
|
||||||
playback_cpu = cpu_dai->capture_widget;
|
playback_cpu = cpu_dai->capture_widget;
|
||||||
capture_cpu = cpu_dai->playback_widget;
|
capture_cpu = cpu_dai->playback_widget;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user