File Index
Files and directories
Sign in
FILE

soc-dai.c

File preview with syntax highlighting.

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