Blame view

sound/soc/soc-dai.c 17.9 KB
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
1
2
3
4
5
6
7
8
9
10
  // SPDX-License-Identifier: GPL-2.0
  //
  // soc-dai.c
  //
  // Copyright (C) 2019 Renesas Electronics Corp.
  // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  //
  
  #include <sound/soc.h>
  #include <sound/soc-dai.h>
0cbbf8a03   Kuninori Morimoto   ASoC: soc-link: a...
11
  #include <sound/soc-link.h>
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
12

aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
13
14
15
16
  #define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
  static inline int _soc_dai_ret(struct snd_soc_dai *dai,
  			       const char *func, int ret)
  {
28ff437a4   Pierre-Louis Bossart   ASoC: reduce verb...
17
18
19
20
21
  	/* Positive, Zero values are not errors */
  	if (ret >= 0)
  		return ret;
  
  	/* Negative values might be errors */
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
22
23
24
  	switch (ret) {
  	case -EPROBE_DEFER:
  	case -ENOTSUPP:
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
25
26
27
28
29
30
31
32
33
34
  		break;
  	default:
  		dev_err(dai->dev,
  			"ASoC: error at %s on %s: %d
  ",
  			func, dai->name, ret);
  	}
  
  	return ret;
  }
00a0b46c9   Kuninori Morimoto   ASoC: soc-dai: ad...
35
36
37
38
39
40
41
  /*
   * We might want to check substream by using list.
   * In such case, we can update these macros.
   */
  #define soc_dai_mark_push(dai, substream, tgt)	((dai)->mark_##tgt = substream)
  #define soc_dai_mark_pop(dai, substream, tgt)	((dai)->mark_##tgt = NULL)
  #define soc_dai_mark_match(dai, substream, tgt)	((dai)->mark_##tgt == substream)
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
42
43
44
45
46
47
48
49
50
51
52
53
  /**
   * snd_soc_dai_set_sysclk - configure DAI system or master clock.
   * @dai: DAI
   * @clk_id: DAI specific clock ID
   * @freq: new clock frequency in Hz
   * @dir: new clock direction - input/output.
   *
   * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
   */
  int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
  			   unsigned int freq, int dir)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
54
  	int ret;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
55
56
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_sysclk)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
57
58
59
60
  		ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
  	else
  		ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
  						   freq, dir);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
61

aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
62
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
  
  /**
   * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
   * @dai: DAI
   * @div_id: DAI specific clock divider ID
   * @div: new clock divisor.
   *
   * Configures the clock dividers. This is used to derive the best DAI bit and
   * frame clocks from the system or master clock. It's best to set the DAI bit
   * and frame clocks as low as possible to save system power.
   */
  int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
  			   int div_id, int div)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
79
  	int ret = -EINVAL;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
80
81
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_clkdiv)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
82
83
84
  		ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
  
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
  
  /**
   * snd_soc_dai_set_pll - configure DAI PLL.
   * @dai: DAI
   * @pll_id: DAI specific PLL ID
   * @source: DAI specific source for the PLL
   * @freq_in: PLL input clock frequency in Hz
   * @freq_out: requested PLL output clock frequency in Hz
   *
   * Configures and enables PLL to generate output clock based on input clock.
   */
  int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
  			unsigned int freq_in, unsigned int freq_out)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
101
  	int ret;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
102
103
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_pll)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
104
105
106
107
108
  		ret = dai->driver->ops->set_pll(dai, pll_id, source,
  						freq_in, freq_out);
  	else
  		ret = snd_soc_component_set_pll(dai->component, pll_id, source,
  						freq_in, freq_out);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
109

aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
110
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
111
112
113
114
115
116
117
118
119
120
121
122
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
  
  /**
   * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
   * @dai: DAI
   * @ratio: Ratio of BCLK to Sample rate.
   *
   * Configures the DAI for a preset BCLK to sample rate ratio.
   */
  int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
123
  	int ret = -EINVAL;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
124
125
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_bclk_ratio)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
126
127
128
  		ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
  
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
129
130
131
132
133
134
135
136
137
138
139
140
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
  
  /**
   * snd_soc_dai_set_fmt - configure DAI hardware audio format.
   * @dai: DAI
   * @fmt: SND_SOC_DAIFMT_* format value.
   *
   * Configures the DAI hardware format and clocking.
   */
  int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
