Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/soc-dai.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// soc-dai.c
4
//
5
// Copyright (C) 2019 Renesas Electronics Corp.
6
// Kuninori Morimoto <[email protected]>
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)
14
static 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
*/
38
int 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
}
52
EXPORT_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
*/
64
int 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
}
75
EXPORT_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
*/
87
int 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
}
102
EXPORT_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
*/
111
int 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
}
121
EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
122
123
int 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
*/
155
u64 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
for (i = 0; i < until; i++)
181
fmt |= ops->auto_selectable_formats[i];
182
183
return fmt;
184
}
185
186
/**
187
* snd_soc_dai_set_fmt - configure DAI hardware audio format.
188
* @dai: DAI
189
* @fmt: SND_SOC_DAIFMT_* format value.
190
*
191
* Configures the DAI hardware format and clocking.
192
*/
193
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
194
{
195
int ret = -ENOTSUPP;
196
197
if (dai->driver->ops && dai->driver->ops->set_fmt)
198
ret = dai->driver->ops->set_fmt(dai, fmt);
199
200
return soc_dai_ret(dai, ret);
201
}
202
EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
203
204
/**
205
* snd_soc_xlate_tdm_slot_mask - generate tx/rx slot mask.
206
* @slots: Number of slots in use.
207
* @tx_mask: bitmask representing active TX slots.
208
* @rx_mask: bitmask representing active RX slots.
209
*
210
* Generates the TDM tx and rx slot default masks for DAI.
211
*/
212
static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
213
unsigned int *tx_mask,
214
unsigned int *rx_mask)
215
{
216
if (*tx_mask || *rx_mask)
217
return 0;
218
219
if (!slots)
220
return -EINVAL;
221
222
*tx_mask = (1 << slots) - 1;
223
*rx_mask = (1 << slots) - 1;
224
225
return 0;
226
}
227
228
/**
229
* snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
230
* @dai: The DAI to configure
231
* @tx_mask: bitmask representing active TX slots.
232
* @rx_mask: bitmask representing active RX slots.
233
* @slots: Number of slots in use.
234
* @slot_width: Width in bits for each slot.
235
*
236
* This function configures the specified DAI for TDM operation. @slot contains
237
* the total number of slots of the TDM stream and @slot_with the width of each
238
* slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
239
* active slots of the TDM stream for the specified DAI, i.e. which slots the
240
* DAI should write to or read from. If a bit is set the corresponding slot is
241
* active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
242
* the first slot, bit 1 to the second slot and so on. The first active slot
243
* maps to the first channel of the DAI, the second active slot to the second
244
* channel and so on.
245
*
246
* TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
247
* @rx_mask and @slot_width will be ignored.
248
*
249
* Returns 0 on success, a negative error code otherwise.
250
*/
251
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
252
unsigned int tx_mask, unsigned int rx_mask,
253
int slots, int slot_width)
254
{
255
int ret = -ENOTSUPP;
256
int stream;
257
unsigned int *tdm_mask[] = {
258
&tx_mask,
259
&rx_mask,
260
};
261
262
if (slots) {
263
if (dai->driver->ops &&
264
dai->driver->ops->xlate_tdm_slot_mask)
265
ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
266
else
267
ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
268
if (ret)
269
goto err;
270
}
271
272
for_each_pcm_streams(stream)
273
snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]);
274
275
if (dai->driver->ops &&
276
dai->driver->ops->set_tdm_slot)
277
ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
278
slots, slot_width);
279
err:
280
return soc_dai_ret(dai, ret);
281
}
282
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
283
284
/**
285
* snd_soc_dai_set_channel_map - configure DAI audio channel map
286
* @dai: DAI
287
* @tx_num: how many TX channels
288
* @tx_slot: pointer to an array which imply the TX slot number channel
289
* 0~num-1 uses
290
* @rx_num: how many RX channels
291
* @rx_slot: pointer to an array which imply the RX slot number channel
292
* 0~num-1 uses
293
*
294
* configure the relationship between channel number and TDM slot number.
295
*/
296
int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
297
unsigned int tx_num, const unsigned int *tx_slot,
298
unsigned int rx_num, const unsigned int *rx_slot)
299
{
300
int ret = -ENOTSUPP;
301
302
if (dai->driver->ops &&
303
dai->driver->ops->set_channel_map)
304
ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
305
rx_num, rx_slot);
306
return soc_dai_ret(dai, ret);
307
}
308
EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
309
310
/**
311
* snd_soc_dai_get_channel_map - Get DAI audio channel map
312
* @dai: DAI
313
* @tx_num: how many TX channels
314
* @tx_slot: pointer to an array which imply the TX slot number channel
315
* 0~num-1 uses
316
* @rx_num: how many RX channels
317
* @rx_slot: pointer to an array which imply the RX slot number channel
318
* 0~num-1 uses
319
*/
320
int snd_soc_dai_get_channel_map(const struct snd_soc_dai *dai,
321
unsigned int *tx_num, unsigned int *tx_slot,
322
unsigned int *rx_num, unsigned int *rx_slot)
323
{
324
int ret = -ENOTSUPP;
325
326
if (dai->driver->ops &&
327
dai->driver->ops->get_channel_map)
328
ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
329
rx_num, rx_slot);
330
return soc_dai_ret(dai, ret);
331
}
332
EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
333
334
/**
335
* snd_soc_dai_set_tristate - configure DAI system or master clock.
336
* @dai: DAI
337
* @tristate: tristate enable
338
*
339
* Tristates the DAI so that others can use it.
340
*/
341
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
342
{
343
int ret = -EINVAL;
344
345
if (dai->driver->ops &&
346
dai->driver->ops->set_tristate)
347
ret = dai->driver->ops->set_tristate(dai, tristate);
348
349
return soc_dai_ret(dai, ret);
350
}
351
EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
352
353
int snd_soc_dai_prepare(struct snd_soc_dai *dai,
354
struct snd_pcm_substream *substream)
355
{
356
int ret = 0;
357
358
if (!snd_soc_dai_stream_valid(dai, substream->stream))
359
return 0;
360
361
if (dai->driver->ops &&
362
dai->driver->ops->prepare)
363
ret = dai->driver->ops->prepare(substream, dai);
364
365
return soc_dai_ret(dai, ret);
366
}
367
EXPORT_SYMBOL_GPL(snd_soc_dai_prepare);
368
369
int snd_soc_dai_mute_is_ctrled_at_trigger(struct snd_soc_dai *dai)
370
{
371
if (dai->driver->ops)
372
return dai->driver->ops->mute_unmute_on_trigger;
373
374
return 0;
375
}
376
377
/**
378
* snd_soc_dai_digital_mute - configure DAI system or master clock.
379
* @dai: DAI
380
* @mute: mute enable
381
* @direction: stream to mute
382
*
383
* Mutes the DAI DAC.
384
*/
385
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
386
int direction)
387
{
388
int ret = -ENOTSUPP;
389
390
/*
391
* ignore if direction was CAPTURE
392
* and it had .no_capture_mute flag
393
*/
394
if (dai->driver->ops &&
395
dai->driver->ops->mute_stream &&
396
(direction == SNDRV_PCM_STREAM_PLAYBACK ||
397
!dai->driver->ops->no_capture_mute))
398
ret = dai->driver->ops->mute_stream(dai, mute, direction);
399
400
return soc_dai_ret(dai, ret);
401
}
402
EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
403
404
int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
405
struct snd_pcm_substream *substream,
406
struct snd_pcm_hw_params *params)
407
{
408
int ret = 0;
409
410
if (dai->driver->ops &&
411
dai->driver->ops->hw_params)
412
ret = dai->driver->ops->hw_params(substream, params, dai);
413
414
/* mark substream if succeeded */
415
if (ret == 0)
416
soc_dai_mark_push(dai, substream, hw_params);
417
418
return soc_dai_ret(dai, ret);
419
}
420
421
void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
422
struct snd_pcm_substream *substream,
423
int rollback)
424
{
425
if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
426
return;
427
428
if (dai->driver->ops &&
429
dai->driver->ops->hw_free)
430
dai->driver->ops->hw_free(substream, dai);
431
432
/* remove marked substream */
433
soc_dai_mark_pop(dai, hw_params);
434
}
435
436
int snd_soc_dai_startup(struct snd_soc_dai *dai,
437
struct snd_pcm_substream *substream)
438
{
439
int ret = 0;
440
441
if (!snd_soc_dai_stream_valid(dai, substream->stream))
442
return 0;
443
444
if (dai->driver->ops &&
445
dai->driver->ops->startup)
446
ret = dai->driver->ops->startup(substream, dai);
447
448
/* mark substream if succeeded */
449
if (ret == 0)
450
soc_dai_mark_push(dai, substream, startup);
451
452
return soc_dai_ret(dai, ret);
453
}
454
455
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
456
struct snd_pcm_substream *substream,
457
int rollback)
458
{
459
if (!snd_soc_dai_stream_valid(dai, substream->stream))
460
return;
461
462
if (rollback && !soc_dai_mark_match(dai, substream, startup))
463
return;
464
465
if (dai->driver->ops &&
466
dai->driver->ops->shutdown)
467
dai->driver->ops->shutdown(substream, dai);
468
469
/* remove marked substream */
470
soc_dai_mark_pop(dai, startup);
471
}
472
473
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
474
struct snd_soc_pcm_runtime *rtd)
475
{
476
int ret = -ENOTSUPP;
477
if (dai->driver->ops &&
478
dai->driver->ops->compress_new)
479
ret = dai->driver->ops->compress_new(rtd);
480
return soc_dai_ret(dai, ret);
481
}
482
483
/*
484
* snd_soc_dai_stream_valid() - check if a DAI supports the given stream
485
*
486
* Returns true if the DAI supports the indicated stream type.
487
*/
488
bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int dir)
489
{
490
const struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
491
492
/* If the codec specifies any channels at all, it supports the stream */
493
return stream->channels_min;
494
}
495
496
void snd_soc_dai_action(struct snd_soc_dai *dai,
497
int stream, int action)
498
{
499
/* see snd_soc_dai_stream_active() */
500
dai->stream[stream].active += action;
501
502
/* see snd_soc_component_active() */
503
dai->component->active += action;
504
}
505
EXPORT_SYMBOL_GPL(snd_soc_dai_action);
506
507
int snd_soc_dai_active(const struct snd_soc_dai *dai)
508
{
509
int stream, active;
510
511
active = 0;
512
for_each_pcm_streams(stream)
513
active += dai->stream[stream].active;
514
515
return active;
516
}
517
EXPORT_SYMBOL_GPL(snd_soc_dai_active);
518
519
int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
520
{
521
struct snd_soc_dai *dai;
522
int i;
523
524
for_each_rtd_dais(rtd, i, dai) {
525
if (dai->probed)
526
continue;
527
528
if (dai->driver->ops) {
529
if (dai->driver->ops->probe_order != order)
530
continue;
531
532
if (dai->driver->ops->probe) {
533
int ret = dai->driver->ops->probe(dai);
534
535
if (ret < 0)
536
return soc_dai_ret(dai, ret);
537
}
538
}
539
dai->probed = 1;
540
}
541
542
return 0;
543
}
544
545
int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
546
{
547
struct snd_soc_dai *dai;
548
int i, r, ret = 0;
549
550
for_each_rtd_dais(rtd, i, dai) {
551
if (!dai->probed)
552
continue;
553
554
if (dai->driver->ops) {
555
if (dai->driver->ops->remove_order != order)
556
continue;
557
558
if (dai->driver->ops->remove) {
559
r = dai->driver->ops->remove(dai);
560
if (r < 0)
561
ret = r; /* use last error */
562
}
563
}
564
dai->probed = 0;
565
}
566
567
return ret;
568
}
569
570
int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
571
{
572
struct snd_soc_dai *dai;
573
int i;
574
575
for_each_rtd_dais(rtd, i, dai) {
576
if (dai->driver->ops &&
577
dai->driver->ops->pcm_new) {
578
int ret = dai->driver->ops->pcm_new(rtd, dai);
579
if (ret < 0)
580
return soc_dai_ret(dai, ret);
581
}
582
}
583
584
return 0;
585
}
586
587
int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
588
{
589
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
590
struct snd_soc_dai *dai;
591
int i, ret;
592
593
for_each_rtd_dais(rtd, i, dai) {
594
ret = snd_soc_dai_prepare(dai, substream);
595
if (ret < 0)
596
return ret;
597
}
598
599
return 0;
600
}
601
602
static int soc_dai_trigger(struct snd_soc_dai *dai,
603
struct snd_pcm_substream *substream, int cmd)
604
{
605
int ret = 0;
606
607
if (!snd_soc_dai_stream_valid(dai, substream->stream))
608
return 0;
609
610
if (dai->driver->ops &&
611
dai->driver->ops->trigger)
612
ret = dai->driver->ops->trigger(substream, cmd, dai);
613
614
return soc_dai_ret(dai, ret);
615
}
616
617
int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
618
int cmd, int rollback)
619
{
620
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
621
struct snd_soc_dai *dai;
622
int i, r, ret = 0;
623
624
switch (cmd) {
625
case SNDRV_PCM_TRIGGER_START:
626
case SNDRV_PCM_TRIGGER_RESUME:
627
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
628
for_each_rtd_dais(rtd, i, dai) {
629
ret = soc_dai_trigger(dai, substream, cmd);
630
if (ret < 0)
631
break;
632
633
if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
634
snd_soc_dai_digital_mute(dai, 0, substream->stream);
635
636
soc_dai_mark_push(dai, substream, trigger);
637
}
638
break;
639
case SNDRV_PCM_TRIGGER_STOP:
640
case SNDRV_PCM_TRIGGER_SUSPEND:
641
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
642
for_each_rtd_dais(rtd, i, dai) {
643
if (rollback && !soc_dai_mark_match(dai, substream, trigger))
644
continue;
645
646
if (snd_soc_dai_mute_is_ctrled_at_trigger(dai))
647
snd_soc_dai_digital_mute(dai, 1, substream->stream);
648
649
r = soc_dai_trigger(dai, substream, cmd);
650
if (r < 0)
651
ret = r; /* use last ret */
652
soc_dai_mark_pop(dai, trigger);
653
}
654
}
655
656
return ret;
657
}
658
659
void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
660
snd_pcm_sframes_t *cpu_delay,
661
snd_pcm_sframes_t *codec_delay)
662
{
663
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
664
struct snd_soc_dai *dai;
665
int i;
666
667
/*
668
* We're looking for the delay through the full audio path so it needs to
669
* be the maximum of the DAIs doing transmit and the maximum of the DAIs
670
* doing receive (ie, all CPUs and all CODECs) rather than just the maximum
671
* of all DAIs.
672
*/
673
674
/* for CPU */
675
for_each_rtd_cpu_dais(rtd, i, dai)
676
if (dai->driver->ops &&
677
dai->driver->ops->delay)
678
*cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai));
679
680
/* for Codec */
681
for_each_rtd_codec_dais(rtd, i, dai)
682
if (dai->driver->ops &&
683
dai->driver->ops->delay)
684
*codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai));
685
}
686
687
int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
688
struct snd_compr_stream *cstream)
689
{
690
int ret = 0;
691
692
if (dai->driver->cops &&
693
dai->driver->cops->startup)
694
ret = dai->driver->cops->startup(cstream, dai);
695
696
/* mark cstream if succeeded */
697
if (ret == 0)
698
soc_dai_mark_push(dai, cstream, compr_startup);
699
700
return soc_dai_ret(dai, ret);
701
}
702
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
703
704
void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
705
struct snd_compr_stream *cstream,
706
int rollback)
707
{
708
if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
709
return;
710
711
if (dai->driver->cops &&
712
dai->driver->cops->shutdown)
713
dai->driver->cops->shutdown(cstream, dai);
714
715
/* remove marked cstream */
716
soc_dai_mark_pop(dai, compr_startup);
717
}
718
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
719
720
int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
721
struct snd_compr_stream *cstream, int cmd)
722
{
723
int ret = 0;
724
725
if (dai->driver->cops &&
726
dai->driver->cops->trigger)
727
ret = dai->driver->cops->trigger(cstream, cmd, dai);
728
729
return soc_dai_ret(dai, ret);
730
}
731
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
732
733
int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
734
struct snd_compr_stream *cstream,
735
struct snd_compr_params *params)
736
{
737
int ret = 0;
738
739
if (dai->driver->cops &&
740
dai->driver->cops->set_params)
741
ret = dai->driver->cops->set_params(cstream, params, dai);
742
743
return soc_dai_ret(dai, ret);
744
}
745
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
746
747
int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
748
struct snd_compr_stream *cstream,
749
struct snd_codec *params)
750
{
751
int ret = 0;
752
753
if (dai->driver->cops &&
754
dai->driver->cops->get_params)
755
ret = dai->driver->cops->get_params(cstream, params, dai);
756
757
return soc_dai_ret(dai, ret);
758
}
759
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
760
761
int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
762
struct snd_compr_stream *cstream,
763
size_t bytes)
764
{
765
int ret = 0;
766
767
if (dai->driver->cops &&
768
dai->driver->cops->ack)
769
ret = dai->driver->cops->ack(cstream, bytes, dai);
770
771
return soc_dai_ret(dai, ret);
772
}
773
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
774
775
int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
776
struct snd_compr_stream *cstream,
777
struct snd_compr_tstamp *tstamp)
778
{
779
int ret = 0;
780
781
if (dai->driver->cops &&
782
dai->driver->cops->pointer)
783
ret = dai->driver->cops->pointer(cstream, tstamp, dai);
784
785
return soc_dai_ret(dai, ret);
786
}
787
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
788
789
int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
790
struct snd_compr_stream *cstream,
791
struct snd_compr_metadata *metadata)
792
{
793
int ret = 0;
794
795
if (dai->driver->cops &&
796
dai->driver->cops->set_metadata)
797
ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
798
799
return soc_dai_ret(dai, ret);
800
}
801
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
802
803
int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
804
struct snd_compr_stream *cstream,
805
struct snd_compr_metadata *metadata)
806
{
807
int ret = 0;
808
809
if (dai->driver->cops &&
810
dai->driver->cops->get_metadata)
811
ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
812
813
return soc_dai_ret(dai, ret);
814
}
815
EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
816
817