ASoC: soc-dai: don't overwide dai->driver->ops
[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
KM
356
357int snd_soc_dai_prepare(struct snd_soc_dai *dai,
358 struct snd_pcm_substream *substream)
359{
360 int ret = 0;
361
479914ed
KM
362 if (dai->driver->ops &&
363 dai->driver->ops->prepare)
4beb8e10
KM
364 ret = dai->driver->ops->prepare(substream, dai);
365
aa7b8230 366 return soc_dai_ret(dai, ret);
4beb8e10 367}
95aef355
KM
368
369int snd_soc_dai_trigger(struct snd_soc_dai *dai,
370 struct snd_pcm_substream *substream,
371 int cmd)
372{
373 int ret = 0;
374
479914ed
KM
375 if (dai->driver->ops &&
376 dai->driver->ops->trigger)
95aef355
KM
377 ret = dai->driver->ops->trigger(substream, cmd, dai);
378
379 return ret;
380}
5c0769af
KM
381
382int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai,
383 struct snd_pcm_substream *substream,
384 int cmd)
385{
386 int ret = 0;
387
479914ed
KM
388 if (dai->driver->ops &&
389 dai->driver->ops->bespoke_trigger)
5c0769af
KM
390 ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai);
391
aa7b8230 392 return soc_dai_ret(dai, ret);
5c0769af 393}
1dea80d4
KM
394
395snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
396 struct snd_pcm_substream *substream)
397{
398 int delay = 0;
399
479914ed
KM
400 if (dai->driver->ops &&
401 dai->driver->ops->delay)
1dea80d4
KM
402 delay = dai->driver->ops->delay(substream, dai);
403
404 return delay;
405}
e0f22622 406
cfd9b5fb
KM
407int snd_soc_dai_probe(struct snd_soc_dai *dai)
408{
aa7b8230
KM
409 int ret = 0;
410
cfd9b5fb 411 if (dai->driver->probe)
aa7b8230
KM
412 ret = dai->driver->probe(dai);
413
414 return soc_dai_ret(dai, ret);
cfd9b5fb 415}
dcdab582
KM
416
417int snd_soc_dai_remove(struct snd_soc_dai *dai)
418{
aa7b8230
KM
419 int ret = 0;
420
dcdab582 421 if (dai->driver->remove)
aa7b8230
KM
422 ret = dai->driver->remove(dai);
423
424 return soc_dai_ret(dai, ret);
dcdab582 425}
b423c420
KM
426
427int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
428 struct snd_soc_pcm_runtime *rtd, int num)
429{
aa7b8230 430 int ret = -ENOTSUPP;
b423c420 431 if (dai->driver->compress_new)
aa7b8230
KM
432 ret = dai->driver->compress_new(rtd, num);
433 return soc_dai_ret(dai, ret);
b423c420 434}
467fece8
KM
435
436/*
437 * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
438 *
439 * Returns true if the DAI supports the indicated stream type.
440 */
441bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
442{
acf253c1 443 struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
467fece8
KM
444
445 /* If the codec specifies any channels at all, it supports the stream */
446 return stream->channels_min;
447}