141
  	int ret = -ENOTSUPP;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
142
143
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_fmt)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
144
145
146
  		ret = dai->driver->ops->set_fmt(dai, fmt);
  
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
  
  /**
   * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
   * @slots: Number of slots in use.
   * @tx_mask: bitmask representing active TX slots.
   * @rx_mask: bitmask representing active RX slots.
   *
   * Generates the TDM tx and rx slot default masks for DAI.
   */
  static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
  				       unsigned int *tx_mask,
  				       unsigned int *rx_mask)
  {
  	if (*tx_mask || *rx_mask)
  		return 0;
  
  	if (!slots)
  		return -EINVAL;
  
  	*tx_mask = (1 << slots) - 1;
  	*rx_mask = (1 << slots) - 1;
  
  	return 0;
  }
  
  /**
   * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
   * @dai: The DAI to configure
   * @tx_mask: bitmask representing active TX slots.
   * @rx_mask: bitmask representing active RX slots.
   * @slots: Number of slots in use.
   * @slot_width: Width in bits for each slot.
   *
   * This function configures the specified DAI for TDM operation. @slot contains
   * the total number of slots of the TDM stream and @slot_with the width of each
   * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
   * active slots of the TDM stream for the specified DAI, i.e. which slots the
   * DAI should write to or read from. If a bit is set the corresponding slot is
   * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
   * the first slot, bit 1 to the second slot and so on. The first active slot
   * maps to the first channel of the DAI, the second active slot to the second
   * channel and so on.
   *
   * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
   * @rx_mask and @slot_width will be ignored.
   *
   * Returns 0 on success, a negative error code otherwise.
   */
  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
  			     unsigned int tx_mask, unsigned int rx_mask,
  			     int slots, int slot_width)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
201
  	int ret = -ENOTSUPP;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
202
203
  	if (dai->driver->ops &&
  	    dai->driver->ops->xlate_tdm_slot_mask)
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
204
205
206
207
208
209
210
  		dai->driver->ops->xlate_tdm_slot_mask(slots,
  						      &tx_mask, &rx_mask);
  	else
  		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
  
  	dai->tx_mask = tx_mask;
  	dai->rx_mask = rx_mask;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
211
212
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_tdm_slot)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
213
  		ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
214
  						      slots, slot_width);
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
215
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
  
  /**
   * snd_soc_dai_set_channel_map - configure DAI audio channel map
   * @dai: DAI
   * @tx_num: how many TX channels
   * @tx_slot: pointer to an array which imply the TX slot number channel
   *           0~num-1 uses
   * @rx_num: how many RX channels
   * @rx_slot: pointer to an array which imply the RX slot number channel
   *           0~num-1 uses
   *
   * configure the relationship between channel number and TDM slot number.
   */
  int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
  				unsigned int tx_num, unsigned int *tx_slot,
  				unsigned int rx_num, unsigned int *rx_slot)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
235
  	int ret = -ENOTSUPP;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
236
237
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_channel_map)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
238
239
240
  		ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
  							rx_num, rx_slot);
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
  
  /**
   * snd_soc_dai_get_channel_map - Get DAI audio channel map
   * @dai: DAI
   * @tx_num: how many TX channels
   * @tx_slot: pointer to an array which imply the TX slot number channel
   *           0~num-1 uses
   * @rx_num: how many RX channels
   * @rx_slot: pointer to an array which imply the RX slot number channel
   *           0~num-1 uses
   */
  int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
  				unsigned int *tx_num, unsigned int *tx_slot,
  				unsigned int *rx_num, unsigned int *rx_slot)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
258
  	int ret = -ENOTSUPP;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
259
260
  	if (dai->driver->ops &&
  	    dai->driver->ops->get_channel_map)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
261
262
263
  		ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
  							rx_num, rx_slot);
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
264
265
266
267
268
269
270
271
272
273
274
275
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
  
  /**
   * snd_soc_dai_set_tristate - configure DAI system or master clock.
   * @dai: DAI
   * @tristate: tristate enable
   *
   * Tristates the DAI so that others can use it.
   */
  int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
