x86/microcode: Fix return value for microcode late loading
[linux-2.6-microblaze.git] / sound / soc / soc-dai.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
12 /**
13  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
14  * @dai: DAI
15  * @clk_id: DAI specific clock ID
16  * @freq: new clock frequency in Hz
17  * @dir: new clock direction - input/output.
18  *
19  * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
20  */
21 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
22                            unsigned int freq, int dir)
23 {
24         if (dai->driver->ops->set_sysclk)
25                 return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
26
27         return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
28                                             freq, dir);
29 }
30 EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
31
32 /**
33  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
34  * @dai: DAI
35  * @div_id: DAI specific clock divider ID
36  * @div: new clock divisor.
37  *
38  * Configures the clock dividers. This is used to derive the best DAI bit and
39  * frame clocks from the system or master clock. It's best to set the DAI bit
40  * and frame clocks as low as possible to save system power.
41  */
42 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
43                            int div_id, int div)
44 {
45         if (dai->driver->ops->set_clkdiv)
46                 return dai->driver->ops->set_clkdiv(dai, div_id, div);
47         else
48                 return -EINVAL;
49 }
50 EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
51
52 /**
53  * snd_soc_dai_set_pll - configure DAI PLL.
54  * @dai: DAI
55  * @pll_id: DAI specific PLL ID
56  * @source: DAI specific source for the PLL
57  * @freq_in: PLL input clock frequency in Hz
58  * @freq_out: requested PLL output clock frequency in Hz
59  *
60  * Configures and enables PLL to generate output clock based on input clock.
61  */
62 int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
63                         unsigned int freq_in, unsigned int freq_out)
64 {
65         if (dai->driver->ops->set_pll)
66                 return dai->driver->ops->set_pll(dai, pll_id, source,
67                                                  freq_in, freq_out);
68
69         return snd_soc_component_set_pll(dai->component, pll_id, source,
70                                          freq_in, freq_out);
71 }
72 EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
73
74 /**
75  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
76  * @dai: DAI
77  * @ratio: Ratio of BCLK to Sample rate.
78  *
79  * Configures the DAI for a preset BCLK to sample rate ratio.
80  */
81 int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
82 {
83         if (dai->driver->ops->set_bclk_ratio)
84                 return dai->driver->ops->set_bclk_ratio(dai, ratio);
85         else
86                 return -EINVAL;
87 }
88 EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
89
90 /**
91  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
92  * @dai: DAI
93  * @fmt: SND_SOC_DAIFMT_* format value.
94  *
95  * Configures the DAI hardware format and clocking.
96  */
97 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
98 {
99         if (dai->driver->ops->set_fmt == NULL)
100                 return -ENOTSUPP;
101         return dai->driver->ops->set_fmt(dai, fmt);
102 }
103 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
104
105 /**
106  * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
107  * @slots: Number of slots in use.
108  * @tx_mask: bitmask representing active TX slots.
109  * @rx_mask: bitmask representing active RX slots.
110  *
111  * Generates the TDM tx and rx slot default masks for DAI.
112  */
113 static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
114                                        unsigned int *tx_mask,
115                                        unsigned int *rx_mask)
116 {
117         if (*tx_mask || *rx_mask)
118                 return 0;
119
120         if (!slots)
121                 return -EINVAL;
122
123         *tx_mask = (1 << slots) - 1;
124         *rx_mask = (1 << slots) - 1;
125
126         return 0;
127 }
128
129 /**
130  * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
131  * @dai: The DAI to configure
132  * @tx_mask: bitmask representing active TX slots.
133  * @rx_mask: bitmask representing active RX slots.
134  * @slots: Number of slots in use.
135  * @slot_width: Width in bits for each slot.
136  *
137  * This function configures the specified DAI for TDM operation. @slot contains
138  * the total number of slots of the TDM stream and @slot_with the width of each
139  * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
140  * active slots of the TDM stream for the specified DAI, i.e. which slots the
141  * DAI should write to or read from. If a bit is set the corresponding slot is
142  * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
143  * the first slot, bit 1 to the second slot and so on. The first active slot
144  * maps to the first channel of the DAI, the second active slot to the second
145  * channel and so on.
146  *
147  * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
148  * @rx_mask and @slot_width will be ignored.
149  *
150  * Returns 0 on success, a negative error code otherwise.
151  */
152 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
153                              unsigned int tx_mask, unsigned int rx_mask,
154                              int slots, int slot_width)
155 {
156         if (dai->driver->ops->xlate_tdm_slot_mask)
157                 dai->driver->ops->xlate_tdm_slot_mask(slots,
158                                                       &tx_mask, &rx_mask);
159         else
160                 snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
161
162         dai->tx_mask = tx_mask;
163         dai->rx_mask = rx_mask;
164
165         if (dai->driver->ops->set_tdm_slot)
166                 return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
167                                                       slots, slot_width);
168         else
169                 return -ENOTSUPP;
170 }
171 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
172
173 /**
174  * snd_soc_dai_set_channel_map - configure DAI audio channel map
175  * @dai: DAI
176  * @tx_num: how many TX channels
177  * @tx_slot: pointer to an array which imply the TX slot number channel
178  *           0~num-1 uses
179  * @rx_num: how many RX channels
180  * @rx_slot: pointer to an array which imply the RX slot number channel
181  *           0~num-1 uses
182  *
183  * configure the relationship between channel number and TDM slot number.
184  */
185 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
186                                 unsigned int tx_num, unsigned int *tx_slot,
187                                 unsigned int rx_num, unsigned int *rx_slot)
188 {
189         if (dai->driver->ops->set_channel_map)
190                 return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
191                                                          rx_num, rx_slot);
192         else
193                 return -ENOTSUPP;
194 }
195 EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
196
197 /**
198  * snd_soc_dai_get_channel_map - Get DAI audio channel map
199  * @dai: DAI
200  * @tx_num: how many TX channels
201  * @tx_slot: pointer to an array which imply the TX slot number channel
202  *           0~num-1 uses
203  * @rx_num: how many RX channels
204  * @rx_slot: pointer to an array which imply the RX slot number channel
205  *           0~num-1 uses
206  */
207 int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
208                                 unsigned int *tx_num, unsigned int *tx_slot,
209                                 unsigned int *rx_num, unsigned int *rx_slot)
210 {
211         if (dai->driver->ops->get_channel_map)
212                 return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
213                                                          rx_num, rx_slot);
214         else
215                 return -ENOTSUPP;
216 }
217 EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
218
219 /**
220  * snd_soc_dai_set_tristate - configure DAI system or master clock.
221  * @dai: DAI
222  * @tristate: tristate enable
223  *
224  * Tristates the DAI so that others can use it.
225  */
226 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
227 {
228         if (dai->driver->ops->set_tristate)
229                 return dai->driver->ops->set_tristate(dai, tristate);
230         else
231                 return -EINVAL;
232 }
233 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
234
235 /**
236  * snd_soc_dai_digital_mute - configure DAI system or master clock.
237  * @dai: DAI
238  * @mute: mute enable
239  * @direction: stream to mute
240  *
241  * Mutes the DAI DAC.
242  */
243 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
244                              int direction)
245 {
246         if (dai->driver->ops->mute_stream)
247                 return dai->driver->ops->mute_stream(dai, mute, direction);
248         else if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
249                  dai->driver->ops->digital_mute)
250                 return dai->driver->ops->digital_mute(dai, mute);
251         else
252                 return -ENOTSUPP;
253 }
254 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
255
256 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
257                           struct snd_pcm_substream *substream,
258                           struct snd_pcm_hw_params *params)
259 {
260         struct snd_soc_pcm_runtime *rtd = substream->private_data;
261         int ret;
262
263         /* perform any topology hw_params fixups before DAI  */
264         if (rtd->dai_link->be_hw_params_fixup) {
265                 ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
266                 if (ret < 0) {
267                         dev_err(rtd->dev,
268                                 "ASoC: hw_params topology fixup failed %d\n",
269                                 ret);
270                         return ret;
271                 }
272         }
273
274         if (dai->driver->ops->hw_params) {
275                 ret = dai->driver->ops->hw_params(substream, params, dai);
276                 if (ret < 0) {
277                         dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
278                                 dai->name, ret);
279                         return ret;
280                 }
281         }
282
283         return 0;
284 }
285
286 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
287                          struct snd_pcm_substream *substream)
288 {
289         if (dai->driver->ops->hw_free)
290                 dai->driver->ops->hw_free(substream, dai);
291 }
292
293 int snd_soc_dai_startup(struct snd_soc_dai *dai,
294                         struct snd_pcm_substream *substream)
295 {
296         int ret = 0;
297
298         if (!dai->started[substream->stream] &&
299             dai->driver->ops->startup)
300                 ret = dai->driver->ops->startup(substream, dai);
301
302         if (ret == 0)
303                 dai->started[substream->stream] = 1;
304
305         return ret;
306 }
307
308 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
309                          struct snd_pcm_substream *substream)
310 {
311         if (dai->started[substream->stream] &&
312             dai->driver->ops->shutdown)
313                 dai->driver->ops->shutdown(substream, dai);
314
315         dai->started[substream->stream] = 0;
316 }
317
318 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
319                         struct snd_pcm_substream *substream)
320 {
321         int ret = 0;
322
323         if (dai->driver->ops->prepare)
324                 ret = dai->driver->ops->prepare(substream, dai);
325
326         return ret;
327 }
328
329 int snd_soc_dai_trigger(struct snd_soc_dai *dai,
330                         struct snd_pcm_substream *substream,
331                         int cmd)
332 {
333         int ret = 0;
334
335         if (dai->driver->ops->trigger)
336                 ret = dai->driver->ops->trigger(substream, cmd, dai);
337
338         return ret;
339 }
340
341 int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai,
342                                 struct snd_pcm_substream *substream,
343                                 int cmd)
344 {
345         int ret = 0;
346
347         if (dai->driver->ops->bespoke_trigger)
348                 ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai);
349
350         return ret;
351 }
352
353 snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
354                                     struct snd_pcm_substream *substream)
355 {
356         int delay = 0;
357
358         if (dai->driver->ops->delay)
359                 delay = dai->driver->ops->delay(substream, dai);
360
361         return delay;
362 }
363
364 int snd_soc_dai_probe(struct snd_soc_dai *dai)
365 {
366         if (dai->driver->probe)
367                 return dai->driver->probe(dai);
368         return 0;
369 }
370
371 int snd_soc_dai_remove(struct snd_soc_dai *dai)
372 {
373         if (dai->driver->remove)
374                 return dai->driver->remove(dai);
375         return 0;
376 }
377
378 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
379                              struct snd_soc_pcm_runtime *rtd, int num)
380 {
381         if (dai->driver->compress_new)
382                 return dai->driver->compress_new(rtd, num);
383         return -ENOTSUPP;
384 }
385
386 /*
387  * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
388  *
389  * Returns true if the DAI supports the indicated stream type.
390  */
391 bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
392 {
393         struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
394
395         /* If the codec specifies any channels at all, it supports the stream */
396         return stream->channels_min;
397 }