ASoC: soc-dai: add snd_soc_pcm_dai_remove()
[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
51801aea
KM
391int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
392{
393 struct snd_soc_dai *dai;
394 int i;
395
396 for_each_rtd_dais(rtd, i, dai) {
397 if (dai->driver->probe_order != order)
398 continue;
399
400 if (dai->driver->probe) {
401 int ret = dai->driver->probe(dai);
402
403 if (ret < 0)
404 return soc_dai_ret(dai, ret);
405 }
406
407 dai->probed = 1;
408 }
409
410 return 0;
411}
412
7eaa313b
KM
413int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
414{
415 struct snd_soc_dai *dai;
416 int i, r, ret = 0;
417
418 for_each_rtd_dais(rtd, i, dai) {
419 if (dai->driver->remove_order != order)
420 continue;
421
422 if (dai->probed &&
423 dai->driver->remove) {
424 r = dai->driver->remove(dai);
425 if (r < 0)
426 ret = r; /* use last error */
427 }
428
429 dai->probed = 0;
430 }
431
432 return ret;
433}
434
0b73ba55
KM
435int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
436{
437 struct snd_soc_dai *dai;
438 int i, ret = 0;
439
440 for_each_rtd_dais(rtd, i, dai) {
441 if (dai->driver->pcm_new) {
442 ret = dai->driver->pcm_new(rtd, dai);
443 if (ret < 0)
444 return soc_dai_ret(dai, ret);
445 }
446 }
447
448 return 0;
449}
d108c7fd
KM
450
451int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
452{
453 struct snd_soc_pcm_runtime *rtd = substream->private_data;
454 struct snd_soc_dai *dai;
455 int i, ret;
456
457 for_each_rtd_dais(rtd, i, dai) {
458 if (dai->driver->ops &&
459 dai->driver->ops->prepare) {
460 ret = dai->driver->ops->prepare(substream, dai);
461 if (ret < 0)
462 return soc_dai_ret(dai, ret);
463 }
464 }
465
466 return 0;
467}
42f2472d
KM
468
469int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
470 int cmd)
471{
472 struct snd_soc_pcm_runtime *rtd = substream->private_data;
473 struct snd_soc_dai *dai;
474 int i, ret;
475
476 for_each_rtd_dais(rtd, i, dai) {
477 if (dai->driver->ops &&
478 dai->driver->ops->trigger) {
479 ret = dai->driver->ops->trigger(substream, cmd, dai);
480 if (ret < 0)
481 return soc_dai_ret(dai, ret);
482 }
483 }
484
485 return 0;
486}
30819358
KM
487
488int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
489 int cmd)
490{
491 struct snd_soc_pcm_runtime *rtd = substream->private_data;
492 struct snd_soc_dai *dai;
493 int i, ret;
494
495 for_each_rtd_dais(rtd, i, dai) {
496 if (dai->driver->ops &&
497 dai->driver->ops->bespoke_trigger) {
498 ret = dai->driver->ops->bespoke_trigger(substream,
499 cmd, dai);
500 if (ret < 0)
501 return soc_dai_ret(dai, ret);
502 }
503 }
504
505 return 0;
506}