276
  	int ret = -EINVAL;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
277
278
  	if (dai->driver->ops &&
  	    dai->driver->ops->set_tristate)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
279
280
281
  		ret = dai->driver->ops->set_tristate(dai, tristate);
  
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
  
  /**
   * snd_soc_dai_digital_mute - configure DAI system or master clock.
   * @dai: DAI
   * @mute: mute enable
   * @direction: stream to mute
   *
   * Mutes the DAI DAC.
   */
  int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
  			     int direction)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
296
  	int ret = -ENOTSUPP;
350d99351   Kuninori Morimoto   ASoC: soc-dai.c: ...
297
298
299
300
  	/*
  	 * ignore if direction was CAPTURE
  	 * and it had .no_capture_mute flag
  	 */
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
301
  	if (dai->driver->ops &&
350d99351   Kuninori Morimoto   ASoC: soc-dai.c: ...
302
303
304
  	    dai->driver->ops->mute_stream &&
  	    (direction == SNDRV_PCM_STREAM_PLAYBACK ||
  	     !dai->driver->ops->no_capture_mute))
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
305
  		ret = dai->driver->ops->mute_stream(dai, mute, direction);
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
306
307
  
  	return soc_dai_ret(dai, ret);
06f6e1d41   Kuninori Morimoto   ASoC: add soc-dai.c
308
309
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
aa6166c2a   Kuninori Morimoto   ASoC: soc-dai: mv...
310
311
312
313
314
  
  int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
  			  struct snd_pcm_substream *substream,
  			  struct snd_pcm_hw_params *params)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
315
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
316
  	int ret = 0;
aa6166c2a   Kuninori Morimoto   ASoC: soc-dai: mv...
317
318
  
  	/* perform any topology hw_params fixups before DAI  */
0cbbf8a03   Kuninori Morimoto   ASoC: soc-link: a...
319
320
321
  	ret = snd_soc_link_be_hw_params_fixup(rtd, params);
  	if (ret < 0)
  		goto end;
aa6166c2a   Kuninori Morimoto   ASoC: soc-dai: mv...
322

479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
323
324
  	if (dai->driver->ops &&
  	    dai->driver->ops->hw_params)
aa6166c2a   Kuninori Morimoto   ASoC: soc-dai: mv...
325
  		ret = dai->driver->ops->hw_params(substream, params, dai);
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
326
327
  end:
  	return soc_dai_ret(dai, ret);
aa6166c2a   Kuninori Morimoto   ASoC: soc-dai: mv...
328
  }
846faaed9   Kuninori Morimoto   ASoC: soc-dai: ad...
329
330
331
332
  
  void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
  			 struct snd_pcm_substream *substream)
  {
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
333
334
  	if (dai->driver->ops &&
  	    dai->driver->ops->hw_free)
846faaed9   Kuninori Morimoto   ASoC: soc-dai: ad...
335
336
  		dai->driver->ops->hw_free(substream, dai);
  }
5a52a0453   Kuninori Morimoto   ASoC: soc-dai: ad...
337
338
339
340
341
  
  int snd_soc_dai_startup(struct snd_soc_dai *dai,
  			struct snd_pcm_substream *substream)
  {
  	int ret = 0;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
342
343
  	if (dai->driver->ops &&
  	    dai->driver->ops->startup)
5a52a0453   Kuninori Morimoto   ASoC: soc-dai: ad...
344
  		ret = dai->driver->ops->startup(substream, dai);
00a0b46c9   Kuninori Morimoto   ASoC: soc-dai: ad...
345
346
347
  	/* mark substream if succeeded */
  	if (ret == 0)
  		soc_dai_mark_push(dai, substream, startup);
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
348
  	return soc_dai_ret(dai, ret);
5a52a0453   Kuninori Morimoto   ASoC: soc-dai: ad...
349
  }
330fcb513   Kuninori Morimoto   ASoC: soc-dai: ad...
350
351
  
  void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
00a0b46c9   Kuninori Morimoto   ASoC: soc-dai: ad...
352
353
  			  struct snd_pcm_substream *substream,
  			  int rollback)
