158 lines · c
1/* SPDX-License-Identifier: GPL-2.02 *3 * linux/sound/soc-dpcm.h -- ALSA SoC Dynamic PCM Support4 *5 * Author: Liam Girdwood <lrg@ti.com>6 */7 8#ifndef __LINUX_SND_SOC_DPCM_H9#define __LINUX_SND_SOC_DPCM_H10 11#include <linux/slab.h>12#include <linux/list.h>13#include <sound/pcm.h>14 15struct snd_soc_pcm_runtime;16 17/*18 * Types of runtime_update to perform. e.g. originated from FE PCM ops19 * or audio route changes triggered by muxes/mixers.20 */21enum snd_soc_dpcm_update {22 SND_SOC_DPCM_UPDATE_NO = 0,23 SND_SOC_DPCM_UPDATE_BE,24 SND_SOC_DPCM_UPDATE_FE,25};26 27/*28 * Dynamic PCM Frontend -> Backend link management states.29 */30enum snd_soc_dpcm_link_state {31 SND_SOC_DPCM_LINK_STATE_NEW = 0, /* newly created link */32 SND_SOC_DPCM_LINK_STATE_FREE, /* link to be dismantled */33};34 35/*36 * Dynamic PCM Frontend -> Backend link PCM states.37 */38enum snd_soc_dpcm_state {39 SND_SOC_DPCM_STATE_NEW = 0,40 SND_SOC_DPCM_STATE_OPEN,41 SND_SOC_DPCM_STATE_HW_PARAMS,42 SND_SOC_DPCM_STATE_PREPARE,43 SND_SOC_DPCM_STATE_START,44 SND_SOC_DPCM_STATE_STOP,45 SND_SOC_DPCM_STATE_PAUSED,46 SND_SOC_DPCM_STATE_SUSPEND,47 SND_SOC_DPCM_STATE_HW_FREE,48 SND_SOC_DPCM_STATE_CLOSE,49};50 51/*52 * Dynamic PCM trigger ordering. Triggering flexibility is required as some53 * DSPs require triggering before/after their CPU platform and DAIs.54 *55 * i.e. some clients may want to manually order this call in their PCM56 * trigger() whilst others will just use the regular core ordering.57 */58enum snd_soc_dpcm_trigger {59 SND_SOC_DPCM_TRIGGER_PRE = 0,60 SND_SOC_DPCM_TRIGGER_POST,61};62 63/*64 * Dynamic PCM link65 * This links together a FE and BE DAI at runtime and stores the link66 * state information and the hw_params configuration.67 */68struct snd_soc_dpcm {69 /* FE and BE DAIs*/70 struct snd_soc_pcm_runtime *be;71 struct snd_soc_pcm_runtime *fe;72 73 /* link state */74 enum snd_soc_dpcm_link_state state;75 76 /* list of BE and FE for this DPCM link */77 struct list_head list_be;78 struct list_head list_fe;79 80#ifdef CONFIG_DEBUG_FS81 struct dentry *debugfs_state;82#endif83};84 85/*86 * Dynamic PCM runtime data.87 */88struct snd_soc_dpcm_runtime {89 struct list_head be_clients;90 struct list_head fe_clients;91 92 int users;93 struct snd_pcm_hw_params hw_params;94 95 /* state and update */96 enum snd_soc_dpcm_update runtime_update;97 enum snd_soc_dpcm_state state;98 99 int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */100 101 int be_start; /* refcount protected by BE stream pcm lock */102 int be_pause; /* refcount protected by BE stream pcm lock */103 bool fe_pause; /* used to track STOP after PAUSE */104};105 106#define for_each_dpcm_fe(be, stream, _dpcm) \107 list_for_each_entry(_dpcm, &(be)->dpcm[stream].fe_clients, list_fe)108 109#define for_each_dpcm_be(fe, stream, _dpcm) \110 list_for_each_entry(_dpcm, &(fe)->dpcm[stream].be_clients, list_be)111#define for_each_dpcm_be_safe(fe, stream, _dpcm, __dpcm) \112 list_for_each_entry_safe(_dpcm, __dpcm, &(fe)->dpcm[stream].be_clients, list_be)113#define for_each_dpcm_be_rollback(fe, stream, _dpcm) \114 list_for_each_entry_continue_reverse(_dpcm, &(fe)->dpcm[stream].be_clients, list_be)115 116 117/* get the substream for this BE */118struct snd_pcm_substream *119 snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);120 121/* update audio routing between PCMs and any DAI links */122int snd_soc_dpcm_runtime_update(struct snd_soc_card *card);123 124#ifdef CONFIG_DEBUG_FS125void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);126#else127static inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)128{129}130#endif131 132int dpcm_path_get(struct snd_soc_pcm_runtime *fe,133 int stream, struct snd_soc_dapm_widget_list **list_);134void dpcm_path_put(struct snd_soc_dapm_widget_list **list);135int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,136 int stream, struct snd_soc_dapm_widget_list **list, int new);137int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);138void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream,139 int do_hw_free, struct snd_soc_dpcm *last);140void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream);141void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream);142void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream);143int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int tream);144int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd);145int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream);146int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,147 int event);148bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, enum snd_soc_dapm_direction dir);149int widget_in_list(struct snd_soc_dapm_widget_list *list,150 struct snd_soc_dapm_widget *widget);151 152#define dpcm_be_dai_startup_rollback(fe, stream, last) \153 dpcm_be_dai_stop(fe, stream, 0, last)154#define dpcm_be_dai_startup_unwind(fe, stream) dpcm_be_dai_stop(fe, stream, 0, NULL)155#define dpcm_be_dai_shutdown(fe, stream) dpcm_be_dai_stop(fe, stream, 1, NULL)156 157#endif158