cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

soc-dai.c (21737B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// soc-dai.c
      4//
      5// Copyright (C) 2019 Renesas Electronics Corp.
      6// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
      7//
      8
      9#include <sound/soc.h>
     10#include <sound/soc-dai.h>
     11#include <sound/soc-link.h>
     12
     13#define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
     14static inline int _soc_dai_ret(struct snd_soc_dai *dai,
     15			       const char *func, int ret)
     16{
     17	/* Positive, Zero values are not errors */
     18	if (ret >= 0)
     19		return ret;
     20
     21	/* Negative values might be errors */
     22	switch (ret) {
     23	case -EPROBE_DEFER:
     24	case -ENOTSUPP:
     25		break;
     26	default:
     27		dev_err(dai->dev,
     28			"ASoC: error at %s on %s: %d\n",
     29			func, dai->name, ret);
     30	}
     31
     32	return ret;
     33}
     34
     35/*
     36 * We might want to check substream by using list.
     37 * In such case, we can update these macros.
     38 */
     39#define soc_dai_mark_push(dai, substream, tgt)	((dai)->mark_##tgt = substream)
     40#define soc_dai_mark_pop(dai, substream, tgt)	((dai)->mark_##tgt = NULL)
     41#define soc_dai_mark_match(dai, substream, tgt)	((dai)->mark_##tgt == substream)
     42
     43/**
     44 * snd_soc_dai_set_sysclk - configure DAI system or master clock.
     45 * @dai: DAI
     46 * @clk_id: DAI specific clock ID
     47 * @freq: new clock frequency in Hz
     48 * @dir: new clock direction - input/output.
     49 *
     50 * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
     51 */
     52int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
     53			   unsigned int freq, int dir)
     54{
     55	int ret;
     56
     57	if (dai->driver->ops &&
     58	    dai->driver->ops->set_sysclk)
     59		ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
     60	else
     61		ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
     62						   freq, dir);
     63
     64	return soc_dai_ret(dai, ret);
     65}
     66EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
     67
     68/**
     69 * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
     70 * @dai: DAI
     71 * @div_id: DAI specific clock divider ID
     72 * @div: new clock divisor.
     73 *
     74 * Configures the clock dividers. This is used to derive the best DAI bit and
     75 * frame clocks from the system or master clock. It's best to set the DAI bit
     76 * and frame clocks as low as possible to save system power.
     77 */
     78int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
     79			   int div_id, int div)
     80{
     81	int ret = -EINVAL;
     82
     83	if (dai->driver->ops &&
     84	    dai->driver->ops->set_clkdiv)
     85		ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
     86
     87	return soc_dai_ret(dai, ret);
     88}
     89EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
     90
     91/**
     92 * snd_soc_dai_set_pll - configure DAI PLL.
     93 * @dai: DAI
     94 * @pll_id: DAI specific PLL ID
     95 * @source: DAI specific source for the PLL
     96 * @freq_in: PLL input clock frequency in Hz
     97 * @freq_out: requested PLL output clock frequency in Hz
     98 *
     99 * Configures and enables PLL to generate output clock based on input clock.
    100 */
    101int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
    102			unsigned int freq_in, unsigned int freq_out)
    103{
    104	int ret;
    105
    106	if (dai->driver->ops &&
    107	    dai->driver->ops->set_pll)
    108		ret = dai->driver->ops->set_pll(dai, pll_id, source,
    109						freq_in, freq_out);
    110	else
    111		ret = snd_soc_component_set_pll(dai->component, pll_id, source,
    112						freq_in, freq_out);
    113
    114	return soc_dai_ret(dai, ret);
    115}
    116EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
    117
    118/**
    119 * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
    120 * @dai: DAI
    121 * @ratio: Ratio of BCLK to Sample rate.
    122 *
    123 * Configures the DAI for a preset BCLK to sample rate ratio.
    124 */
    125int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
    126{
    127	int ret = -EINVAL;
    128
    129	if (dai->driver->ops &&
    130	    dai->driver->ops->set_bclk_ratio)
    131		ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
    132
    133	return soc_dai_ret(dai, ret);
    134}
    135EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
    136
    137int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
    138{
    139	struct snd_soc_dai *dai;
    140	int i, max = 0;
    141
    142	/*
    143	 * return max num if *ALL* DAIs have .auto_selectable_formats
    144	 */
    145	for_each_rtd_dais(rtd, i, dai) {
    146		if (dai->driver->ops &&
    147		    dai->driver->ops->num_auto_selectable_formats)
    148			max = max(max, dai->driver->ops->num_auto_selectable_formats);
    149		else
    150			return 0;
    151	}
    152
    153	return max;
    154}
    155
    156/**
    157 * snd_soc_dai_get_fmt - get supported audio format.
    158 * @dai: DAI
    159 * @priority: priority level of supported audio format.
    160 *
    161 * This should return only formats implemented with high
    162 * quality by the DAI so that the core can configure a
    163 * format which will work well with other devices.
    164 * For example devices which don't support both edges of the
    165 * LRCLK signal in I2S style formats should only list DSP
    166 * modes.  This will mean that sometimes fewer formats
    167 * are reported here than are supported by set_fmt().
    168 */
    169u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority)
    170{
    171	const struct snd_soc_dai_ops *ops = dai->driver->ops;
    172	u64 fmt = 0;
    173	int i, max = 0, until = priority;
    174
    175	/*
    176	 * Collect auto_selectable_formats until priority
    177	 *
    178	 * ex)
    179	 *	auto_selectable_formats[] = { A, B, C };
    180	 *	(A, B, C = SND_SOC_POSSIBLE_DAIFMT_xxx)
    181	 *
    182	 * priority = 1 :	A
    183	 * priority = 2 :	A | B
    184	 * priority = 3 :	A | B | C
    185	 * priority = 4 :	A | B | C
    186	 * ...
    187	 */
    188	if (ops)
    189		max = ops->num_auto_selectable_formats;
    190
    191	if (max < until)
    192		until = max;
    193
    194	for (i = 0; i < until; i++)
    195		fmt |= ops->auto_selectable_formats[i];
    196
    197	return fmt;
    198}
    199
    200/**
    201 * snd_soc_dai_set_fmt - configure DAI hardware audio format.
    202 * @dai: DAI
    203 * @fmt: SND_SOC_DAIFMT_* format value.
    204 *
    205 * Configures the DAI hardware format and clocking.
    206 */
    207int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
    208{
    209	int ret = -ENOTSUPP;
    210
    211	if (dai->driver->ops &&
    212	    dai->driver->ops->set_fmt)
    213		ret = dai->driver->ops->set_fmt(dai, fmt);
    214
    215	return soc_dai_ret(dai, ret);
    216}
    217EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
    218
    219/**
    220 * snd_soc_xlate_tdm_slot_mask - generate tx/rx slot mask.
    221 * @slots: Number of slots in use.
    222 * @tx_mask: bitmask representing active TX slots.
    223 * @rx_mask: bitmask representing active RX slots.
    224 *
    225 * Generates the TDM tx and rx slot default masks for DAI.
    226 */
    227static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
    228				       unsigned int *tx_mask,
    229				       unsigned int *rx_mask)
    230{
    231	if (*tx_mask || *rx_mask)
    232		return 0;
    233
    234	if (!slots)
    235		return -EINVAL;
    236
    237	*tx_mask = (1 << slots) - 1;
    238	*rx_mask = (1 << slots) - 1;
    239
    240	return 0;
    241}
    242
    243/**
    244 * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
    245 * @dai: The DAI to configure
    246 * @tx_mask: bitmask representing active TX slots.
    247 * @rx_mask: bitmask representing active RX slots.
    248 * @slots: Number of slots in use.
    249 * @slot_width: Width in bits for each slot.
    250 *
    251 * This function configures the specified DAI for TDM operation. @slot contains
    252 * the total number of slots of the TDM stream and @slot_with the width of each
    253 * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
    254 * active slots of the TDM stream for the specified DAI, i.e. which slots the
    255 * DAI should write to or read from. If a bit is set the corresponding slot is
    256 * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
    257 * the first slot, bit 1 to the second slot and so on. The first active slot
    258 * maps to the first channel of the DAI, the second active slot to the second
    259 * channel and so on.
    260 *
    261 * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
    262 * @rx_mask and @slot_width will be ignored.
    263 *
    264 * Returns 0 on success, a negative error code otherwise.
    265 */
    266int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
    267			     unsigned int tx_mask, unsigned int rx_mask,
    268			     int slots, int slot_width)
    269{
    270	int ret = -ENOTSUPP;
    271
    272	if (dai->driver->ops &&
    273	    dai->driver->ops->xlate_tdm_slot_mask)
    274		dai->driver->ops->xlate_tdm_slot_mask(slots,
    275						      &tx_mask, &rx_mask);
    276	else
    277		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
    278
    279	dai->tx_mask = tx_mask;
    280	dai->rx_mask = rx_mask;
    281
    282	if (dai->driver->ops &&
    283	    dai->driver->ops->set_tdm_slot)
    284		ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
    285						      slots, slot_width);
    286	return soc_dai_ret(dai, ret);
    287}
    288EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
    289
    290/**
    291 * snd_soc_dai_set_channel_map - configure DAI audio channel map
    292 * @dai: DAI
    293 * @tx_num: how many TX channels
    294 * @tx_slot: pointer to an array which imply the TX slot number channel
    295 *           0~num-1 uses
    296 * @rx_num: how many RX channels
    297 * @rx_slot: pointer to an array which imply the RX slot number channel
    298 *           0~num-1 uses
    299 *
    300 * configure the relationship between channel number and TDM slot number.
    301 */
    302int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
    303				unsigned int tx_num, unsigned int *tx_slot,
    304				unsigned int rx_num, unsigned int *rx_slot)
    305{
    306	int ret = -ENOTSUPP;
    307
    308	if (dai->driver->ops &&
    309	    dai->driver->ops->set_channel_map)
    310		ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
    311							rx_num, rx_slot);
    312	return soc_dai_ret(dai, ret);
    313}
    314EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
    315
    316/**
    317 * snd_soc_dai_get_channel_map - Get DAI audio channel map
    318 * @dai: DAI
    319 * @tx_num: how many TX channels
    320 * @tx_slot: pointer to an array which imply the TX slot number channel
    321 *           0~num-1 uses
    322 * @rx_num: how many RX channels
    323 * @rx_slot: pointer to an array which imply the RX slot number channel
    324 *           0~num-1 uses
    325 */
    326int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
    327				unsigned int *tx_num, unsigned int *tx_slot,
    328				unsigned int *rx_num, unsigned int *rx_slot)
    329{
    330	int ret = -ENOTSUPP;
    331
    332	if (dai->driver->ops &&
    333	    dai->driver->ops->get_channel_map)
    334		ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
    335							rx_num, rx_slot);
    336	return soc_dai_ret(dai, ret);
    337}
    338EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
    339
    340/**
    341 * snd_soc_dai_set_tristate - configure DAI system or master clock.
    342 * @dai: DAI
    343 * @tristate: tristate enable
    344 *
    345 * Tristates the DAI so that others can use it.
    346 */
    347int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
    348{
    349	int ret = -EINVAL;
    350
    351	if (dai->driver->ops &&
    352	    dai->driver->ops->set_tristate)
    353		ret = dai->driver->ops->set_tristate(dai, tristate);
    354
    355	return soc_dai_ret(dai, ret);
    356}
    357EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
    358
    359/**
    360 * snd_soc_dai_digital_mute - configure DAI system or master clock.
    361 * @dai: DAI
    362 * @mute: mute enable
    363 * @direction: stream to mute
    364 *
    365 * Mutes the DAI DAC.
    366 */
    367int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
    368			     int direction)
    369{
    370	int ret = -ENOTSUPP;
    371
    372	/*
    373	 * ignore if direction was CAPTURE
    374	 * and it had .no_capture_mute flag
    375	 */
    376	if (dai->driver->ops &&
    377	    dai->driver->ops->mute_stream &&
    378	    (direction == SNDRV_PCM_STREAM_PLAYBACK ||
    379	     !dai->driver->ops->no_capture_mute))
    380		ret = dai->driver->ops->mute_stream(dai, mute, direction);
    381
    382	return soc_dai_ret(dai, ret);
    383}
    384EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
    385
    386int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
    387			  struct snd_pcm_substream *substream,
    388			  struct snd_pcm_hw_params *params)
    389{
    390	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    391	int ret = 0;
    392
    393	if (dai->driver->ops &&
    394	    dai->driver->ops->hw_params) {
    395		/* perform any topology hw_params fixups before DAI  */
    396		ret = snd_soc_link_be_hw_params_fixup(rtd, params);
    397		if (ret < 0)
    398			goto end;
    399
    400		ret = dai->driver->ops->hw_params(substream, params, dai);
    401	}
    402
    403	/* mark substream if succeeded */
    404	if (ret == 0)
    405		soc_dai_mark_push(dai, substream, hw_params);
    406end:
    407	return soc_dai_ret(dai, ret);
    408}
    409
    410void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
    411			 struct snd_pcm_substream *substream,
    412			 int rollback)
    413{
    414	if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
    415		return;
    416
    417	if (dai->driver->ops &&
    418	    dai->driver->ops->hw_free)
    419		dai->driver->ops->hw_free(substream, dai);
    420
    421	/* remove marked substream */
    422	soc_dai_mark_pop(dai, substream, hw_params);
    423}
    424
    425int snd_soc_dai_startup(struct snd_soc_dai *dai,
    426			struct snd_pcm_substream *substream)
    427{
    428	int ret = 0;
    429
    430	if (dai->driver->ops &&
    431	    dai->driver->ops->startup)
    432		ret = dai->driver->ops->startup(substream, dai);
    433
    434	/* mark substream if succeeded */
    435	if (ret == 0)
    436		soc_dai_mark_push(dai, substream, startup);
    437
    438	return soc_dai_ret(dai, ret);
    439}
    440
    441void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
    442			  struct snd_pcm_substream *substream,
    443			  int rollback)
    444{
    445	if (rollback && !soc_dai_mark_match(dai, substream, startup))
    446		return;
    447
    448	if (dai->driver->ops &&
    449	    dai->driver->ops->shutdown)
    450		dai->driver->ops->shutdown(substream, dai);
    451
    452	/* remove marked substream */
    453	soc_dai_mark_pop(dai, substream, startup);
    454}
    455
    456int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
    457			     struct snd_soc_pcm_runtime *rtd, int num)
    458{
    459	int ret = -ENOTSUPP;
    460	if (dai->driver->compress_new)
    461		ret = dai->driver->compress_new(rtd, num);
    462	return soc_dai_ret(dai, ret);
    463}
    464
    465/*
    466 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
    467 *
    468 * Returns true if the DAI supports the indicated stream type.
    469 */
    470bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
    471{
    472	struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
    473
    474	/* If the codec specifies any channels at all, it supports the stream */
    475	return stream->channels_min;
    476}
    477
    478/*
    479 * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs
    480 */
    481void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
    482{
    483	bool supported[SNDRV_PCM_STREAM_LAST + 1];
    484	int direction;
    485
    486	for_each_pcm_streams(direction) {
    487		struct snd_soc_dai_link_component *cpu;
    488		struct snd_soc_dai_link_component *codec;
    489		struct snd_soc_dai *dai;
    490		bool supported_cpu = false;
    491		bool supported_codec = false;
    492		int i;
    493
    494		for_each_link_cpus(dai_link, i, cpu) {
    495			dai = snd_soc_find_dai_with_mutex(cpu);
    496			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
    497				supported_cpu = true;
    498				break;
    499			}
    500		}
    501		for_each_link_codecs(dai_link, i, codec) {
    502			dai = snd_soc_find_dai_with_mutex(codec);
    503			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
    504				supported_codec = true;
    505				break;
    506			}
    507		}
    508		supported[direction] = supported_cpu && supported_codec;
    509	}
    510
    511	dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK];
    512	dai_link->dpcm_capture  = supported[SNDRV_PCM_STREAM_CAPTURE];
    513}
    514EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities);
    515
    516void snd_soc_dai_action(struct snd_soc_dai *dai,
    517			int stream, int action)
    518{
    519	/* see snd_soc_dai_stream_active() */
    520	dai->stream_active[stream]	+= action;
    521
    522	/* see snd_soc_component_active() */
    523	dai->component->active		+= action;
    524}
    525EXPORT_SYMBOL_GPL(snd_soc_dai_action);
    526
    527int snd_soc_dai_active(struct snd_soc_dai *dai)
    528{
    529	int stream, active;
    530
    531	active = 0;
    532	for_each_pcm_streams(stream)
    533		active += dai->stream_active[stream];
    534
    535	return active;
    536}
    537EXPORT_SYMBOL_GPL(snd_soc_dai_active);
    538
    539int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
    540{
    541	struct snd_soc_dai *dai;
    542	int i;
    543
    544	for_each_rtd_dais(rtd, i, dai) {
    545		if (dai->driver->probe_order != order)
    546			continue;
    547
    548		if (dai->driver->probe) {
    549			int ret = dai->driver->probe(dai);
    550
    551			if (ret < 0)
    552				return soc_dai_ret(dai, ret);
    553		}
    554
    555		dai->probed = 1;
    556	}
    557
    558	return 0;
    559}
    560
    561int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
    562{
    563	struct snd_soc_dai *dai;
    564	int i, r, ret = 0;
    565
    566	for_each_rtd_dais(rtd, i, dai) {
    567		if (dai->driver->remove_order != order)
    568			continue;
    569
    570		if (dai->probed &&
    571		    dai->driver->remove) {
    572			r = dai->driver->remove(dai);
    573			if (r < 0)
    574				ret = r; /* use last error */
    575		}
    576
    577		dai->probed = 0;
    578	}
    579
    580	return ret;
    581}
    582
    583int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
    584{
    585	struct snd_soc_dai *dai;
    586	int i;
    587
    588	for_each_rtd_dais(rtd, i, dai) {
    589		if (dai->driver->pcm_new) {
    590			int ret = dai->driver->pcm_new(rtd, dai);
    591			if (ret < 0)
    592				return soc_dai_ret(dai, ret);
    593		}
    594	}
    595
    596	return 0;
    597}
    598
    599int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
    600{
    601	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    602	struct snd_soc_dai *dai;
    603	int i, ret;
    604
    605	for_each_rtd_dais(rtd, i, dai) {
    606		if (dai->driver->ops &&
    607		    dai->driver->ops->prepare) {
    608			ret = dai->driver->ops->prepare(substream, dai);
    609			if (ret < 0)
    610				return soc_dai_ret(dai, ret);
    611		}
    612	}
    613
    614	return 0;
    615}
    616
    617static int soc_dai_trigger(struct snd_soc_dai *dai,
    618			   struct snd_pcm_substream *substream, int cmd)
    619{
    620	int ret = 0;
    621
    622	if (dai->driver->ops &&
    623	    dai->driver->ops->trigger)
    624		ret = dai->driver->ops->trigger(substream, cmd, dai);
    625
    626	return soc_dai_ret(dai, ret);
    627}
    628
    629int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
    630			    int cmd, int rollback)
    631{
    632	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    633	struct snd_soc_dai *dai;
    634	int i, r, ret = 0;
    635
    636	switch (cmd) {
    637	case SNDRV_PCM_TRIGGER_START:
    638	case SNDRV_PCM_TRIGGER_RESUME:
    639	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    640		for_each_rtd_dais(rtd, i, dai) {
    641			ret = soc_dai_trigger(dai, substream, cmd);
    642			if (ret < 0)
    643				break;
    644			soc_dai_mark_push(dai, substream, trigger);
    645		}
    646		break;
    647	case SNDRV_PCM_TRIGGER_STOP:
    648	case SNDRV_PCM_TRIGGER_SUSPEND:
    649	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    650		for_each_rtd_dais(rtd, i, dai) {
    651			if (rollback && !soc_dai_mark_match(dai, substream, trigger))
    652				continue;
    653
    654			r = soc_dai_trigger(dai, substream, cmd);
    655			if (r < 0)
    656				ret = r; /* use last ret */
    657			soc_dai_mark_pop(dai, substream, trigger);
    658		}
    659	}
    660
    661	return ret;
    662}
    663
    664int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
    665				    int cmd)
    666{
    667	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    668	struct snd_soc_dai *dai;
    669	int i, ret;
    670
    671	for_each_rtd_dais(rtd, i, dai) {
    672		if (dai->driver->ops &&
    673		    dai->driver->ops->bespoke_trigger) {
    674			ret = dai->driver->ops->bespoke_trigger(substream,
    675								cmd, dai);
    676			if (ret < 0)
    677				return soc_dai_ret(dai, ret);
    678		}
    679	}
    680
    681	return 0;
    682}
    683
    684void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
    685			   snd_pcm_sframes_t *cpu_delay,
    686			   snd_pcm_sframes_t *codec_delay)
    687{
    688	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    689	struct snd_soc_dai *dai;
    690	int i;
    691
    692	/*
    693	 * We're looking for the delay through the full audio path so it needs to
    694	 * be the maximum of the DAIs doing transmit and the maximum of the DAIs
    695	 * doing receive (ie, all CPUs and all CODECs) rather than just the maximum
    696	 * of all DAIs.
    697	 */
    698
    699	/* for CPU */
    700	for_each_rtd_cpu_dais(rtd, i, dai)
    701		if (dai->driver->ops &&
    702		    dai->driver->ops->delay)
    703			*cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai));
    704
    705	/* for Codec */
    706	for_each_rtd_codec_dais(rtd, i, dai)
    707		if (dai->driver->ops &&
    708		    dai->driver->ops->delay)
    709			*codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai));
    710}
    711
    712int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
    713			      struct snd_compr_stream *cstream)
    714{
    715	int ret = 0;
    716
    717	if (dai->driver->cops &&
    718	    dai->driver->cops->startup)
    719		ret = dai->driver->cops->startup(cstream, dai);
    720
    721	/* mark cstream if succeeded */
    722	if (ret == 0)
    723		soc_dai_mark_push(dai, cstream, compr_startup);
    724
    725	return soc_dai_ret(dai, ret);
    726}
    727EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
    728
    729void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
    730				struct snd_compr_stream *cstream,
    731				int rollback)
    732{
    733	if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
    734		return;
    735
    736	if (dai->driver->cops &&
    737	    dai->driver->cops->shutdown)
    738		dai->driver->cops->shutdown(cstream, dai);
    739
    740	/* remove marked cstream */
    741	soc_dai_mark_pop(dai, cstream, compr_startup);
    742}
    743EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
    744
    745int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
    746			      struct snd_compr_stream *cstream, int cmd)
    747{
    748	int ret = 0;
    749
    750	if (dai->driver->cops &&
    751	    dai->driver->cops->trigger)
    752		ret = dai->driver->cops->trigger(cstream, cmd, dai);
    753
    754	return soc_dai_ret(dai, ret);
    755}
    756EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
    757
    758int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
    759				 struct snd_compr_stream *cstream,
    760				 struct snd_compr_params *params)
    761{
    762	int ret = 0;
    763
    764	if (dai->driver->cops &&
    765	    dai->driver->cops->set_params)
    766		ret = dai->driver->cops->set_params(cstream, params, dai);
    767
    768	return soc_dai_ret(dai, ret);
    769}
    770EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
    771
    772int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
    773				 struct snd_compr_stream *cstream,
    774				 struct snd_codec *params)
    775{
    776	int ret = 0;
    777
    778	if (dai->driver->cops &&
    779	    dai->driver->cops->get_params)
    780		ret = dai->driver->cops->get_params(cstream, params, dai);
    781
    782	return soc_dai_ret(dai, ret);
    783}
    784EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
    785
    786int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
    787			  struct snd_compr_stream *cstream,
    788			  size_t bytes)
    789{
    790	int ret = 0;
    791
    792	if (dai->driver->cops &&
    793	    dai->driver->cops->ack)
    794		ret = dai->driver->cops->ack(cstream, bytes, dai);
    795
    796	return soc_dai_ret(dai, ret);
    797}
    798EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
    799
    800int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
    801			      struct snd_compr_stream *cstream,
    802			      struct snd_compr_tstamp *tstamp)
    803{
    804	int ret = 0;
    805
    806	if (dai->driver->cops &&
    807	    dai->driver->cops->pointer)
    808		ret = dai->driver->cops->pointer(cstream, tstamp, dai);
    809
    810	return soc_dai_ret(dai, ret);
    811}
    812EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
    813
    814int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
    815				   struct snd_compr_stream *cstream,
    816				   struct snd_compr_metadata *metadata)
    817{
    818	int ret = 0;
    819
    820	if (dai->driver->cops &&
    821	    dai->driver->cops->set_metadata)
    822		ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
    823
    824	return soc_dai_ret(dai, ret);
    825}
    826EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
    827
    828int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
    829				   struct snd_compr_stream *cstream,
    830				   struct snd_compr_metadata *metadata)
    831{
    832	int ret = 0;
    833
    834	if (dai->driver->cops &&
    835	    dai->driver->cops->get_metadata)
    836		ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
    837
    838	return soc_dai_ret(dai, ret);
    839}
    840EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);