|
@@ -632,6 +632,33 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|
return 0;
|
|
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
|
|
* soc level wrapper for pointer callback
|
|
* If cpu_dai, codec_dai, platform driver has the delay callback, than
|
|
* 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);
|
|
ret = soc_pcm_trigger(substream, cmd);
|
|
break;
|
|
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:
|
|
default:
|
|
dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd,
|
|
dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd,
|
|
fe->dai_link->name);
|
|
fe->dai_link->name);
|
|
@@ -1610,14 +1649,30 @@ out:
|
|
|
|
|
|
static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
|
|
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;
|
|
int err;
|
|
|
|
|
|
dev_dbg(fe->dev, "runtime %s close on FE %s\n",
|
|
dev_dbg(fe->dev, "runtime %s close on FE %s\n",
|
|
stream ? "capture" : "playback", fe->dai_link->name);
|
|
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);
|
|
err = dpcm_be_dai_hw_free(fe, stream);
|
|
if (err < 0)
|
|
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)
|
|
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;
|
|
struct snd_soc_dpcm *dpcm;
|
|
|
|
+ enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
dev_dbg(fe->dev, "runtime %s open on FE %s\n",
|
|
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)
|
|
fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
|
|
return 0;
|
|
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;
|
|
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);
|
|
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
|
|
#ifdef CONFIG_DEBUG_FS
|
|
static char *dpcm_state_string(enum snd_soc_dpcm_state state)
|
|
static char *dpcm_state_string(enum snd_soc_dpcm_state state)
|
|
{
|
|
{
|