summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/soc-pcm.c99
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)
{