330fcb513   Kuninori Morimoto   ASoC: soc-dai: ad...
354
  {
00a0b46c9   Kuninori Morimoto   ASoC: soc-dai: ad...
355
356
  	if (rollback && !soc_dai_mark_match(dai, substream, startup))
  		return;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
357
358
  	if (dai->driver->ops &&
  	    dai->driver->ops->shutdown)
330fcb513   Kuninori Morimoto   ASoC: soc-dai: ad...
359
  		dai->driver->ops->shutdown(substream, dai);
00a0b46c9   Kuninori Morimoto   ASoC: soc-dai: ad...
360
361
362
  
  	/* remove marked substream */
  	soc_dai_mark_pop(dai, substream, startup);
330fcb513   Kuninori Morimoto   ASoC: soc-dai: ad...
363
  }
4beb8e109   Kuninori Morimoto   ASoC: soc-dai: ad...
364

1dea80d4b   Kuninori Morimoto   ASoC: soc-dai: ad...
365
366
367
368
  snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
  				    struct snd_pcm_substream *substream)
  {
  	int delay = 0;
479914ed7   Kuninori Morimoto   ASoC: soc-dai: do...
369
370
  	if (dai->driver->ops &&
  	    dai->driver->ops->delay)
1dea80d4b   Kuninori Morimoto   ASoC: soc-dai: ad...
371
372
373
374
  		delay = dai->driver->ops->delay(substream, dai);
  
  	return delay;
  }
e0f226229   Kuninori Morimoto   ASoC: soc-dai: ad...
375

b423c4202   Kuninori Morimoto   ASoC: soc-dai: ad...
376
377
378
  int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
  			     struct snd_soc_pcm_runtime *rtd, int num)
  {
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
379
  	int ret = -ENOTSUPP;
b423c4202   Kuninori Morimoto   ASoC: soc-dai: ad...
380
  	if (dai->driver->compress_new)
aa7b8230d   Kuninori Morimoto   ASoC: soc-dai: ad...
381
382
  		ret = dai->driver->compress_new(rtd, num);
  	return soc_dai_ret(dai, ret);
b423c4202   Kuninori Morimoto   ASoC: soc-dai: ad...
383
  }
467fece8f   Kuninori Morimoto   ASoC: soc-dai: mo...
384
385
386
387
388
389
390
391
  
  /*
   * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
   *
   * Returns true if the DAI supports the indicated stream type.
   */
  bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
  {
acf253c11   Kuninori Morimoto   ASoC: soc-pcm: ad...
392
  	struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
467fece8f   Kuninori Morimoto   ASoC: soc-dai: mo...
393
394
395
396
  
  	/* If the codec specifies any channels at all, it supports the stream */
  	return stream->channels_min;
  }
0b73ba550   Kuninori Morimoto   ASoC: soc-dai: ad...
397

25612477d   Pierre-Louis Bossart   ASoC: soc-dai: se...
398
399
400
401
402
403
404
405
406
  /*
   * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs
   */
  void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
  {
  	struct snd_soc_dai_link_component *cpu;
  	struct snd_soc_dai_link_component *codec;
  	struct snd_soc_dai *dai;
  	bool supported[SNDRV_PCM_STREAM_LAST + 1];
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
407
408
  	bool supported_cpu;
  	bool supported_codec;
25612477d   Pierre-Louis Bossart   ASoC: soc-dai: se...
409
410
411
412
  	int direction;
  	int i;
  
  	for_each_pcm_streams(direction) {
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
413
414
  		supported_cpu = false;
  		supported_codec = false;
25612477d   Pierre-Louis Bossart   ASoC: soc-dai: se...
415
416
  
  		for_each_link_cpus(dai_link, i, cpu) {
c1c277b2c   Kuninori Morimoto   ASoC: soc-core: a...
417
  			dai = snd_soc_find_dai_with_mutex(cpu);
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
418
419
  			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
  				supported_cpu = true;
25612477d   Pierre-Louis Bossart   ASoC: soc-dai: se...
420
421
422
  				break;
  			}
  		}
25612477d   Pierre-Louis Bossart   ASoC: soc-dai: se...
423
  		for_each_link_codecs(dai_link, i, codec) {
c1c277b2c   Kuninori Morimoto   ASoC: soc-core: a...
424
  			dai = snd_soc_find_dai_with_mutex(codec);
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
425
426
  			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
  				supported_codec = true;
25612477d   Pierre-Louis Bossart   ASoC: soc-dai: se...
427
428
429
  				break;
  			}
  		}
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
430
  		supported[direction] = supported_cpu && supported_codec;
