diff options
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r-- | sound/soc/soc-pcm.c | 99 |
1 files changed, 89 insertions, 10 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index ca36fd6746f..5bd8270beea 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -632,6 +632,33 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return 0; } +int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + if (codec_dai->driver->ops->bespoke_trigger) { + ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); + if (ret < 0) + return ret; + } + + if (platform->driver->bespoke_trigger) { + ret = platform->driver->bespoke_trigger(substream, cmd); + if (ret < 0) + return ret; + } + + if (cpu_dai->driver->ops->bespoke_trigger) { + ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai); + if (ret < 0) + return ret; + } + return 0; +} /* * soc level wrapper for pointer callback * If cpu_dai, codec_dai, platform driver has the delay callback, than @@ -1507,6 +1534,18 @@ int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) ret = soc_pcm_trigger(substream, cmd); break; + case SND_SOC_DPCM_TRIGGER_BESPOKE: + /* bespoke trigger() - handles both FE and BEs */ + + dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); + + ret = soc_pcm_bespoke_trigger(substream, cmd); + if (ret < 0) { + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + goto out; + } + break; default: dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd, fe->dai_link->name); @@ -1610,14 +1649,30 @@ out: static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) { + struct snd_pcm_substream *substream = + snd_soc_dpcm_get_substream(fe, stream); + enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int err; dev_dbg(fe->dev, "runtime %s close on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); - err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); - if (err < 0) - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); + if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { + /* call bespoke trigger - FE takes care of all BE triggers */ + dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n", + fe->dai_link->name); + + err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP); + if (err < 0) + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); + } else { + dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n", + fe->dai_link->name); + + err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP); + if (err < 0) + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err); + } err = dpcm_be_dai_hw_free(fe, stream); if (err < 0) @@ -1635,7 +1690,10 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream) static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) { + struct snd_pcm_substream *substream = + snd_soc_dpcm_get_substream(fe, stream); struct snd_soc_dpcm *dpcm; + enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int ret; dev_dbg(fe->dev, "runtime %s open on FE %s\n", @@ -1682,14 +1740,26 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP) return 0; - dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", - fe->dai_link->name); + if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) { + /* call trigger on the frontend - FE takes care of all BE triggers */ + dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n", + fe->dai_link->name); - ret = dpcm_be_dai_trigger(fe, stream, - SNDRV_PCM_TRIGGER_START); - if (ret < 0) { - dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); - goto hw_free; + ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret); + goto hw_free; + } + } else { + dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n", + fe->dai_link->name); + + ret = dpcm_be_dai_trigger(fe, stream, + SNDRV_PCM_TRIGGER_START); + if (ret < 0) { + dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret); + goto hw_free; + } } return 0; @@ -2120,6 +2190,15 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, } EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); +int snd_soc_platform_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_platform *platform) +{ + if (platform->driver->ops->trigger) + return platform->driver->ops->trigger(substream, cmd); + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_platform_trigger); + #ifdef CONFIG_DEBUG_FS static char *dpcm_state_string(enum snd_soc_dpcm_state state) { |