Merge tag 'drm-misc-fixes-2019-12-11' of git://anongit.freedesktop.org/drm/drm-misc...
[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->driver->ops->startup)
299                 ret = dai->driver->ops->startup(substream, dai);
300
301         return ret;
302 }
303
304 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
305                          struct snd_pcm_substream *substream)
306 {
307         if (dai->driver->ops->shutdown)
308                 dai->driver->ops->shutdown(substream, dai);
309 }
310
311 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
312                         struct snd_pcm_substream *substream)
313 {
314         int ret = 0;
315
316         if (dai->driver->ops->prepare)
317                 ret = dai->driver->ops->prepare(substream, dai);
318
319         return ret;
320 }
321
322 int snd_soc_dai_trigger(struct snd_soc_dai *dai,
323                         struct snd_pcm_substream *substream,
324                         int cmd)
325 {
326         int ret = 0;
327
328         if (dai->driver->ops->trigger)
329                 ret = dai->driver->ops->trigger(substream, cmd, dai);
330
331         return ret;
332 }
333
334 int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai,
335                                 struct snd_pcm_substream *substream,
336                                 int cmd)
337 {
338         int ret = 0;
339
340         if (dai->driver->ops->bespoke_trigger)
341                 ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai);
342
343         return ret;
344 }
345
346 snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
347                                     struct snd_pcm_substream *substream)
348 {
349         int delay = 0;
350
351         if (dai->driver->ops->delay)
352                 delay = dai->driver->ops->delay(substream, dai);
353
354         return delay;
355 }
356
357 void snd_soc_dai_suspend(struct snd_soc_dai *dai)
358 {
359         if (dai->driver->suspend)
360                 dai->driver->suspend(dai);
361 }
362
363 void snd_soc_dai_resume(struct snd_soc_dai *dai)
364 {
365         if (dai->driver->resume)
366                 dai->driver->resume(dai);
367 }
368
369 int snd_soc_dai_probe(struct snd_soc_dai *dai)
370 {
371         if (dai->driver->probe)
372                 return dai->driver->probe(dai);
373         return 0;
374 }
375
376 int snd_soc_dai_remove(struct snd_soc_dai *dai)
377 {
378         if (dai->driver->remove)
379                 return dai->driver->remove(dai);
380         return 0;
381 }
382
383 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
384                              struct snd_soc_pcm_runtime *rtd, int num)
385 {
386         if (dai->driver->compress_new)
387                 return dai->driver->compress_new(rtd, num);
388         return -ENOTSUPP;
389 }
390
391 /*
392  * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
393  *
394  * Returns true if the DAI supports the indicated stream type.
395  */
396 bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
397 {
398         struct snd_soc_pcm_stream *stream;
399
400         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
401                 stream = &dai->driver->playback;
402         else
403                 stream = &dai->driver->capture;
404
405         /* If the codec specifies any channels at all, it supports the stream */
406         return stream->channels_min;
407 }