25612477d   Pierre-Louis Bossart   ASoC: soc-dai: se...
431
432
433
434
435
436
  	}
  
  	dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK];
  	dai_link->dpcm_capture  = supported[SNDRV_PCM_STREAM_CAPTURE];
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities);
dc8291068   Kuninori Morimoto   ASoC: soc-dai: ad...
437
438
439
  void snd_soc_dai_action(struct snd_soc_dai *dai,
  			int stream, int action)
  {
5552f8d72   Kuninori Morimoto   ASoC: soc-dai: ad...
440
  	/* see snd_soc_dai_stream_active() */
dc8291068   Kuninori Morimoto   ASoC: soc-dai: ad...
441
  	dai->stream_active[stream]	+= action;
0812a08ac   Kuninori Morimoto   ASoC: cleanup dai...
442

488b2ca59   Kuninori Morimoto   ASoC: soc-compone...
443
  	/* see snd_soc_component_active() */
dc8291068   Kuninori Morimoto   ASoC: soc-dai: ad...
444
445
446
  	dai->component->active		+= action;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_action);
efffd9b34   Kuninori Morimoto   ASoC: soc-dai: ad...
447
448
449
450
451
452
453
454
455
456
457
  int snd_soc_dai_active(struct snd_soc_dai *dai)
  {
  	int stream, active;
  
  	active = 0;
  	for_each_pcm_streams(stream)
  		active += dai->stream_active[stream];
  
  	return active;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_active);
51801aeaf   Kuninori Morimoto   ASoC: soc-dai: ad...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
  {
  	struct snd_soc_dai *dai;
  	int i;
  
  	for_each_rtd_dais(rtd, i, dai) {
  		if (dai->driver->probe_order != order)
  			continue;
  
  		if (dai->driver->probe) {
  			int ret = dai->driver->probe(dai);
  
  			if (ret < 0)
  				return soc_dai_ret(dai, ret);
  		}
  
  		dai->probed = 1;
  	}
  
  	return 0;
  }
7eaa313bd   Kuninori Morimoto   ASoC: soc-dai: ad...
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
  {
  	struct snd_soc_dai *dai;
  	int i, r, ret = 0;
  
  	for_each_rtd_dais(rtd, i, dai) {
  		if (dai->driver->remove_order != order)
  			continue;
  
  		if (dai->probed &&
  		    dai->driver->remove) {
  			r = dai->driver->remove(dai);
  			if (r < 0)
  				ret = r; /* use last error */
  		}
  
  		dai->probed = 0;
  	}
  
  	return ret;
  }
0b73ba550   Kuninori Morimoto   ASoC: soc-dai: ad...
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
  {
  	struct snd_soc_dai *dai;
  	int i, ret = 0;
  
  	for_each_rtd_dais(rtd, i, dai) {
  		if (dai->driver->pcm_new) {
  			ret = dai->driver->pcm_new(rtd, dai);
  			if (ret < 0)
  				return soc_dai_ret(dai, ret);
  		}
  	}
  
  	return 0;
  }
d108c7fd0   Kuninori Morimoto   ASoC: soc-dai: ad...
515
516
517
  
  int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
518
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
d108c7fd0   Kuninori Morimoto   ASoC: soc-dai: ad...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  	struct snd_soc_dai *dai;
  	int i, ret;
  
  	for_each_rtd_dais(rtd, i, dai) {
  		if (dai->driver->ops &&
  		    dai->driver->ops->prepare) {
  			ret = dai->driver->ops->prepare(substream, dai);
  			if (ret < 0)
  				return soc_dai_ret(dai, ret);
  		}
  	}
  
  	return 0;
  }
