diff options
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r-- | sound/soc/soc-pcm.c | 165 |
1 files changed, 86 insertions, 79 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 19ebfc958b9d..63f96cde046a 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2597,106 +2597,113 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) return ret; } -/* Called by DAPM mixer/mux changes to update audio routing between PCMs and - * any DAI links. - */ -int soc_dpcm_runtime_update(struct snd_soc_card *card) +static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) { - struct snd_soc_pcm_runtime *fe; - int old, new, paths; + struct snd_soc_dapm_widget_list *list; + int count, paths; - mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - list_for_each_entry(fe, &card->rtd_list, list) { - struct snd_soc_dapm_widget_list *list; + if (!fe->dai_link->dynamic) + return 0; - /* make sure link is FE */ - if (!fe->dai_link->dynamic) - continue; + /* only check active links */ + if (!fe->cpu_dai->active) + return 0; - /* only check active links */ - if (!fe->cpu_dai->active) - continue; + /* DAPM sync will call this to update DSP paths */ + dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s\n", + new ? "new" : "old", fe->dai_link->name); - /* DAPM sync will call this to update DSP paths */ - dev_dbg(fe->dev, "ASoC: DPCM runtime update for FE %s\n", - fe->dai_link->name); + /* skip if FE doesn't have playback capability */ + if (!fe->cpu_dai->driver->playback.channels_min || + !fe->codec_dai->driver->playback.channels_min) + goto capture; - /* skip if FE doesn't have playback capability */ - if (!fe->cpu_dai->driver->playback.channels_min - || !fe->codec_dai->driver->playback.channels_min) - goto capture; - - /* skip if FE isn't currently playing */ - if (!fe->cpu_dai->playback_active - || !fe->codec_dai->playback_active) - goto capture; - - paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); - if (paths < 0) { - dev_warn(fe->dev, "ASoC: %s no valid %s path\n", - fe->dai_link->name, "playback"); - mutex_unlock(&card->mutex); - return paths; - } + /* skip if FE isn't currently playing */ + if (!fe->cpu_dai->playback_active || !fe->codec_dai->playback_active) + goto capture; - /* update any new playback paths */ - new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1); - if (new) { - dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK); - dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); - dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); - } + paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); + if (paths < 0) { + dev_warn(fe->dev, "ASoC: %s no valid %s path\n", + fe->dai_link->name, "playback"); + return paths; + } - /* update any old playback paths */ - old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0); - if (old) { + /* update any playback paths */ + count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, new); + if (count) { + if (new) + dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK); + else dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK); - dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); - dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); - } - dpcm_path_put(&list); + dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK); + dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); + } + + dpcm_path_put(&list); + capture: - /* skip if FE doesn't have capture capability */ - if (!fe->cpu_dai->driver->capture.channels_min - || !fe->codec_dai->driver->capture.channels_min) - continue; + /* skip if FE doesn't have capture capability */ + if (!fe->cpu_dai->driver->capture.channels_min || + !fe->codec_dai->driver->capture.channels_min) + return 0; - /* skip if FE isn't currently capturing */ - if (!fe->cpu_dai->capture_active - || !fe->codec_dai->capture_active) - continue; + /* skip if FE isn't currently capturing */ + if (!fe->cpu_dai->capture_active || !fe->codec_dai->capture_active) + return 0; - paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); - if (paths < 0) { - dev_warn(fe->dev, "ASoC: %s no valid %s path\n", - fe->dai_link->name, "capture"); - mutex_unlock(&card->mutex); - return paths; - } + paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); + if (paths < 0) { + dev_warn(fe->dev, "ASoC: %s no valid %s path\n", + fe->dai_link->name, "capture"); + return paths; + } - /* update any new capture paths */ - new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1); - if (new) { + /* update any old capture paths */ + count = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, new); + if (count) { + if (new) dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE); - dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); - dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); - } - - /* update any old capture paths */ - old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0); - if (old) { + else dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE); - dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); - dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); - } - dpcm_path_put(&list); + dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE); + dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE); } - mutex_unlock(&card->mutex); + dpcm_path_put(&list); + return 0; } + +/* Called by DAPM mixer/mux changes to update audio routing between PCMs and + * any DAI links. + */ +int soc_dpcm_runtime_update(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *fe; + int ret = 0; + + mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + /* shutdown all old paths first */ + list_for_each_entry(fe, &card->rtd_list, list) { + ret = soc_dpcm_fe_runtime_update(fe, 0); + if (ret) + goto out; + } + + /* bring new paths up */ + list_for_each_entry(fe, &card->rtd_list, list) { + ret = soc_dpcm_fe_runtime_update(fe, 1); + if (ret) + goto out; + } + +out: + mutex_unlock(&card->mutex); + return ret; +} int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) { struct snd_soc_dpcm *dpcm; |