diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h index 0b47603c9db2..87f248a06271 100644 --- a/include/sound/soc-component.h +++ b/include/sound/soc-component.h @@ -158,6 +158,15 @@ struct snd_soc_component_driver { int probe_order; int remove_order; + /* + * soc_pcm_trigger() start/stop sequence. + * see also + * snd_soc_dai_link + * soc_pcm_trigger() + */ + enum snd_soc_trigger_order trigger_start; + enum snd_soc_trigger_order trigger_stop; + /* * signal if the module handling the component should not be removed * if a pcm is open. Setting this would prevent the module @@ -190,8 +199,6 @@ struct snd_soc_component_driver { bool use_dai_pcm_id; /* use DAI link PCM ID as PCM device number */ int be_pcm_base; /* base device ID for all BE PCMs */ - unsigned int start_dma_last; - #ifdef CONFIG_DEBUG_FS const char *debugfs_prefix; #endif diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e48a1135844..a7ae8b26737e 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -607,6 +607,14 @@ int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +enum snd_soc_trigger_order { + /* start stop */ + SND_SOC_TRIGGER_ORDER_DEFAULT = 0, /* Link->Component->DAI DAI->Component->Link */ + SND_SOC_TRIGGER_ORDER_LDC, /* Link->DAI->Component Component->DAI->Link */ + + SND_SOC_TRIGGER_ORDER_MAX, +}; + /* SoC PCM stream information */ struct snd_soc_pcm_stream { const char *stream_name; @@ -713,6 +721,15 @@ struct snd_soc_dai_link { const struct snd_soc_ops *ops; const struct snd_soc_compr_ops *compr_ops; + /* + * soc_pcm_trigger() start/stop sequence. + * see also + * snd_soc_component_driver + * soc_pcm_trigger() + */ + enum snd_soc_trigger_order trigger_start; + enum snd_soc_trigger_order trigger_stop; + /* Mark this pcm with non atomic ops */ unsigned int nonatomic:1; @@ -751,12 +768,6 @@ struct snd_soc_dai_link { /* Do not create a PCM for this DAI link (Backend link) */ unsigned int ignore:1; - /* This flag will reorder stop sequence. By enabling this flag - * DMA controller stop sequence will be invoked first followed by - * CPU DAI driver stop sequence - */ - unsigned int stop_dma_first:1; - #ifdef CONFIG_SND_SOC_TOPOLOGY struct snd_soc_dobj dobj; /* For topology */ #endif diff --git a/sound/soc/amd/acp-da7219-max98357a.c b/sound/soc/amd/acp-da7219-max98357a.c index 375417bd7d6e..7464ca2b596c 100644 --- a/sound/soc/amd/acp-da7219-max98357a.c +++ b/sound/soc/amd/acp-da7219-max98357a.c @@ -524,7 +524,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { | SND_SOC_DAIFMT_CBP_CFP, .init = cz_da7219_init, .dpcm_playback = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_da7219_play_ops, SND_SOC_DAILINK_REG(designware1, dlgs, platform), }, @@ -534,7 +534,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_da7219_cap_ops, SND_SOC_DAILINK_REG(designware2, dlgs, platform), }, @@ -544,7 +544,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_playback = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_max_play_ops, SND_SOC_DAILINK_REG(designware3, mx, platform), }, @@ -555,7 +555,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_dmic0_cap_ops, SND_SOC_DAILINK_REG(designware3, adau, platform), }, @@ -566,7 +566,7 @@ static struct snd_soc_dai_link cz_dai_7219_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_dmic1_cap_ops, SND_SOC_DAILINK_REG(designware2, adau, platform), }, @@ -580,7 +580,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { | SND_SOC_DAIFMT_CBP_CFP, .init = cz_rt5682_init, .dpcm_playback = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_play_ops, SND_SOC_DAILINK_REG(designware1, rt5682, platform), }, @@ -590,7 +590,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_cap_ops, SND_SOC_DAILINK_REG(designware2, rt5682, platform), }, @@ -600,7 +600,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_playback = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_max_play_ops, SND_SOC_DAILINK_REG(designware3, mx, platform), }, @@ -611,7 +611,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_dmic0_cap_ops, SND_SOC_DAILINK_REG(designware3, adau, platform), }, @@ -622,7 +622,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, .dpcm_capture = 1, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .ops = &cz_rt5682_dmic1_cap_ops, SND_SOC_DAILINK_REG(designware2, adau, platform), }, diff --git a/sound/soc/amd/acp-es8336.c b/sound/soc/amd/acp-es8336.c index 89499542c803..5e56d3a53be7 100644 --- a/sound/soc/amd/acp-es8336.c +++ b/sound/soc/amd/acp-es8336.c @@ -149,7 +149,7 @@ static struct snd_soc_dai_link st_dai_es8336[] = { .stream_name = "ES8336 HiFi Play", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP, - .stop_dma_first = 1, + .trigger_stop = SND_SOC_TRIGGER_ORDER_LDC, .dpcm_capture = 1, .dpcm_playback = 1, .init = st_es8336_init, diff --git a/sound/soc/atmel/mchp-pdmc.c b/sound/soc/atmel/mchp-pdmc.c index da23855a0e40..c79c73e6791e 100644 --- a/sound/soc/atmel/mchp-pdmc.c +++ b/sound/soc/atmel/mchp-pdmc.c @@ -423,7 +423,7 @@ static const struct snd_soc_component_driver mchp_pdmc_dai_component = { .open = &mchp_pdmc_open, .close = &mchp_pdmc_close, .legacy_dai_naming = 1, - .start_dma_last = 1, + .trigger_start = SND_SOC_TRIGGER_ORDER_LDC, }; static const unsigned int mchp_pdmc_1mic[] = {1}; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 60cfbe565759..6fc90bc25317 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1094,49 +1094,67 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, return ret; } +#define TRIGGER_MAX 3 +static int (* const trigger[][TRIGGER_MAX])(struct snd_pcm_substream *substream, int cmd, int rollback) = { + [SND_SOC_TRIGGER_ORDER_DEFAULT] = { + snd_soc_link_trigger, + snd_soc_pcm_component_trigger, + snd_soc_pcm_dai_trigger, + }, + [SND_SOC_TRIGGER_ORDER_LDC] = { + snd_soc_link_trigger, + snd_soc_pcm_dai_trigger, + snd_soc_pcm_component_trigger, + }, +}; + static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_component *component; - int ret = -EINVAL, _ret = 0, start_dma_last = 0, i; + int ret = 0, r = 0, i; int rollback = 0; + int start = 0, stop = 0; + /* + * select START/STOP sequence + */ + for_each_rtd_components(rtd, i, component) { + if (component->driver->trigger_start) + start = component->driver->trigger_start; + if (component->driver->trigger_stop) + stop = component->driver->trigger_stop; + } + if (rtd->dai_link->trigger_start) + start = rtd->dai_link->trigger_start; + if (rtd->dai_link->trigger_stop) + stop = rtd->dai_link->trigger_stop; + + if (start < 0 || start >= SND_SOC_TRIGGER_ORDER_MAX || + stop < 0 || stop >= SND_SOC_TRIGGER_ORDER_MAX) + return -EINVAL; + + /* + * START + */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - /* Do we need to start dma last? */ - for_each_rtd_components(rtd, i, component) { - if (component->driver->start_dma_last) { - start_dma_last = 1; + for (i = 0; i < TRIGGER_MAX; i++) { + r = trigger[start][i](substream, cmd, 0); + if (r < 0) break; - } } - - ret = snd_soc_link_trigger(substream, cmd, 0); - if (ret < 0) - goto start_err; - - if (start_dma_last) { - ret = snd_soc_pcm_dai_trigger(substream, cmd, 0); - if (ret < 0) - goto start_err; - - ret = snd_soc_pcm_component_trigger(substream, cmd, 0); - } else { - ret = snd_soc_pcm_component_trigger(substream, cmd, 0); - if (ret < 0) - goto start_err; - - ret = snd_soc_pcm_dai_trigger(substream, cmd, 0); - } -start_err: - if (ret < 0) - rollback = 1; } - if (rollback) { - _ret = ret; + /* + * Rollback if START failed + * find correspond STOP command + */ + if (r < 0) { + rollback = 1; + ret = r; switch (cmd) { case SNDRV_PCM_TRIGGER_START: cmd = SNDRV_PCM_TRIGGER_STOP; @@ -1150,34 +1168,20 @@ start_err: } } + /* + * STOP + */ switch (cmd) { case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (rtd->dai_link->stop_dma_first) { - ret = snd_soc_pcm_component_trigger(substream, cmd, rollback); - if (ret < 0) - break; - - ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback); - if (ret < 0) - break; - } else { - ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback); - if (ret < 0) - break; - - ret = snd_soc_pcm_component_trigger(substream, cmd, rollback); - if (ret < 0) - break; + for (i = TRIGGER_MAX; i > 0; i--) { + r = trigger[stop][i - 1](substream, cmd, rollback); + if (r < 0) + ret = r; } - ret = snd_soc_link_trigger(substream, cmd, rollback); - break; } - if (_ret) - ret = _ret; - return ret; } diff --git a/sound/soc/starfive/jh7110_tdm.c b/sound/soc/starfive/jh7110_tdm.c index e4bdba20c499..5f5a6ca7dbda 100644 --- a/sound/soc/starfive/jh7110_tdm.c +++ b/sound/soc/starfive/jh7110_tdm.c @@ -328,7 +328,7 @@ static int jh7110_tdm_startup(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); struct snd_soc_dai_link *dai_link = rtd->dai_link; - dai_link->stop_dma_first = 1; + dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; return 0; }