ASoC: soc-dapm: use snd_soc_dai_activate()/deactivate()
[linux-2.6-block.git] / sound / soc / soc-dai.c
CommitLineData
06f6e1d4
KM
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
aa7b8230
KM
12#define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
13static inline int _soc_dai_ret(struct snd_soc_dai *dai,
14 const char *func, int ret)
15{
16 switch (ret) {
17 case -EPROBE_DEFER:
18 case -ENOTSUPP:
19 case 0:
20 break;
21 default:
22 dev_err(dai->dev,
23 "ASoC: error at %s on %s: %d\n",
24 func, dai->name, ret);
25 }
26
27 return ret;
28}
29
06f6e1d4
KM
30/**
31 * snd_soc_dai_set_sysclk - configure DAI system or master clock.
32 * @dai: DAI
33 * @clk_id: DAI specific clock ID
34 * @freq: new clock frequency in Hz
35 * @dir: new clock direction - input/output.
36 *
37 * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
38 */
39int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
40 unsigned int freq, int dir)
41{
aa7b8230
KM
42 int ret;
43
479914ed
KM
44 if (dai->driver->ops &&
45 dai->driver->ops->set_sysclk)
aa7b8230
KM
46 ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
47 else
48 ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
49 freq, dir);
06f6e1d4 50
aa7b8230 51 return soc_dai_ret(dai, ret);
06f6e1d4
KM
52}
53EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
54
55/**
56 * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
57 * @dai: DAI
58 * @div_id: DAI specific clock divider ID
59 * @div: new clock divisor.
60 *
61 * Configures the clock dividers. This is used to derive the best DAI bit and
62 * frame clocks from the system or master clock. It's best to set the DAI bit
63 * and frame clocks as low as possible to save system power.
64 */
65int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
66 int div_id, int div)
67{
aa7b8230
KM
68 int ret = -EINVAL;
69
479914ed
KM
70 if (dai->driver->ops &&
71 dai->driver->ops->set_clkdiv)
aa7b8230
KM
72 ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
73
74 return soc_dai_ret(dai, ret);
06f6e1d4
KM
75}
76EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
77
78/**
79 * snd_soc_dai_set_pll - configure DAI PLL.
80 * @dai: DAI
81 * @pll_id: DAI specific PLL ID
82 * @source: DAI specific source for the PLL
83 * @freq_in: PLL input clock frequency in Hz
84 * @freq_out: requested PLL output clock frequency in Hz
85 *
86 * Configures and enables PLL to generate output clock based on input clock.
87 */
88int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
89 unsigned int freq_in, unsigned int freq_out)
90{
aa7b8230
KM
91 int ret;
92
479914ed
KM
93 if (dai->driver->ops &&
94 dai->driver->ops->set_pll)
aa7b8230
KM
95 ret = dai->driver->ops->set_pll(dai, pll_id, source,
96 freq_in, freq_out);
97 else
98 ret = snd_soc_component_set_pll(dai->component, pll_id, source,
99 freq_in, freq_out);
06f6e1d4 100
aa7b8230 101 return soc_dai_ret(dai, ret);
06f6e1d4
KM
102}
103EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
104
105/**
106 * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
107 * @dai: DAI
108 * @ratio: Ratio of BCLK to Sample rate.
109 *
110 * Configures the DAI for a preset BCLK to sample rate ratio.
111 */
112int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
113{
aa7b8230
KM
114 int ret = -EINVAL;
115
479914ed
KM
116 if (dai->driver->ops &&
117 dai->driver->ops->set_bclk_ratio)
aa7b8230
KM
118 ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
119
120 return soc_dai_ret(dai, ret);
06f6e1d4
KM
121}
122EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
123
124/**
125 * snd_soc_dai_set_fmt - configure DAI hardware audio format.
126 * @dai: DAI
127 * @fmt: SND_SOC_DAIFMT_* format value.
128 *
129 * Configures the DAI hardware format and clocking.
130 */
131int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
132{
aa7b8230
KM
133 int ret = -ENOTSUPP;
134
479914ed
KM
135 if (dai->driver->ops &&
136 dai->driver->ops->set_fmt)
aa7b8230
KM
137 ret = dai->driver->ops->set_fmt(dai, fmt);
138
139 return soc_dai_ret(dai, ret);
06f6e1d4
KM
140}
141EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
142
143/**
144 * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
145 * @slots: Number of slots in use.
146 * @tx_mask: bitmask representing active TX slots.
147 * @rx_mask: bitmask representing active RX slots.
148 *
149 * Generates the TDM tx and rx slot default masks for DAI.
150 */
151static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
152 unsigned int *tx_mask,
153 unsigned int *rx_mask)
154{
155 if (*tx_mask || *rx_mask)
156 return 0;
157
158 if (!slots)
159 return -EINVAL;
160
161 *tx_mask = (1 << slots) - 1;
162 *rx_mask = (1 << slots) - 1;
163
164 return 0;
165}
166
167/**
168 * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
169 * @dai: The DAI to configure
170 * @tx_mask: bitmask representing active TX slots.
171 * @rx_mask: bitmask representing active RX slots.
172 * @slots: Number of slots in use.
173 * @slot_width: Width in bits for each slot.
174 *
175 * This function configures the specified DAI for TDM operation. @slot contains
176 * the total number of slots of the TDM stream and @slot_with the width of each
177 * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
178 * active slots of the TDM stream for the specified DAI, i.e. which slots the
179 * DAI should write to or read from. If a bit is set the corresponding slot is
180 * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
181 * the first slot, bit 1 to the second slot and so on. The first active slot
182 * maps to the first channel of the DAI, the second active slot to the second
183 * channel and so on.
184 *
185 * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
186 * @rx_mask and @slot_width will be ignored.
187 *
188 * Returns 0 on success, a negative error code otherwise.
189 */
190int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
191 unsigned int tx_mask, unsigned int rx_mask,
192 int slots, int slot_width)
193{
aa7b8230
KM
194 int ret = -ENOTSUPP;
195
479914ed
KM
196 if (dai->driver->ops &&
197 dai->driver->ops->xlate_tdm_slot_mask)
06f6e1d4
KM
198 dai->driver->ops->xlate_tdm_slot_mask(slots,
199 &tx_mask, &rx_mask);
200 else
201 snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
202
203 dai->tx_mask = tx_mask;
204 dai->rx_mask = rx_mask;
205
479914ed
KM
206 if (dai->driver->ops &&
207 dai->driver->ops->set_tdm_slot)
aa7b8230 208 ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
06f6e1d4 209 slots, slot_width);
aa7b8230 210 return soc_dai_ret(dai, ret);
06f6e1d4
KM
211}
212EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
213
214/**
215 * snd_soc_dai_set_channel_map - configure DAI audio channel map
216 * @dai: DAI
217 * @tx_num: how many TX channels
218 * @tx_slot: pointer to an array which imply the TX slot number channel
219 * 0~num-1 uses
220 * @rx_num: how many RX channels
221 * @rx_slot: pointer to an array which imply the RX slot number channel
222 * 0~num-1 uses
223 *
224 * configure the relationship between channel number and TDM slot number.
225 */
226int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
227 unsigned int tx_num, unsigned int *tx_slot,
228 unsigned int rx_num, unsigned int *rx_slot)
229{
aa7b8230
KM
230 int ret = -ENOTSUPP;
231
479914ed
KM
232 if (dai->driver->ops &&
233 dai->driver->ops->set_channel_map)
aa7b8230
KM
234 ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
235 rx_num, rx_slot);
236 return soc_dai_ret(dai, ret);
06f6e1d4
KM
237}
238EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
239
240/**
241 * snd_soc_dai_get_channel_map - Get DAI audio channel map
242 * @dai: DAI
243 * @tx_num: how many TX channels
244 * @tx_slot: pointer to an array which imply the TX slot number channel
245 * 0~num-1 uses
246 * @rx_num: how many RX channels
247 * @rx_slot: pointer to an array which imply the RX slot number channel
248 * 0~num-1 uses
249 */
250int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
251 unsigned int *tx_num, unsigned int *tx_slot,
252 unsigned int *rx_num, unsigned int *rx_slot)
253{
aa7b8230
KM
254 int ret = -ENOTSUPP;
255
479914ed
KM
256 if (dai->driver->ops &&
257 dai->driver->ops->get_channel_map)
aa7b8230
KM
258 ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
259 rx_num, rx_slot);
260 return soc_dai_ret(dai, ret);
06f6e1d4
KM
261}
262EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
263
264/**
265 * snd_soc_dai_set_tristate - configure DAI system or master clock.
266 * @dai: DAI
267 * @tristate: tristate enable
268 *
269 * Tristates the DAI so that others can use it.
270 */
271int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
272{
aa7b8230
KM
273 int ret = -EINVAL;
274
479914ed
KM
275 if (dai->driver->ops &&
276 dai->driver->ops->set_tristate)
aa7b8230
KM
277 ret = dai->driver->ops->set_tristate(dai, tristate);
278
279 return soc_dai_ret(dai, ret);
06f6e1d4
KM
280}
281EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
282
283/**
284 * snd_soc_dai_digital_mute - configure DAI system or master clock.
285 * @dai: DAI
286 * @mute: mute enable
287 * @direction: stream to mute
288 *
289 * Mutes the DAI DAC.
290 */
291int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
292 int direction)
293{
aa7b8230
KM
294 int ret = -ENOTSUPP;
295
479914ed
KM
296 if (dai->driver->ops &&
297 dai->driver->ops->mute_stream)
aa7b8230 298 ret = dai->driver->ops->mute_stream(dai, mute, direction);
06f6e1d4 299 else if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
479914ed 300 dai->driver->ops &&
06f6e1d4 301 dai->driver->ops->digital_mute)
aa7b8230
KM
302 ret = dai->driver->ops->digital_mute(dai, mute);
303
304 return soc_dai_ret(dai, ret);
06f6e1d4
KM
305}
306EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
aa6166c2
KM
307
308int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
309 struct snd_pcm_substream *substream,
310 struct snd_pcm_hw_params *params)
311{
312 struct snd_soc_pcm_runtime *rtd = substream->private_data;
aa7b8230 313 int ret = 0;
aa6166c2
KM
314
315 /* perform any topology hw_params fixups before DAI */
316 if (rtd->dai_link->be_hw_params_fixup) {
317 ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
aa7b8230
KM
318 if (ret < 0)
319 goto end;
aa6166c2
KM
320 }
321
479914ed
KM
322 if (dai->driver->ops &&
323 dai->driver->ops->hw_params)
aa6166c2 324 ret = dai->driver->ops->hw_params(substream, params, dai);
aa7b8230
KM
325end:
326 return soc_dai_ret(dai, ret);
aa6166c2 327}
846faaed
KM
328
329void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
330 struct snd_pcm_substream *substream)
331{
479914ed
KM
332 if (dai->driver->ops &&
333 dai->driver->ops->hw_free)
846faaed
KM
334 dai->driver->ops->hw_free(substream, dai);
335}
5a52a045
KM
336
337int snd_soc_dai_startup(struct snd_soc_dai *dai,
338 struct snd_pcm_substream *substream)
339{
340 int ret = 0;
341
479914ed
KM
342 if (dai->driver->ops &&
343 dai->driver->ops->startup)
5a52a045
KM
344 ret = dai->driver->ops->startup(substream, dai);
345
aa7b8230 346 return soc_dai_ret(dai, ret);
5a52a045 347}
330fcb51
KM
348
349void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
350 struct snd_pcm_substream *substream)
351{
479914ed
KM
352 if (dai->driver->ops &&
353 dai->driver->ops->shutdown)
330fcb51
KM
354 dai->driver->ops->shutdown(substream, dai);
355}
4beb8e10 356
1dea80d4
KM
357snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
358 struct snd_pcm_substream *substream)
359{
360 int delay = 0;
361
479914ed
KM
362 if (dai->driver->ops &&
363 dai->driver->ops->delay)
1dea80d4
KM
364 delay = dai->driver->ops->delay(substream, dai);
365
366 return delay;
367}
e0f22622 368
b423c420
KM
369int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
370 struct snd_soc_pcm_runtime *rtd, int num)
371{
aa7b8230 372 int ret = -ENOTSUPP;
b423c420 373 if (dai->driver->compress_new)
aa7b8230
KM
374 ret = dai->driver->compress_new(rtd, num);
375 return soc_dai_ret(dai, ret);
b423c420 376}
467fece8
KM
377
378/*
379 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
380 *
381 * Returns true if the DAI supports the indicated stream type.
382 */
383bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
384{
acf253c1 385 struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
467fece8
KM
386
387 /* If the codec specifies any channels at all, it supports the stream */
388 return stream->channels_min;
389}
0b73ba55 390
dc829106
KM
391void snd_soc_dai_action(struct snd_soc_dai *dai,
392 int stream, int action)
393{
394 dai->stream_active[stream] += action;
395 dai->active += action;
396 dai->component->active += action;
397}
398EXPORT_SYMBOL_GPL(snd_soc_dai_action);
399
51801aea
KM
400int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
401{
402 struct snd_soc_dai *dai;
403 int i;
404
405 for_each_rtd_dais(rtd, i, dai) {
406 if (dai->driver->probe_order != order)
407 continue;
408
409 if (dai->driver->probe) {
410 int ret = dai->driver->probe(dai);
411
412 if (ret < 0)
413 return soc_dai_ret(dai, ret);
414 }
415
416 dai->probed = 1;
417 }
418
419 return 0;
420}
421
7eaa313b
KM
422int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
423{
424 struct snd_soc_dai *dai;
425 int i, r, ret = 0;
426
427 for_each_rtd_dais(rtd, i, dai) {
428 if (dai->driver->remove_order != order)
429 continue;
430
431 if (dai->probed &&
432 dai->driver->remove) {
433 r = dai->driver->remove(dai);
434 if (r < 0)
435 ret = r; /* use last error */
436 }
437
438 dai->probed = 0;
439 }
440
441 return ret;
442}
443
0b73ba55
KM
444int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
445{
446 struct snd_soc_dai *dai;
447 int i, ret = 0;
448
449 for_each_rtd_dais(rtd, i, dai) {
450 if (dai->driver->pcm_new) {
451 ret = dai->driver->pcm_new(rtd, dai);
452 if (ret < 0)
453 return soc_dai_ret(dai, ret);
454 }
455 }
456
457 return 0;
458}
d108c7fd
KM
459
460int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
461{
462 struct snd_soc_pcm_runtime *rtd = substream->private_data;
463 struct snd_soc_dai *dai;
464 int i, ret;
465
466 for_each_rtd_dais(rtd, i, dai) {
467 if (dai->driver->ops &&
468 dai->driver->ops->prepare) {
469 ret = dai->driver->ops->prepare(substream, dai);
470 if (ret < 0)
471 return soc_dai_ret(dai, ret);
472 }
473 }
474
475 return 0;
476}
42f2472d
KM
477
478int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
479 int cmd)
480{
481 struct snd_soc_pcm_runtime *rtd = substream->private_data;
482 struct snd_soc_dai *dai;
483 int i, ret;
484
485 for_each_rtd_dais(rtd, i, dai) {
486 if (dai->driver->ops &&
487 dai->driver->ops->trigger) {
488 ret = dai->driver->ops->trigger(substream, cmd, dai);
489 if (ret < 0)
490 return soc_dai_ret(dai, ret);
491 }
492 }
493
494 return 0;
495}
30819358
KM
496
497int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
498 int cmd)
499{
500 struct snd_soc_pcm_runtime *rtd = substream->private_data;
501 struct snd_soc_dai *dai;
502 int i, ret;
503
504 for_each_rtd_dais(rtd, i, dai) {
505 if (dai->driver->ops &&
506 dai->driver->ops->bespoke_trigger) {
507 ret = dai->driver->ops->bespoke_trigger(substream,
508 cmd, dai);
509 if (ret < 0)
510 return soc_dai_ret(dai, ret);
511 }
512 }
513
514 return 0;
515}
b5ae4cce
KM
516
517int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
518 struct snd_compr_stream *cstream)
519{
520 int ret = 0;
521
522 if (dai->driver->cops &&
523 dai->driver->cops->startup)
524 ret = dai->driver->cops->startup(cstream, dai);
525
526 return soc_dai_ret(dai, ret);
527}
528EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
2b25f81d
KM
529
530void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
531 struct snd_compr_stream *cstream)
532{
533 if (dai->driver->cops &&
534 dai->driver->cops->shutdown)
535 dai->driver->cops->shutdown(cstream, dai);
536}
537EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
eb08411b
KM
538
539int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
540 struct snd_compr_stream *cstream, int cmd)
541{
542 int ret = 0;
543
544 if (dai->driver->cops &&
545 dai->driver->cops->trigger)
546 ret = dai->driver->cops->trigger(cstream, cmd, dai);
547
548 return soc_dai_ret(dai, ret);
549}
550EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
8dfedafb
KM
551
552int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
553 struct snd_compr_stream *cstream,
554 struct snd_compr_params *params)
555{
556 int ret = 0;
557
558 if (dai->driver->cops &&
559 dai->driver->cops->set_params)
560 ret = dai->driver->cops->set_params(cstream, params, dai);
561
562 return soc_dai_ret(dai, ret);
563}
564EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
adbef543
KM
565
566int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
567 struct snd_compr_stream *cstream,
568 struct snd_codec *params)
569{
570 int ret = 0;
571
572 if (dai->driver->cops &&
573 dai->driver->cops->get_params)
574 ret = dai->driver->cops->get_params(cstream, params, dai);
575
576 return soc_dai_ret(dai, ret);
577}
578EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
53294353
KM
579
580int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
581 struct snd_compr_stream *cstream,
582 size_t bytes)
583{
584 int ret = 0;
585
586 if (dai->driver->cops &&
587 dai->driver->cops->ack)
588 ret = dai->driver->cops->ack(cstream, bytes, dai);
589
590 return soc_dai_ret(dai, ret);
591}
592EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
ed38cc59
KM
593
594int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
595 struct snd_compr_stream *cstream,
596 struct snd_compr_tstamp *tstamp)
597{
598 int ret = 0;
599
600 if (dai->driver->cops &&
601 dai->driver->cops->pointer)
602 ret = dai->driver->cops->pointer(cstream, tstamp, dai);
603
604 return soc_dai_ret(dai, ret);
605}
606EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
88b3a7df
KM
607
608int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
609 struct snd_compr_stream *cstream,
610 struct snd_compr_metadata *metadata)
611{
612 int ret = 0;
613
614 if (dai->driver->cops &&
615 dai->driver->cops->set_metadata)
616 ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
617
618 return soc_dai_ret(dai, ret);
619}
620EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
94d72819
KM
621
622int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
623 struct snd_compr_stream *cstream,
624 struct snd_compr_metadata *metadata)
625{
626 int ret = 0;
627
628 if (dai->driver->cops &&
629 dai->driver->cops->get_metadata)
630 ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
631
632 return soc_dai_ret(dai, ret);
633}
634EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);