162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * linux/sound/soc-dpcm.h -- ALSA SoC Dynamic PCM Support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author:		Liam Girdwood <lrg@ti.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifndef __LINUX_SND_SOC_DPCM_H
962306a36Sopenharmony_ci#define __LINUX_SND_SOC_DPCM_H
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/list.h>
1362306a36Sopenharmony_ci#include <sound/pcm.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct snd_soc_pcm_runtime;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Types of runtime_update to perform. e.g. originated from FE PCM ops
1962306a36Sopenharmony_ci * or audio route changes triggered by muxes/mixers.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cienum snd_soc_dpcm_update {
2262306a36Sopenharmony_ci	SND_SOC_DPCM_UPDATE_NO	= 0,
2362306a36Sopenharmony_ci	SND_SOC_DPCM_UPDATE_BE,
2462306a36Sopenharmony_ci	SND_SOC_DPCM_UPDATE_FE,
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci * Dynamic PCM Frontend -> Backend link management states.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_cienum snd_soc_dpcm_link_state {
3162306a36Sopenharmony_ci	SND_SOC_DPCM_LINK_STATE_NEW	= 0,	/* newly created link */
3262306a36Sopenharmony_ci	SND_SOC_DPCM_LINK_STATE_FREE,		/* link to be dismantled */
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Dynamic PCM Frontend -> Backend link PCM states.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_cienum snd_soc_dpcm_state {
3962306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_NEW	= 0,
4062306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_OPEN,
4162306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_HW_PARAMS,
4262306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_PREPARE,
4362306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_START,
4462306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_STOP,
4562306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_PAUSED,
4662306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_SUSPEND,
4762306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_HW_FREE,
4862306a36Sopenharmony_ci	SND_SOC_DPCM_STATE_CLOSE,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/*
5262306a36Sopenharmony_ci * Dynamic PCM trigger ordering. Triggering flexibility is required as some
5362306a36Sopenharmony_ci * DSPs require triggering before/after their CPU platform and DAIs.
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * i.e. some clients may want to manually order this call in their PCM
5662306a36Sopenharmony_ci * trigger() whilst others will just use the regular core ordering.
5762306a36Sopenharmony_ci */
5862306a36Sopenharmony_cienum snd_soc_dpcm_trigger {
5962306a36Sopenharmony_ci	SND_SOC_DPCM_TRIGGER_PRE		= 0,
6062306a36Sopenharmony_ci	SND_SOC_DPCM_TRIGGER_POST,
6162306a36Sopenharmony_ci	SND_SOC_DPCM_TRIGGER_BESPOKE,
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * Dynamic PCM link
6662306a36Sopenharmony_ci * This links together a FE and BE DAI at runtime and stores the link
6762306a36Sopenharmony_ci * state information and the hw_params configuration.
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistruct snd_soc_dpcm {
7062306a36Sopenharmony_ci	/* FE and BE DAIs*/
7162306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *be;
7262306a36Sopenharmony_ci	struct snd_soc_pcm_runtime *fe;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* link state */
7562306a36Sopenharmony_ci	enum snd_soc_dpcm_link_state state;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* list of BE and FE for this DPCM link */
7862306a36Sopenharmony_ci	struct list_head list_be;
7962306a36Sopenharmony_ci	struct list_head list_fe;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
8262306a36Sopenharmony_ci	struct dentry *debugfs_state;
8362306a36Sopenharmony_ci#endif
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/*
8762306a36Sopenharmony_ci * Dynamic PCM runtime data.
8862306a36Sopenharmony_ci */
8962306a36Sopenharmony_cistruct snd_soc_dpcm_runtime {
9062306a36Sopenharmony_ci	struct list_head be_clients;
9162306a36Sopenharmony_ci	struct list_head fe_clients;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	int users;
9462306a36Sopenharmony_ci	struct snd_pcm_hw_params hw_params;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* state and update */
9762306a36Sopenharmony_ci	enum snd_soc_dpcm_update runtime_update;
9862306a36Sopenharmony_ci	enum snd_soc_dpcm_state state;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	int be_start; /* refcount protected by BE stream pcm lock */
10362306a36Sopenharmony_ci	int be_pause; /* refcount protected by BE stream pcm lock */
10462306a36Sopenharmony_ci	bool fe_pause; /* used to track STOP after PAUSE */
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define for_each_dpcm_fe(be, stream, _dpcm)				\
10862306a36Sopenharmony_ci	list_for_each_entry(_dpcm, &(be)->dpcm[stream].fe_clients, list_fe)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define for_each_dpcm_be(fe, stream, _dpcm)				\
11162306a36Sopenharmony_ci	list_for_each_entry(_dpcm, &(fe)->dpcm[stream].be_clients, list_be)
11262306a36Sopenharmony_ci#define for_each_dpcm_be_safe(fe, stream, _dpcm, __dpcm)			\
11362306a36Sopenharmony_ci	list_for_each_entry_safe(_dpcm, __dpcm, &(fe)->dpcm[stream].be_clients, list_be)
11462306a36Sopenharmony_ci#define for_each_dpcm_be_rollback(fe, stream, _dpcm)			\
11562306a36Sopenharmony_ci	list_for_each_entry_continue_reverse(_dpcm, &(fe)->dpcm[stream].be_clients, list_be)
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci/* can this BE stop and free */
11862306a36Sopenharmony_ciint snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
11962306a36Sopenharmony_ci		struct snd_soc_pcm_runtime *be, int stream);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci/* can this BE perform a hw_params() */
12262306a36Sopenharmony_ciint snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
12362306a36Sopenharmony_ci		struct snd_soc_pcm_runtime *be, int stream);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* can this BE perform prepare */
12662306a36Sopenharmony_ciint snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe,
12762306a36Sopenharmony_ci				 struct snd_soc_pcm_runtime *be, int stream);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* is the current PCM operation for this FE ? */
13062306a36Sopenharmony_ciint snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/* is the current PCM operation for this BE ? */
13362306a36Sopenharmony_ciint snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
13462306a36Sopenharmony_ci		struct snd_soc_pcm_runtime *be, int stream);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci/* get the substream for this BE */
13762306a36Sopenharmony_cistruct snd_pcm_substream *
13862306a36Sopenharmony_ci	snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci/* update audio routing between PCMs and any DAI links */
14162306a36Sopenharmony_ciint snd_soc_dpcm_runtime_update(struct snd_soc_card *card);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
14462306a36Sopenharmony_civoid soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
14562306a36Sopenharmony_ci#else
14662306a36Sopenharmony_cistatic inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci#endif
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ciint dpcm_path_get(struct snd_soc_pcm_runtime *fe,
15262306a36Sopenharmony_ci	int stream, struct snd_soc_dapm_widget_list **list_);
15362306a36Sopenharmony_civoid dpcm_path_put(struct snd_soc_dapm_widget_list **list);
15462306a36Sopenharmony_ciint dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
15562306a36Sopenharmony_ci	int stream, struct snd_soc_dapm_widget_list **list, int new);
15662306a36Sopenharmony_ciint dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);
15762306a36Sopenharmony_civoid dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,
15862306a36Sopenharmony_ci		      int do_hw_free, struct snd_soc_dpcm *last);
15962306a36Sopenharmony_civoid dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream);
16062306a36Sopenharmony_civoid dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream);
16162306a36Sopenharmony_civoid dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream);
16262306a36Sopenharmony_ciint dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int tream);
16362306a36Sopenharmony_ciint dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd);
16462306a36Sopenharmony_ciint dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream);
16562306a36Sopenharmony_ciint dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
16662306a36Sopenharmony_ci	int event);
16762306a36Sopenharmony_cibool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, enum snd_soc_dapm_direction dir);
16862306a36Sopenharmony_ciint widget_in_list(struct snd_soc_dapm_widget_list *list,
16962306a36Sopenharmony_ci		   struct snd_soc_dapm_widget *widget);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#define dpcm_be_dai_startup_rollback(fe, stream, last)	\
17262306a36Sopenharmony_ci						dpcm_be_dai_stop(fe, stream, 0, last)
17362306a36Sopenharmony_ci#define dpcm_be_dai_startup_unwind(fe, stream)	dpcm_be_dai_stop(fe, stream, 0, NULL)
17462306a36Sopenharmony_ci#define dpcm_be_dai_shutdown(fe, stream)	dpcm_be_dai_stop(fe, stream, 1, NULL)
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci#endif
177