42f2472d4   Kuninori Morimoto   ASoC: soc-dai: ad...
533
534
535
536
  
  int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
  			    int cmd)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
537
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
42f2472d4   Kuninori Morimoto   ASoC: soc-dai: ad...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  	struct snd_soc_dai *dai;
  	int i, ret;
  
  	for_each_rtd_dais(rtd, i, dai) {
  		if (dai->driver->ops &&
  		    dai->driver->ops->trigger) {
  			ret = dai->driver->ops->trigger(substream, cmd, dai);
  			if (ret < 0)
  				return soc_dai_ret(dai, ret);
  		}
  	}
  
  	return 0;
  }
30819358a   Kuninori Morimoto   ASoC: soc-dai: ad...
552
553
554
555
  
  int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
  				    int cmd)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
556
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
30819358a   Kuninori Morimoto   ASoC: soc-dai: ad...
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
  	struct snd_soc_dai *dai;
  	int i, ret;
  
  	for_each_rtd_dais(rtd, i, dai) {
  		if (dai->driver->ops &&
  		    dai->driver->ops->bespoke_trigger) {
  			ret = dai->driver->ops->bespoke_trigger(substream,
  								cmd, dai);
  			if (ret < 0)
  				return soc_dai_ret(dai, ret);
  		}
  	}
  
  	return 0;
  }
b5ae4ccea   Kuninori Morimoto   ASoC: soc-dai: ad...
572
573
574
575
576
577
578
579
580
581
582
583
584
  
  int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
  			      struct snd_compr_stream *cstream)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->startup)
  		ret = dai->driver->cops->startup(cstream, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
2b25f81d4   Kuninori Morimoto   ASoC: soc-dai: ad...
585
586
587
588
589
590
591
592
593
  
  void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
  				struct snd_compr_stream *cstream)
  {
  	if (dai->driver->cops &&
  	    dai->driver->cops->shutdown)
  		dai->driver->cops->shutdown(cstream, dai);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
eb08411bd   Kuninori Morimoto   ASoC: soc-dai: ad...
594
595
596
597
598
599
600
601
602
603
604
605
606
  
  int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
  			      struct snd_compr_stream *cstream, int cmd)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->trigger)
  		ret = dai->driver->cops->trigger(cstream, cmd, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
8dfedafb5   Kuninori Morimoto   ASoC: soc-dai: ad...
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  
  int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
  				 struct snd_compr_stream *cstream,
  				 struct snd_compr_params *params)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->set_params)
  		ret = dai->driver->cops->set_params(cstream, params, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
adbef5432   Kuninori Morimoto   ASoC: soc-dai: ad...
621
622
623
624
625
626
627
628
629
630
631
632
633
634
  
  int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
  				 struct snd_compr_stream *cstream,
  				 struct snd_codec *params)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->get_params)
  		ret = dai->driver->cops->get_params(cstream, params, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
53294353a   Kuninori Morimoto   ASoC: soc-dai: ad...
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  
  int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
  			  struct snd_compr_stream *cstream,
  			  size_t bytes)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->ack)
  		ret = dai->driver->cops->ack(cstream, bytes, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
ed38cc590   Kuninori Morimoto   ASoC: soc-dai: ad...
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  
  int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
  			      struct snd_compr_stream *cstream,
  			      struct snd_compr_tstamp *tstamp)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->pointer)
  		ret = dai->driver->cops->pointer(cstream, tstamp, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
88b3a7dfe   Kuninori Morimoto   ASoC: soc-dai: ad...
663
664
665
666
667
668
669
670
671
672
673
674
675
676
  
  int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
  				   struct snd_compr_stream *cstream,
  				   struct snd_compr_metadata *metadata)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->set_metadata)
  		ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
94d728199   Kuninori Morimoto   ASoC: soc-dai: ad...
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  
  int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
  				   struct snd_compr_stream *cstream,
  				   struct snd_compr_metadata *metadata)
  {
  	int ret = 0;
  
  	if (dai->driver->cops &&
  	    dai->driver->cops->get_metadata)
  		ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
  
  	return soc_dai_ret(dai, ret);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);