Blame view

sound/soc/soc-pcm.c 79.4 KB
ed5175824   Kuninori Morimoto   ASoC: soc-pcm.c: ...
1
2
3
4
5
6
7
8
9
10
11
  // SPDX-License-Identifier: GPL-2.0+
  //
  // soc-pcm.c  --  ALSA SoC PCM
  //
  // Copyright 2005 Wolfson Microelectronics PLC.
  // Copyright 2005 Openedhand Ltd.
  // Copyright (C) 2010 Slimlogic Ltd.
  // Copyright (C) 2010 Texas Instruments Inc.
  //
  // Authors: Liam Girdwood <lrg@ti.com>
  //          Mark Brown <broonie@opensource.wolfsonmicro.com>
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
12
13
14
15
  
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/delay.h>
988e8cc41   Nicolin Chen   ASoC: Add pinctrl...
16
  #include <linux/pinctrl/consumer.h>
d6652ef82   Mark Brown   ASoC: Hold runtim...
17
  #include <linux/pm_runtime.h>
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
18
19
  #include <linux/slab.h>
  #include <linux/workqueue.h>
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
20
  #include <linux/export.h>
f86dcef87   Liam Girdwood   ASoC: dpcm: Add d...
21
  #include <linux/debugfs.h>
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
22
23
24
25
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/soc.h>
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
26
  #include <sound/soc-dpcm.h>
a5e6c1090   Kuninori Morimoto   ASoC: soc-link: m...
27
  #include <sound/soc-link.h>
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
28
  #include <sound/initval.h>
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
29
  #define DPCM_MAX_BE_USERS	8
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
  #ifdef CONFIG_DEBUG_FS
  static const char *dpcm_state_string(enum snd_soc_dpcm_state state)
  {
  	switch (state) {
  	case SND_SOC_DPCM_STATE_NEW:
  		return "new";
  	case SND_SOC_DPCM_STATE_OPEN:
  		return "open";
  	case SND_SOC_DPCM_STATE_HW_PARAMS:
  		return "hw_params";
  	case SND_SOC_DPCM_STATE_PREPARE:
  		return "prepare";
  	case SND_SOC_DPCM_STATE_START:
  		return "start";
  	case SND_SOC_DPCM_STATE_STOP:
  		return "stop";
  	case SND_SOC_DPCM_STATE_SUSPEND:
  		return "suspend";
  	case SND_SOC_DPCM_STATE_PAUSED:
  		return "paused";
  	case SND_SOC_DPCM_STATE_HW_FREE:
  		return "hw_free";
  	case SND_SOC_DPCM_STATE_CLOSE:
  		return "close";
  	}
  
  	return "unknown";
  }
  
  static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
  			       int stream, char *buf, size_t size)
  {
  	struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
  	struct snd_soc_dpcm *dpcm;
  	ssize_t offset = 0;
  	unsigned long flags;
  
  	/* FE state */
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
68
  	offset += scnprintf(buf + offset, size - offset,
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
69
70
71
  			   "[%s - %s]
  ", fe->dai_link->name,
  			   stream ? "Capture" : "Playback");
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
72
73
  	offset += scnprintf(buf + offset, size - offset, "State: %s
  ",
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
74
75
76
77
  			   dpcm_state_string(fe->dpcm[stream].state));
  
  	if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
  	    (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
78
  		offset += scnprintf(buf + offset, size - offset,
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
79
80
81
82
83
84
85
86
  				   "Hardware Params: "
  				   "Format = %s, Channels = %d, Rate = %d
  ",
  				   snd_pcm_format_name(params_format(params)),
  				   params_channels(params),
  				   params_rate(params));
  
  	/* BEs state */
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
87
88
  	offset += scnprintf(buf + offset, size - offset, "Backends:
  ");
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
89
90
  
  	if (list_empty(&fe->dpcm[stream].be_clients)) {
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
91
  		offset += scnprintf(buf + offset, size - offset,
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
92
93
94
95
96
97
98
99
100
  				   " No active DSP links
  ");
  		goto out;
  	}
  
  	spin_lock_irqsave(&fe->card->dpcm_lock, flags);
  	for_each_dpcm_be(fe, stream, dpcm) {
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		params = &dpcm->hw_params;
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
101
  		offset += scnprintf(buf + offset, size - offset,
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
102
103
  				   "- %s
  ", be->dai_link->name);
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
104
  		offset += scnprintf(buf + offset, size - offset,
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
105
106
107
108
109
110
  				   "   State: %s
  ",
  				   dpcm_state_string(be->dpcm[stream].state));
  
  		if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
  		    (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
d0c9abb83   Takashi Iwai   ASoC: pcm: Fix (a...
111
  			offset += scnprintf(buf + offset, size - offset,
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  					   "   Hardware Params: "
  					   "Format = %s, Channels = %d, Rate = %d
  ",
  					   snd_pcm_format_name(params_format(params)),
  					   params_channels(params),
  					   params_rate(params));
  	}
  	spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
  out:
  	return offset;
  }
  
  static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
  				    size_t count, loff_t *ppos)
  {
  	struct snd_soc_pcm_runtime *fe = file->private_data;
  	ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
  	int stream;
  	char *buf;
6e1276a5e   Bard Liao   ASoC: Return erro...
131
132
133
134
135
136
  	if (fe->num_cpus > 1) {
  		dev_err(fe->dev,
  			"%s doesn't support Multi CPU yet
  ", __func__);
  		return -EINVAL;
  	}
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
137
138
139
140
141
  	buf = kmalloc(out_count, GFP_KERNEL);
  	if (!buf)
  		return -ENOMEM;
  
  	for_each_pcm_streams(stream)
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
142
  		if (snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0), stream))
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
143
144
145
146
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
  			offset += dpcm_show_state(fe, stream,
  						  buf + offset,
  						  out_count - offset);
  
  	ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
  
  	kfree(buf);
  	return ret;
  }
  
  static const struct file_operations dpcm_state_fops = {
  	.open = simple_open,
  	.read = dpcm_state_read_file,
  	.llseek = default_llseek,
  };
  
  void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
  {
  	if (!rtd->dai_link)
  		return;
  
  	if (!rtd->dai_link->dynamic)
  		return;
  
  	if (!rtd->card->debugfs_card_root)
  		return;
  
  	rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
  						    rtd->card->debugfs_card_root);
  
  	debugfs_create_file("state", 0444, rtd->debugfs_dpcm_root,
  			    rtd, &dpcm_state_fops);
  }
154dae87e   Kuninori Morimoto   ASoC: soc-pcm: ad...
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
201
202
203
204
205
  
  static void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm, int stream)
  {
  	char *name;
  
  	name = kasprintf(GFP_KERNEL, "%s:%s", dpcm->be->dai_link->name,
  			 stream ? "capture" : "playback");
  	if (name) {
  		dpcm->debugfs_state = debugfs_create_dir(
  			name, dpcm->fe->debugfs_dpcm_root);
  		debugfs_create_u32("state", 0644, dpcm->debugfs_state,
  				   &dpcm->state);
  		kfree(name);
  	}
  }
  
  static void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
  {
  	debugfs_remove_recursive(dpcm->debugfs_state);
  }
  
  #else
  static inline void dpcm_create_debugfs_state(struct snd_soc_dpcm *dpcm,
  					     int stream)
  {
  }
  
  static inline void dpcm_remove_debugfs_state(struct snd_soc_dpcm *dpcm)
  {
  }
c3212829f   Kuninori Morimoto   ASoC: soc-pcm: mo...
206
  #endif
d9051d86a   Kuninori Morimoto   ASoC: soc-pcm: re...
207
208
209
210
211
  /**
   * snd_soc_runtime_action() - Increment/Decrement active count for
   * PCM runtime components
   * @rtd: ASoC PCM runtime that is activated
   * @stream: Direction of the PCM stream
b6d6e9ea8   Colton Lewis   snd/soc: correct ...
212
   * @action: Activate stream if 1. Deactivate if -1.
d9051d86a   Kuninori Morimoto   ASoC: soc-pcm: re...
213
214
215
216
217
218
219
220
221
   *
   * Increments/Decrements the active count for all the DAIs and components
   * attached to a PCM runtime.
   * Should typically be called when a stream is opened.
   *
   * Must be called with the rtd->card->pcm_mutex being held
   */
  void snd_soc_runtime_action(struct snd_soc_pcm_runtime *rtd,
  			    int stream, int action)
24894b764   Lars-Peter Clausen   ASoC: Add helper ...
222
  {
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
223
  	struct snd_soc_dai *dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
224
  	int i;
24894b764   Lars-Peter Clausen   ASoC: Add helper ...
225

72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
226
  	lockdep_assert_held(&rtd->card->pcm_mutex);
24894b764   Lars-Peter Clausen   ASoC: Add helper ...
227

dc8291068   Kuninori Morimoto   ASoC: soc-dai: ad...
228
229
  	for_each_rtd_dais(rtd, i, dai)
  		snd_soc_dai_action(dai, stream, action);
24894b764   Lars-Peter Clausen   ASoC: Add helper ...
230
  }
d9051d86a   Kuninori Morimoto   ASoC: soc-pcm: re...
231
  EXPORT_SYMBOL_GPL(snd_soc_runtime_action);
24894b764   Lars-Peter Clausen   ASoC: Add helper ...
232
233
  
  /**
208a1589d   Lars-Peter Clausen   ASoC: Handle igno...
234
235
236
237
238
239
240
241
242
243
   * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay
   * @rtd: The ASoC PCM runtime that should be checked.
   *
   * This function checks whether the power down delay should be ignored for a
   * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has
   * been configured to ignore the delay, or if none of the components benefits
   * from having the delay.
   */
  bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd)
  {
fbb16563c   Kuninori Morimoto   ASoC: snd_soc_com...
244
  	struct snd_soc_component *component;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
245
  	bool ignore = true;
613fb5005   Kuninori Morimoto   ASoC: soc-core: r...
246
  	int i;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
247

208a1589d   Lars-Peter Clausen   ASoC: Handle igno...
248
249
  	if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time)
  		return true;
613fb5005   Kuninori Morimoto   ASoC: soc-core: r...
250
  	for_each_rtd_components(rtd, i, component)
72c381841   Kuninori Morimoto   ASoC: soc-pcm: re...
251
  		ignore &= !component->driver->use_pmdown_time;
fbb16563c   Kuninori Morimoto   ASoC: snd_soc_com...
252

fbb16563c   Kuninori Morimoto   ASoC: snd_soc_com...
253
  	return ignore;
208a1589d   Lars-Peter Clausen   ASoC: Handle igno...
254
255
256
  }
  
  /**
90996f43b   Lars-Peter Clausen   ASoC: core: Move ...
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
   * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
   * @substream: the pcm substream
   * @hw: the hardware parameters
   *
   * Sets the substream runtime hardware parameters.
   */
  int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
  	const struct snd_pcm_hardware *hw)
  {
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	runtime->hw.info = hw->info;
  	runtime->hw.formats = hw->formats;
  	runtime->hw.period_bytes_min = hw->period_bytes_min;
  	runtime->hw.period_bytes_max = hw->period_bytes_max;
  	runtime->hw.periods_min = hw->periods_min;
  	runtime->hw.periods_max = hw->periods_max;
  	runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
  	runtime->hw.fifo_size = hw->fifo_size;
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
278
  /* DPCM stream event, send event to FE and all active BEs. */
236070253   Liam Girdwood   ASoC: DPCM: make ...
279
  int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
280
281
282
  	int event)
  {
  	struct snd_soc_dpcm *dpcm;
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
283
  	for_each_dpcm_be(fe, dir, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
284
285
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
286
287
  		dev_dbg(be->dev, "ASoC: BE %s event %d dir %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
288
  				be->dai_link->name, event, dir);
b1cd2e34c   Banajit Goswami   ASoC: do not clos...
289
290
291
  		if ((event == SND_SOC_DAPM_STREAM_STOP) &&
  		    (be->dpcm[dir].users >= 1))
  			continue;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
292
293
294
295
296
297
298
  		snd_soc_dapm_stream_event(be, dir, event);
  	}
  
  	snd_soc_dapm_stream_event(fe, dir, event);
  
  	return 0;
  }
17841020e   Dong Aisheng   ASoC: soc-core: s...
299
300
  static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
  					struct snd_soc_dai *soc_dai)
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
301
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
302
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
303
  	int ret;
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
304
305
306
307
308
  	if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
  				rtd->dai_link->symmetric_rates)) {
  		dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate
  ",
  				soc_dai->rate);
4dcdd43b4   Lars-Peter Clausen   ASoC: pcm: Use sn...
309
  		ret = snd_pcm_hw_constraint_single(substream->runtime,
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
310
  						SNDRV_PCM_HW_PARAM_RATE,
4dcdd43b4   Lars-Peter Clausen   ASoC: pcm: Use sn...
311
  						soc_dai->rate);
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
312
313
314
315
316
317
318
319
  		if (ret < 0) {
  			dev_err(soc_dai->dev,
  				"ASoC: Unable to apply rate constraint: %d
  ",
  				ret);
  			return ret;
  		}
  	}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
320

3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
321
322
323
324
325
  	if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
  				rtd->dai_link->symmetric_channels)) {
  		dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)
  ",
  				soc_dai->channels);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
326

4dcdd43b4   Lars-Peter Clausen   ASoC: pcm: Use sn...
327
  		ret = snd_pcm_hw_constraint_single(substream->runtime,
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
328
  						SNDRV_PCM_HW_PARAM_CHANNELS,
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
329
330
331
332
333
334
335
336
  						soc_dai->channels);
  		if (ret < 0) {
  			dev_err(soc_dai->dev,
  				"ASoC: Unable to apply channel symmetry constraint: %d
  ",
  				ret);
  			return ret;
  		}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
337
  	}
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
338
339
340
341
342
  	if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
  				rtd->dai_link->symmetric_samplebits)) {
  		dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits
  ",
  				soc_dai->sample_bits);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
343

4dcdd43b4   Lars-Peter Clausen   ASoC: pcm: Use sn...
344
  		ret = snd_pcm_hw_constraint_single(substream->runtime,
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
345
  						SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
346
347
348
349
350
351
352
353
  						soc_dai->sample_bits);
  		if (ret < 0) {
  			dev_err(soc_dai->dev,
  				"ASoC: Unable to apply sample bits symmetry constraint: %d
  ",
  				ret);
  			return ret;
  		}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
354
355
356
357
  	}
  
  	return 0;
  }
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
358
359
360
  static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
  				struct snd_pcm_hw_params *params)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
361
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
362
  	struct snd_soc_dai *dai;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
363
  	struct snd_soc_dai *cpu_dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
364
  	unsigned int rate, channels, sample_bits, symmetry, i;
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
365
366
367
368
369
370
  
  	rate = params_rate(params);
  	channels = params_channels(params);
  	sample_bits = snd_pcm_format_physical_width(params_format(params));
  
  	/* reject unmatched parameters when applying symmetry */
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
371
  	symmetry = rtd->dai_link->symmetric_rates;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
372
373
  	for_each_rtd_cpu_dais(rtd, i, dai)
  		symmetry |= dai->driver->symmetric_rates;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
374

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
375
  	if (symmetry) {
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
376
  		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
377
378
379
380
381
382
383
  			if (cpu_dai->rate && cpu_dai->rate != rate) {
  				dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d
  ",
  					cpu_dai->rate, rate);
  				return -EINVAL;
  			}
  		}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
384
  	}
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
385
  	symmetry = rtd->dai_link->symmetric_channels;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
386
387
  	for_each_rtd_dais(rtd, i, dai)
  		symmetry |= dai->driver->symmetric_channels;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
388

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
389
  	if (symmetry) {
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
390
  		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
391
392
393
394
395
396
397
398
  			if (cpu_dai->channels &&
  			    cpu_dai->channels != channels) {
  				dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d
  ",
  					cpu_dai->channels, channels);
  				return -EINVAL;
  			}
  		}
3635bf09a   Nicolin Chen   ASoC: soc-pcm: ad...
399
  	}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
400

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
401
  	symmetry = rtd->dai_link->symmetric_samplebits;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
402
403
  	for_each_rtd_dais(rtd, i, dai)
  		symmetry |= dai->driver->symmetric_samplebits;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
404

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
405
  	if (symmetry) {
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
406
  		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
407
408
409
410
411
412
413
414
  			if (cpu_dai->sample_bits &&
  			    cpu_dai->sample_bits != sample_bits) {
  				dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d
  ",
  					cpu_dai->sample_bits, sample_bits);
  				return -EINVAL;
  			}
  		}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
415
416
417
418
  	}
  
  	return 0;
  }
62e5f676f   Lars-Peter Clausen   ASoC: Set SNDRV_P...
419
420
  static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
421
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
62e5f676f   Lars-Peter Clausen   ASoC: Set SNDRV_P...
422
  	struct snd_soc_dai_link *link = rtd->dai_link;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
423
  	struct snd_soc_dai *dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
424
  	unsigned int symmetry, i;
62e5f676f   Lars-Peter Clausen   ASoC: Set SNDRV_P...
425

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
426
427
428
  	symmetry = link->symmetric_rates ||
  		link->symmetric_channels ||
  		link->symmetric_samplebits;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
429
  	for_each_rtd_dais(rtd, i, dai)
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
430
  		symmetry = symmetry ||
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
431
432
433
  			dai->driver->symmetric_rates ||
  			dai->driver->symmetric_channels ||
  			dai->driver->symmetric_samplebits;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
434
435
  
  	return symmetry;
62e5f676f   Lars-Peter Clausen   ASoC: Set SNDRV_P...
436
  }
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
437
  static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits)
58ba9b254   Mark Brown   ASoC: Allow drive...
438
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
439
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
c6068d3a7   Takashi Iwai   ASoC: pcm: Fix un...
440
  	int ret;
58ba9b254   Mark Brown   ASoC: Allow drive...
441
442
443
  
  	if (!bits)
  		return;
0e2a37513   Lars-Peter Clausen   ASoC: pcm: Use wi...
444
445
446
447
448
  	ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 0, bits);
  	if (ret != 0)
  		dev_warn(rtd->dev, "ASoC: Failed to set MSB %d: %d
  ",
  				 bits, ret);
58ba9b254   Mark Brown   ASoC: Allow drive...
449
  }
c8dd1fec4   Benoit Cousson   ASoC: pcm: Refact...
450
451
  static void soc_pcm_apply_msb(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
452
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
453
  	struct snd_soc_dai *cpu_dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
454
  	struct snd_soc_dai *codec_dai;
57be92066   Kuninori Morimoto   ASoC: soc-pcm: cl...
455
456
  	struct snd_soc_pcm_stream *pcm_codec, *pcm_cpu;
  	int stream = substream->stream;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
457
  	int i;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
458
  	unsigned int bits = 0, cpu_bits = 0;
c8dd1fec4   Benoit Cousson   ASoC: pcm: Refact...
459

a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
460
  	for_each_rtd_codec_dais(rtd, i, codec_dai) {
57be92066   Kuninori Morimoto   ASoC: soc-pcm: cl...
461
462
463
464
465
  		pcm_codec = snd_soc_dai_get_pcm_stream(codec_dai, stream);
  
  		if (pcm_codec->sig_bits == 0) {
  			bits = 0;
  			break;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
466
  		}
57be92066   Kuninori Morimoto   ASoC: soc-pcm: cl...
467
  		bits = max(pcm_codec->sig_bits, bits);
c8dd1fec4   Benoit Cousson   ASoC: pcm: Refact...
468
  	}
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
469
  	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
470
471
472
473
474
475
476
477
  		pcm_cpu = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
  
  		if (pcm_cpu->sig_bits == 0) {
  			cpu_bits = 0;
  			break;
  		}
  		cpu_bits = max(pcm_cpu->sig_bits, cpu_bits);
  	}
57be92066   Kuninori Morimoto   ASoC: soc-pcm: cl...
478

2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
479
480
  	soc_pcm_set_msb(substream, bits);
  	soc_pcm_set_msb(substream, cpu_bits);
c8dd1fec4   Benoit Cousson   ASoC: pcm: Refact...
481
  }
5854a4648   Samuel Holland   ASoC: pcm: Export...
482
483
484
485
486
487
488
489
490
491
492
  /**
   * snd_soc_runtime_calc_hw() - Calculate hw limits for a PCM stream
   * @rtd: ASoC PCM runtime
   * @hw: PCM hardware parameters (output)
   * @stream: Direction of the PCM stream
   *
   * Calculates the subset of stream parameters supported by all DAIs
   * associated with the PCM stream.
   */
  int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd,
  			    struct snd_pcm_hardware *hw, int stream)
bd477c31c   Lars-Peter Clausen   ASoC: core: Add h...
493
  {
0b7990e38   Kuninori Morimoto   ASoC: add for_eac...
494
  	struct snd_soc_dai *codec_dai;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
495
  	struct snd_soc_dai *cpu_dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
496
497
498
  	struct snd_soc_pcm_stream *codec_stream;
  	struct snd_soc_pcm_stream *cpu_stream;
  	unsigned int chan_min = 0, chan_max = UINT_MAX;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
499
  	unsigned int cpu_chan_min = 0, cpu_chan_max = UINT_MAX;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
500
  	unsigned int rate_min = 0, rate_max = UINT_MAX;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
501
502
  	unsigned int cpu_rate_min = 0, cpu_rate_max = UINT_MAX;
  	unsigned int rates = UINT_MAX, cpu_rates = UINT_MAX;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
503
504
  	u64 formats = ULLONG_MAX;
  	int i;
78e45c99f   Lars-Peter Clausen   ASoC: pcm: Always...
505

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
506
  	/* first calculate min/max only for CPUs in the DAI link */
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
507
  	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
508
509
510
511
512
513
  
  		/*
  		 * Skip CPUs which don't support the current stream type.
  		 * Otherwise, since the rate, channel, and format values will
  		 * zero in that case, we would have no usable settings left,
  		 * causing the resulting setup to fail.
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
514
  		 */
5854a4648   Samuel Holland   ASoC: pcm: Export...
515
  		if (!snd_soc_dai_stream_valid(cpu_dai, stream))
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
516
  			continue;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
517
518
519
520
521
522
523
524
525
526
  		cpu_stream = snd_soc_dai_get_pcm_stream(cpu_dai, stream);
  
  		cpu_chan_min = max(cpu_chan_min, cpu_stream->channels_min);
  		cpu_chan_max = min(cpu_chan_max, cpu_stream->channels_max);
  		cpu_rate_min = max(cpu_rate_min, cpu_stream->rate_min);
  		cpu_rate_max = min_not_zero(cpu_rate_max, cpu_stream->rate_max);
  		formats &= cpu_stream->formats;
  		cpu_rates = snd_pcm_rate_mask_intersect(cpu_stream->rates,
  							cpu_rates);
  	}
78e45c99f   Lars-Peter Clausen   ASoC: pcm: Always...
527

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
528
  	/* second calculate min/max only for CODECs in the DAI link */
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
529
  	for_each_rtd_codec_dais(rtd, i, codec_dai) {
cde79035c   Ricard Wanderlof   ASoC: Handle mult...
530
531
532
533
534
535
  
  		/*
  		 * Skip CODECs which don't support the current stream type.
  		 * Otherwise, since the rate, channel, and format values will
  		 * zero in that case, we would have no usable settings left,
  		 * causing the resulting setup to fail.
cde79035c   Ricard Wanderlof   ASoC: Handle mult...
536
  		 */
25c2f5156   Kuninori Morimoto   ASoC: soc-pcm: us...
537
  		if (!snd_soc_dai_stream_valid(codec_dai, stream))
cde79035c   Ricard Wanderlof   ASoC: Handle mult...
538
  			continue;
acf253c11   Kuninori Morimoto   ASoC: soc-pcm: ad...
539
  		codec_stream = snd_soc_dai_get_pcm_stream(codec_dai, stream);
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
540
541
542
543
544
545
546
  		chan_min = max(chan_min, codec_stream->channels_min);
  		chan_max = min(chan_max, codec_stream->channels_max);
  		rate_min = max(rate_min, codec_stream->rate_min);
  		rate_max = min_not_zero(rate_max, codec_stream->rate_max);
  		formats &= codec_stream->formats;
  		rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates);
  	}
5854a4648   Samuel Holland   ASoC: pcm: Export...
547
548
549
  	/* Verify both a valid CPU DAI and a valid CODEC DAI were found */
  	if (!chan_min || !cpu_chan_min)
  		return -EINVAL;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
550
551
  	/*
  	 * chan min/max cannot be enforced if there are multiple CODEC DAIs
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
552
  	 * connected to CPU DAI(s), use CPU DAI's directly and let
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
553
554
555
  	 * channel allocation be fixed up later
  	 */
  	if (rtd->num_codecs > 1) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
556
557
  		chan_min = cpu_chan_min;
  		chan_max = cpu_chan_max;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
558
  	}
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
559
560
561
  	/* finally find a intersection between CODECs and CPUs */
  	hw->channels_min = max(chan_min, cpu_chan_min);
  	hw->channels_max = min(chan_max, cpu_chan_max);
5854a4648   Samuel Holland   ASoC: pcm: Export...
562
  	hw->formats = formats;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
563
  	hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_rates);
78e45c99f   Lars-Peter Clausen   ASoC: pcm: Always...
564

5854a4648   Samuel Holland   ASoC: pcm: Export...
565
  	snd_pcm_hw_limit_rates(hw);
78e45c99f   Lars-Peter Clausen   ASoC: pcm: Always...
566

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
567
  	hw->rate_min = max(hw->rate_min, cpu_rate_min);
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
568
  	hw->rate_min = max(hw->rate_min, rate_min);
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
569
  	hw->rate_max = min_not_zero(hw->rate_max, cpu_rate_max);
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
570
  	hw->rate_max = min_not_zero(hw->rate_max, rate_max);
5854a4648   Samuel Holland   ASoC: pcm: Export...
571
572
573
574
575
576
577
578
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_runtime_calc_hw);
  
  static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
  {
  	struct snd_pcm_hardware *hw = &substream->runtime->hw;
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
579
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
5854a4648   Samuel Holland   ASoC: pcm: Export...
580
581
582
583
584
585
586
587
588
589
590
  	u64 formats = hw->formats;
  
  	/*
  	 * At least one CPU and one CODEC should match. Otherwise, we should
  	 * have bailed out on a higher level, since there would be no CPU or
  	 * CODEC to support the transfer direction in that case.
  	 */
  	snd_soc_runtime_calc_hw(rtd, hw, substream->stream);
  
  	if (formats)
  		hw->formats &= formats;
bd477c31c   Lars-Peter Clausen   ASoC: core: Add h...
591
  }
dd03907bf   Kuninori Morimoto   ASoC: soc-pcm: ca...
592
  static int soc_pcm_components_open(struct snd_pcm_substream *substream)
e7ecfdb79   Kuninori Morimoto   ASoC: soc-pcm: ad...
593
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
594
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
e7ecfdb79   Kuninori Morimoto   ASoC: soc-pcm: ad...
595
  	struct snd_soc_component *component;
613fb5005   Kuninori Morimoto   ASoC: soc-core: r...
596
  	int i, ret = 0;
e7ecfdb79   Kuninori Morimoto   ASoC: soc-pcm: ad...
597

613fb5005   Kuninori Morimoto   ASoC: soc-core: r...
598
  	for_each_rtd_components(rtd, i, component) {
51aff91ad   Kuninori Morimoto   ASoC: soc-compone...
599
  		ret = snd_soc_component_module_get_when_open(component, substream);
bcae16317   Kuninori Morimoto   ASoC: soc-pcm: re...
600
  		if (ret < 0)
d2aaa8d8b   Kai Vehmanen   ASoC: soc-pcm: fi...
601
  			break;
e7ecfdb79   Kuninori Morimoto   ASoC: soc-pcm: ad...
602

ae2f48492   Kuninori Morimoto   ASoC: soc-compone...
603
  		ret = snd_soc_component_open(component, substream);
bcae16317   Kuninori Morimoto   ASoC: soc-pcm: re...
604
  		if (ret < 0)
d2aaa8d8b   Kai Vehmanen   ASoC: soc-pcm: fi...
605
  			break;
e7ecfdb79   Kuninori Morimoto   ASoC: soc-pcm: ad...
606
  	}
dd03907bf   Kuninori Morimoto   ASoC: soc-pcm: ca...
607

d2aaa8d8b   Kai Vehmanen   ASoC: soc-pcm: fi...
608
  	return ret;
e7ecfdb79   Kuninori Morimoto   ASoC: soc-pcm: ad...
609
  }
51aff91ad   Kuninori Morimoto   ASoC: soc-compone...
610
611
  static int soc_pcm_components_close(struct snd_pcm_substream *substream,
  				    int rollback)
244e29369   Charles Keepax   ASoC: pcm: Tidy u...
612
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
613
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
244e29369   Charles Keepax   ASoC: pcm: Tidy u...
614
  	struct snd_soc_component *component;
e82ebffce   Kuninori Morimoto   ASoC: soc-pcm: do...
615
  	int i, r, ret = 0;
244e29369   Charles Keepax   ASoC: pcm: Tidy u...
616

613fb5005   Kuninori Morimoto   ASoC: soc-core: r...
617
  	for_each_rtd_components(rtd, i, component) {
51aff91ad   Kuninori Morimoto   ASoC: soc-compone...
618
  		r = snd_soc_component_close(component, substream, rollback);
e82ebffce   Kuninori Morimoto   ASoC: soc-pcm: do...
619
620
  		if (r < 0)
  			ret = r; /* use last ret */
51aff91ad   Kuninori Morimoto   ASoC: soc-compone...
621
  		snd_soc_component_module_put_when_close(component, substream, rollback);
244e29369   Charles Keepax   ASoC: pcm: Tidy u...
622
  	}
3672beb8c   Kuninori Morimoto   ASoC: soc-compone...
623
  	return ret;
244e29369   Charles Keepax   ASoC: pcm: Tidy u...
624
  }
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
625
  static int soc_pcm_clean(struct snd_pcm_substream *substream, int rollback)
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
626
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
627
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
628
  	struct snd_soc_component *component;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
629
  	struct snd_soc_dai *dai;
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
630
631
632
  	int i;
  
  	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
633
634
  	if (!rollback)
  		snd_soc_runtime_deactivate(rtd, substream->stream);
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
635

c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
636
  	for_each_rtd_dais(rtd, i, dai)
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
637
  		snd_soc_dai_shutdown(dai, substream, rollback);
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
638

140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
639
  	snd_soc_link_shutdown(substream, rollback);
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
640

140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
641
  	soc_pcm_components_close(substream, rollback);
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
642

140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
643
644
  	if (!rollback)
  		snd_soc_dapm_stream_stop(rtd, substream->stream);
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
645
646
  
  	mutex_unlock(&rtd->card->pcm_mutex);
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
647
  	snd_soc_pcm_component_pm_runtime_put(rtd, substream, rollback);
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
648
649
  
  	for_each_rtd_components(rtd, i, component)
b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
650
  		if (!snd_soc_component_active(component))
62c86d1d5   Kuninori Morimoto   ASoC: soc-pcm: mo...
651
652
653
654
655
656
  			pinctrl_pm_select_sleep_state(component->dev);
  
  	return 0;
  }
  
  /*
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
657
658
659
660
661
662
663
664
665
666
   * Called by ALSA when a PCM substream is closed. Private data can be
   * freed here. The cpu DAI, codec DAI, machine and components are also
   * shutdown.
   */
  static int soc_pcm_close(struct snd_pcm_substream *substream)
  {
  	return soc_pcm_clean(substream, 0);
  }
  
  /*
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
667
668
   * Called by ALSA when a PCM substream is opened, the runtime->hw record is
   * then initialized and any private data can be allocated. This also calls
ef050bece   Charles Keepax   ASoC: Remove plat...
669
   * startup for the cpu DAI, component, machine and codec DAI.
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
670
671
672
   */
  static int soc_pcm_open(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
673
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
674
  	struct snd_pcm_runtime *runtime = substream->runtime;
90be711e2   Kuninori Morimoto   ASoC: use snd_soc...
675
  	struct snd_soc_component *component;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
676
  	struct snd_soc_dai *dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
677
  	const char *codec_dai_name = "multicodec";
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
678
  	const char *cpu_dai_name = "multicpu";
244e29369   Charles Keepax   ASoC: pcm: Tidy u...
679
  	int i, ret = 0;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
680

76c39e867   Kuninori Morimoto   ASoC: soc-core: d...
681
682
  	for_each_rtd_components(rtd, i, component)
  		pinctrl_pm_select_default_state(component->dev);
90be711e2   Kuninori Morimoto   ASoC: use snd_soc...
683

939a5cfb2   Kuninori Morimoto   ASoC: soc-compone...
684
685
  	ret = snd_soc_pcm_component_pm_runtime_get(rtd, substream);
  	if (ret < 0)
cb2fce94c   Kuninori Morimoto   ASoC: soc-pcm: ig...
686
  		goto pm_err;
d6652ef82   Mark Brown   ASoC: Hold runtim...
687

72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
688
  	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
689

5d9fa03e6   Kuninori Morimoto   ASoC: soc-pcm: ti...
690
691
  	ret = soc_pcm_components_open(substream);
  	if (ret < 0)
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
692
  		goto err;
5d9fa03e6   Kuninori Morimoto   ASoC: soc-pcm: ti...
693

7cf3c5b4a   Kuninori Morimoto   ASoC: soc-link: r...
694
  	ret = snd_soc_link_startup(substream);
a5e6c1090   Kuninori Morimoto   ASoC: soc-link: m...
695
  	if (ret < 0)
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
696
  		goto err;
5d9fa03e6   Kuninori Morimoto   ASoC: soc-pcm: ti...
697

ddee627cf   Liam Girdwood   ASoC: core - Sepa...
698
  	/* startup the audio subsystem */
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
699
700
  	for_each_rtd_dais(rtd, i, dai) {
  		ret = snd_soc_dai_startup(dai, substream);
ce820145a   Kuninori Morimoto   ASoC: soc-pcm: re...
701
  		if (ret < 0)
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
702
  			goto err;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
703
704
  
  		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
705
  			dai->tx_mask = 0;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
706
  		else
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
707
  			dai->rx_mask = 0;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
708
  	}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
709
710
711
  	/* Dynamic PCM DAI links compat checks use dynamic capabilities */
  	if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
  		goto dynamic;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
712
  	/* Check that the codec and cpu DAIs are compatible */
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
713
714
715
  	soc_pcm_init_runtime_hw(substream);
  
  	if (rtd->num_codecs == 1)
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
716
  		codec_dai_name = asoc_rtd_to_codec(rtd, 0)->name;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
717

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
718
  	if (rtd->num_cpus == 1)
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
719
  		cpu_dai_name = asoc_rtd_to_cpu(rtd, 0)->name;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
720

62e5f676f   Lars-Peter Clausen   ASoC: Set SNDRV_P...
721
722
  	if (soc_pcm_has_symmetry(substream))
  		runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
723
  	ret = -EINVAL;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
724
  	if (!runtime->hw.rates) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
725
726
  		printk(KERN_ERR "ASoC: %s <-> %s No matching rates
  ",
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
727
  			codec_dai_name, cpu_dai_name);
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
728
  		goto err;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
729
730
  	}
  	if (!runtime->hw.formats) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
731
732
  		printk(KERN_ERR "ASoC: %s <-> %s No matching formats
  ",
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
733
  			codec_dai_name, cpu_dai_name);
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
734
  		goto err;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
735
736
737
  	}
  	if (!runtime->hw.channels_min || !runtime->hw.channels_max ||
  	    runtime->hw.channels_min > runtime->hw.channels_max) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
738
739
  		printk(KERN_ERR "ASoC: %s <-> %s No matching channels
  ",
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
740
  				codec_dai_name, cpu_dai_name);
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
741
  		goto err;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
742
  	}
c8dd1fec4   Benoit Cousson   ASoC: pcm: Refact...
743
  	soc_pcm_apply_msb(substream);
58ba9b254   Mark Brown   ASoC: Allow drive...
744

ddee627cf   Liam Girdwood   ASoC: core - Sepa...
745
  	/* Symmetry only applies if we've already got an active stream. */
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
746
  	for_each_rtd_dais(rtd, i, dai) {
b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
747
  		if (snd_soc_dai_active(dai)) {
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
748
  			ret = soc_pcm_apply_symmetry(substream, dai);
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
749
  			if (ret != 0)
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
750
  				goto err;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
751
  		}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
752
  	}
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
753
754
  	pr_debug("ASoC: %s <-> %s info:
  ",
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
755
  		 codec_dai_name, cpu_dai_name);
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
756
757
758
759
  	pr_debug("ASoC: rate mask 0x%x
  ", runtime->hw.rates);
  	pr_debug("ASoC: min ch %d max ch %d
  ", runtime->hw.channels_min,
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
760
  		 runtime->hw.channels_max);
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
761
762
  	pr_debug("ASoC: min rate %d max rate %d
  ", runtime->hw.rate_min,
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
763
  		 runtime->hw.rate_max);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
764
  dynamic:
24894b764   Lars-Peter Clausen   ASoC: Add helper ...
765
  	snd_soc_runtime_activate(rtd, substream->stream);
8e7875ae3   Kuninori Morimoto   ASoC: soc-pcm: ad...
766
  	ret = 0;
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
767
  err:
72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
768
  	mutex_unlock(&rtd->card->pcm_mutex);
cb2fce94c   Kuninori Morimoto   ASoC: soc-pcm: ig...
769
  pm_err:
140a4532c   Kuninori Morimoto   ASoC: soc-pcm: ad...
770
771
  	if (ret < 0)
  		soc_pcm_clean(substream, 1);
d6652ef82   Mark Brown   ASoC: Hold runtim...
772

ddee627cf   Liam Girdwood   ASoC: core - Sepa...
773
774
  	return ret;
  }
4bf2e385a   Curtis Malainey   ASoC: core: Init ...
775
  static void codec2codec_close_delayed_work(struct snd_soc_pcm_runtime *rtd)
a342031cd   Jerome Brunet   ASoC: create pcm ...
776
777
778
779
780
781
782
783
  {
  	/*
  	 * Currently nothing to do for c2c links
  	 * Since c2c links are internal nodes in the DAPM graph and
  	 * don't interface with the outside world or application layer
  	 * we don't have to do any special handling on close.
  	 */
  }
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
784
  /*
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
785
786
787
788
789
790
   * Called by ALSA when the PCM substream is prepared, can set format, sample
   * rate, etc.  This function is non atomic and can be called multiple times,
   * it can refer to the runtime info.
   */
  static int soc_pcm_prepare(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
791
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
792
  	struct snd_soc_dai *dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
793
  	int i, ret = 0;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
794

72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
795
  	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
796

7cf3c5b4a   Kuninori Morimoto   ASoC: soc-link: r...
797
  	ret = snd_soc_link_prepare(substream);
a5e6c1090   Kuninori Morimoto   ASoC: soc-link: m...
798
  	if (ret < 0)
44c1a75b0   Kuninori Morimoto   ASoC: soc-pcm: ad...
799
  		goto out;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
800

4f39514f3   Kuninori Morimoto   ASoC: soc-compone...
801
802
803
  	ret = snd_soc_pcm_component_prepare(substream);
  	if (ret < 0)
  		goto out;
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
804

d108c7fd0   Kuninori Morimoto   ASoC: soc-dai: ad...
805
806
807
808
809
  	ret = snd_soc_pcm_dai_prepare(substream);
  	if (ret < 0) {
  		dev_err(rtd->dev, "ASoC: DAI prepare error: %d
  ", ret);
  		goto out;
4beb8e109   Kuninori Morimoto   ASoC: soc-dai: ad...
810
  	}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
811
812
  	/* cancel any delayed stream shutdown that is pending */
  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
9bffb1fb7   Misael Lopez Cruz   ASoC: Prevent pop...
813
814
  	    rtd->pop_wait) {
  		rtd->pop_wait = 0;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
815
816
  		cancel_delayed_work(&rtd->delayed_work);
  	}
d9b0951b9   Liam Girdwood   ASoC: dapm: Add p...
817
818
  	snd_soc_dapm_stream_event(rtd, substream->stream,
  			SND_SOC_DAPM_STREAM_START);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
819

c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
820
821
  	for_each_rtd_dais(rtd, i, dai)
  		snd_soc_dai_digital_mute(dai, 0, substream->stream);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
822
823
  
  out:
72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
824
  	mutex_unlock(&rtd->card->pcm_mutex);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
825
826
  	return ret;
  }
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
827
828
829
830
831
832
833
834
835
836
  static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
  				       unsigned int mask)
  {
  	struct snd_interval *interval;
  	int channels = hweight_long(mask);
  
  	interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  	interval->min = channels;
  	interval->max = channels;
  }
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
837
838
839
840
841
842
843
844
  /*
   * Called by ALSA when the hardware params are set by application. This
   * function can also be called multiple times and can allocate buffers
   * (using snd_pcm_lib_* ). It's non-atomic.
   */
  static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
  				struct snd_pcm_hw_params *params)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
845
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
846
  	struct snd_soc_component *component;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
847
  	struct snd_soc_dai *cpu_dai;
0b7990e38   Kuninori Morimoto   ASoC: add for_eac...
848
  	struct snd_soc_dai *codec_dai;
244e29369   Charles Keepax   ASoC: pcm: Tidy u...
849
  	int i, ret = 0;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
850

72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
851
  	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
5cca59516   Shengjiu Wang   ASoC: soc-pcm: ch...
852
853
854
855
  
  	ret = soc_pcm_params_symmetry(substream, params);
  	if (ret)
  		goto out;
7cf3c5b4a   Kuninori Morimoto   ASoC: soc-link: r...
856
  	ret = snd_soc_link_hw_params(substream, params);
a5e6c1090   Kuninori Morimoto   ASoC: soc-link: m...
857
  	if (ret < 0)
de9ad9902   Kuninori Morimoto   ASoC: soc-pcm: ad...
858
  		goto out;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
859

a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
860
  	for_each_rtd_codec_dais(rtd, i, codec_dai) {
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
861
  		struct snd_pcm_hw_params codec_params;
cde79035c   Ricard Wanderlof   ASoC: Handle mult...
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
  		/*
  		 * Skip CODECs which don't support the current stream type,
  		 * the idea being that if a CODEC is not used for the currently
  		 * set up transfer direction, it should not need to be
  		 * configured, especially since the configuration used might
  		 * not even be supported by that CODEC. There may be cases
  		 * however where a CODEC needs to be set up although it is
  		 * actually not being used for the transfer, e.g. if a
  		 * capture-only CODEC is acting as an LRCLK and/or BCLK master
  		 * for the DAI link including a playback-only CODEC.
  		 * If this becomes necessary, we will have to augment the
  		 * machine driver setup with information on how to act, so
  		 * we can do the right thing here.
  		 */
  		if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
  			continue;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
878
879
880
881
  		/* copy params for each codec */
  		codec_params = *params;
  
  		/* fixup params based on TDM slot masks */
570f18b6a   Rander Wang   ASoC:soc-pcm:fix ...
882
883
  		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
  		    codec_dai->tx_mask)
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
884
885
  			soc_pcm_codec_params_fixup(&codec_params,
  						   codec_dai->tx_mask);
570f18b6a   Rander Wang   ASoC:soc-pcm:fix ...
886
887
888
  
  		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
  		    codec_dai->rx_mask)
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
889
890
  			soc_pcm_codec_params_fixup(&codec_params,
  						   codec_dai->rx_mask);
aa6166c2a   Kuninori Morimoto   ASoC: soc-dai: mv...
891
892
  		ret = snd_soc_dai_hw_params(codec_dai, substream,
  					    &codec_params);
93e6958a3   Benoit Cousson   ASoC: pcm: Add so...
893
  		if(ret < 0)
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
894
  			goto codec_err;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
895

2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
896
897
898
899
  		codec_dai->rate = params_rate(&codec_params);
  		codec_dai->channels = params_channels(&codec_params);
  		codec_dai->sample_bits = snd_pcm_format_physical_width(
  						params_format(&codec_params));
078a85f28   Charles Keepax   ASoC: dapm: Only ...
900
901
  
  		snd_soc_dapm_update_dai(substream, &codec_params, codec_dai);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
902
  	}
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
903
  	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
904
905
906
907
908
909
  		/*
  		 * Skip CPUs which don't support the current stream
  		 * type. See soc_pcm_init_runtime_hw() for more details
  		 */
  		if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
  			continue;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
910
911
912
  		ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
  		if (ret < 0)
  			goto interface_err;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
913

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
914
915
916
917
918
  		/* store the parameters for each DAI */
  		cpu_dai->rate = params_rate(params);
  		cpu_dai->channels = params_channels(params);
  		cpu_dai->sample_bits =
  			snd_pcm_format_physical_width(params_format(params));
ca58221d2   Kuninori Morimoto   ASoC: soc-pcm: do...
919

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
920
921
  		snd_soc_dapm_update_dai(substream, params, cpu_dai);
  	}
ca58221d2   Kuninori Morimoto   ASoC: soc-pcm: do...
922

e1bafa828   Kuninori Morimoto   ASoC: soc-compone...
923
924
925
  	ret = snd_soc_pcm_component_hw_params(substream, params, &component);
  	if (ret < 0)
  		goto component_err;
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
926

ddee627cf   Liam Girdwood   ASoC: core - Sepa...
927
  out:
72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
928
  	mutex_unlock(&rtd->card->pcm_mutex);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
929
  	return ret;
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
930
  component_err:
047511198   Kuninori Morimoto   ASoC: soc-compone...
931
  	snd_soc_pcm_component_hw_free(substream, component);
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
932

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
933
  	i = rtd->num_cpus;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
934
935
  
  interface_err:
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
936
  	for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) {
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
937
938
  		if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
  			continue;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
939
940
941
  		snd_soc_dai_hw_free(cpu_dai, substream);
  		cpu_dai->rate = 0;
  	}
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
942
  	i = rtd->num_codecs;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
943
944
  
  codec_err:
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
945
  	for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) {
f47b9ad92   Jerome Brunet   ASoC: skip hw_fre...
946
947
  		if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
  			continue;
846faaed9   Kuninori Morimoto   ASoC: soc-dai: ad...
948
  		snd_soc_dai_hw_free(codec_dai, substream);
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
949
950
  		codec_dai->rate = 0;
  	}
7cf3c5b4a   Kuninori Morimoto   ASoC: soc-link: r...
951
  	snd_soc_link_hw_free(substream);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
952

72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
953
  	mutex_unlock(&rtd->card->pcm_mutex);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
954
955
956
957
958
959
960
961
  	return ret;
  }
  
  /*
   * Frees resources allocated by hw_params, can be called multiple times
   */
  static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
962
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
963
  	struct snd_soc_dai *dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
964
  	int i;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
965

72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
966
  	mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
967

d3383420c   Nicolin Chen   ASoC: soc-pcm: mo...
968
  	/* clear the corresponding DAIs parameters when going to be inactive */
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
969
  	for_each_rtd_dais(rtd, i, dai) {
b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
970
  		int active = snd_soc_dai_stream_active(dai, substream->stream);
d3383420c   Nicolin Chen   ASoC: soc-pcm: mo...
971

b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
972
  		if (snd_soc_dai_active(dai) == 1) {
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
973
974
975
  			dai->rate = 0;
  			dai->channels = 0;
  			dai->sample_bits = 0;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
976
  		}
0f6011fd7   Kuninori Morimoto   ASoC: soc-pcm: me...
977

67ad87775   Kuninori Morimoto   ASoC: soc-pcm: ch...
978
  		if (active == 1)
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
979
  			snd_soc_dai_digital_mute(dai, 1, substream->stream);
a9ee331b5   Kuninori Morimoto   ASoC: soc-pcm: Do...
980
  	}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
981
  	/* free any machine hw params */
7cf3c5b4a   Kuninori Morimoto   ASoC: soc-link: r...
982
  	snd_soc_link_hw_free(substream);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
983

b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
984
  	/* free any component resources */
047511198   Kuninori Morimoto   ASoC: soc-compone...
985
  	snd_soc_pcm_component_hw_free(substream, NULL);
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
986

ddee627cf   Liam Girdwood   ASoC: core - Sepa...
987
  	/* now free hw params for the DAIs  */
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
988
989
  	for_each_rtd_dais(rtd, i, dai) {
  		if (!snd_soc_dai_stream_valid(dai, substream->stream))
f47b9ad92   Jerome Brunet   ASoC: skip hw_fre...
990
  			continue;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
991
  		snd_soc_dai_hw_free(dai, substream);
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
992
  	}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
993

72b745e3a   Peter Ujfalusi   ASoC: core: Move ...
994
  	mutex_unlock(&rtd->card->pcm_mutex);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
995
996
  	return 0;
  }
4378f1fbe   Peter Ujfalusi   ASoC: soc-pcm: Us...
997
998
  static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  {
836367be2   Kuninori Morimoto   ASoC: soc-compone...
999
  	int ret = -EINVAL;
4378f1fbe   Peter Ujfalusi   ASoC: soc-pcm: Us...
1000
1001
1002
1003
1004
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_RESUME:
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
836367be2   Kuninori Morimoto   ASoC: soc-compone...
1005
1006
1007
1008
1009
1010
1011
1012
1013
  		ret = snd_soc_link_trigger(substream, cmd);
  		if (ret < 0)
  			break;
  
  		ret = snd_soc_pcm_component_trigger(substream, cmd);
  		if (ret < 0)
  			break;
  
  		ret = snd_soc_pcm_dai_trigger(substream, cmd);
4378f1fbe   Peter Ujfalusi   ASoC: soc-pcm: Us...
1014
1015
1016
1017
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
836367be2   Kuninori Morimoto   ASoC: soc-compone...
1018
1019
1020
1021
1022
1023
1024
1025
1026
  		ret = snd_soc_pcm_dai_trigger(substream, cmd);
  		if (ret < 0)
  			break;
  
  		ret = snd_soc_pcm_component_trigger(substream, cmd);
  		if (ret < 0)
  			break;
  
  		ret = snd_soc_link_trigger(substream, cmd);
4378f1fbe   Peter Ujfalusi   ASoC: soc-pcm: Us...
1027
  		break;
4378f1fbe   Peter Ujfalusi   ASoC: soc-pcm: Us...
1028
1029
1030
1031
  	}
  
  	return ret;
  }
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
1032
1033
  /*
   * soc level wrapper for pointer callback
ef050bece   Charles Keepax   ASoC: Remove plat...
1034
   * If cpu_dai, codec_dai, component driver has the delay callback, then
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
1035
1036
1037
1038
   * the runtime->delay will be updated accordingly.
   */
  static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1039
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1040
  	struct snd_soc_dai *cpu_dai;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
1041
  	struct snd_soc_dai *codec_dai;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
1042
1043
1044
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	snd_pcm_uframes_t offset = 0;
  	snd_pcm_sframes_t delay = 0;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
1045
  	snd_pcm_sframes_t codec_delay = 0;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1046
  	snd_pcm_sframes_t cpu_delay = 0;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
1047
  	int i;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
1048

9fb4c2bf1   Akshu Agrawal   ASoC: soc-pcm: Us...
1049
1050
  	/* clearing the previous total delay */
  	runtime->delay = 0;
0035e2565   Kuninori Morimoto   ASoC: soc-compone...
1051
  	offset = snd_soc_pcm_component_pointer(substream);
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
1052

9fb4c2bf1   Akshu Agrawal   ASoC: soc-pcm: Us...
1053
1054
  	/* base delay if assigned in pointer callback */
  	delay = runtime->delay;
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
1055

a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
1056
  	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1057
1058
1059
1060
  		cpu_delay = max(cpu_delay,
  				snd_soc_dai_delay(cpu_dai, substream));
  	}
  	delay += cpu_delay;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
1061

a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
1062
  	for_each_rtd_codec_dais(rtd, i, codec_dai) {
1dea80d4b   Kuninori Morimoto   ASoC: soc-dai: ad...
1063
1064
  		codec_delay = max(codec_delay,
  				  snd_soc_dai_delay(codec_dai, substream));
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
1065
1066
  	}
  	delay += codec_delay;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
1067

ddee627cf   Liam Girdwood   ASoC: core - Sepa...
1068
1069
1070
1071
  	runtime->delay = delay;
  
  	return offset;
  }
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1072
1073
1074
1075
1076
  /* connect a FE and BE */
  static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
  		struct snd_soc_pcm_runtime *be, int stream)
  {
  	struct snd_soc_dpcm *dpcm;
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1077
  	unsigned long flags;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1078
1079
  
  	/* only add new dpcms */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1080
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  		if (dpcm->be == be && dpcm->fe == fe)
  			return 0;
  	}
  
  	dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
  	if (!dpcm)
  		return -ENOMEM;
  
  	dpcm->be = be;
  	dpcm->fe = fe;
  	be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
  	dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1093
  	spin_lock_irqsave(&fe->card->dpcm_lock, flags);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1094
1095
  	list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
  	list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1096
  	spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1097

7cc302d23   Jarkko Nikula   ASoC: pcm: Remove...
1098
1099
  	dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1100
1101
  			stream ? "capture" : "playback",  fe->dai_link->name,
  			stream ? "<-" : "->", be->dai_link->name);
154dae87e   Kuninori Morimoto   ASoC: soc-pcm: ad...
1102
  	dpcm_create_debugfs_state(dpcm, stream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  	return 1;
  }
  
  /* reparent a BE onto another FE */
  static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
  			struct snd_soc_pcm_runtime *be, int stream)
  {
  	struct snd_soc_dpcm *dpcm;
  	struct snd_pcm_substream *fe_substream, *be_substream;
  
  	/* reparent if BE is connected to other FEs */
  	if (!be->dpcm[stream].users)
  		return;
  
  	be_substream = snd_soc_dpcm_get_substream(be, stream);
d2e24d646   Kuninori Morimoto   ASoC: add for_eac...
1118
  	for_each_dpcm_fe(be, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1119
1120
  		if (dpcm->fe == fe)
  			continue;
7cc302d23   Jarkko Nikula   ASoC: pcm: Remove...
1121
1122
  		dev_dbg(fe->dev, "reparent %s path %s %s %s
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
  			stream ? "capture" : "playback",
  			dpcm->fe->dai_link->name,
  			stream ? "<-" : "->", dpcm->be->dai_link->name);
  
  		fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
  		be_substream->runtime = fe_substream->runtime;
  		break;
  	}
  }
  
  /* disconnect a BE and FE */
236070253   Liam Girdwood   ASoC: DPCM: make ...
1134
  void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1135
1136
  {
  	struct snd_soc_dpcm *dpcm, *d;
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1137
  	unsigned long flags;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1138

8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1139
  	for_each_dpcm_be_safe(fe, stream, dpcm, d) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1140
1141
  		dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1142
1143
1144
1145
1146
  				stream ? "capture" : "playback",
  				dpcm->be->dai_link->name);
  
  		if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
  			continue;
7cc302d23   Jarkko Nikula   ASoC: pcm: Remove...
1147
1148
  		dev_dbg(fe->dev, "freed DSP %s path %s %s %s
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1149
1150
1151
1152
1153
  			stream ? "capture" : "playback", fe->dai_link->name,
  			stream ? "<-" : "->", dpcm->be->dai_link->name);
  
  		/* BEs still alive need new FE */
  		dpcm_be_reparent(fe, dpcm->be, stream);
154dae87e   Kuninori Morimoto   ASoC: soc-pcm: ad...
1154
  		dpcm_remove_debugfs_state(dpcm);
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1155
  		spin_lock_irqsave(&fe->card->dpcm_lock, flags);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1156
1157
  		list_del(&dpcm->list_be);
  		list_del(&dpcm->list_fe);
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1158
  		spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1159
1160
1161
1162
1163
1164
1165
1166
1167
  		kfree(dpcm);
  	}
  }
  
  /* get BE for DAI widget and stream */
  static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
  		struct snd_soc_dapm_widget *widget, int stream)
  {
  	struct snd_soc_pcm_runtime *be;
93597fae5   Kuninori Morimoto   ASoC: soc-pcm: us...
1168
  	struct snd_soc_dapm_widget *w;
7afecb307   Kuninori Morimoto   ASoC: convert for...
1169
  	struct snd_soc_dai *dai;
1a497983a   Mengdong Lin   ASoC: Change the ...
1170
  	int i;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1171

3c1464658   Liam Girdwood   ASoC: pcm: improv...
1172
1173
  	dev_dbg(card->dev, "ASoC: find BE for widget %s
  ", widget->name);
93597fae5   Kuninori Morimoto   ASoC: soc-pcm: us...
1174
  	for_each_card_rtds(card, be) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1175

93597fae5   Kuninori Morimoto   ASoC: soc-pcm: us...
1176
1177
  		if (!be->dai_link->no_pcm)
  			continue;
35ea0655a   Liam Girdwood   ASoC: dpcm: Fix d...
1178

c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1179
  		for_each_rtd_dais(be, i, dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1180
  			w = snd_soc_dai_get_widget(dai, stream);
3c1464658   Liam Girdwood   ASoC: pcm: improv...
1181

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1182
1183
1184
  			dev_dbg(card->dev, "ASoC: try BE : %s
  ",
  				w ? w->name : "(not set)");
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
1185

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1186
1187
1188
  			if (w == widget)
  				return be;
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1189
  	}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1190
1191
  	return NULL;
  }
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1192
1193
1194
  static int widget_in_list(struct snd_soc_dapm_widget_list *list,
  		struct snd_soc_dapm_widget *widget)
  {
09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1195
  	struct snd_soc_dapm_widget *w;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1196
  	int i;
09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1197
1198
  	for_each_dapm_widgets(list, i, w)
  		if (widget == w)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1199
  			return 1;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1200
1201
1202
  
  	return 0;
  }
5fdd022c2   Piotr Stankiewicz   ASoC: dpcm: play ...
1203
1204
1205
1206
1207
  static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
  		enum snd_soc_dapm_direction dir)
  {
  	struct snd_soc_card *card = widget->dapm->card;
  	struct snd_soc_pcm_runtime *rtd;
c2cd82160   Kuninori Morimoto   ASoC: soc-pcm: us...
1208
  	int stream;
5fdd022c2   Piotr Stankiewicz   ASoC: dpcm: play ...
1209

c2cd82160   Kuninori Morimoto   ASoC: soc-pcm: us...
1210
1211
1212
1213
1214
  	/* adjust dir to stream */
  	if (dir == SND_SOC_DAPM_DIR_OUT)
  		stream = SNDRV_PCM_STREAM_PLAYBACK;
  	else
  		stream = SNDRV_PCM_STREAM_CAPTURE;
5fdd022c2   Piotr Stankiewicz   ASoC: dpcm: play ...
1215

027a48387   Kuninori Morimoto   ASoC: soc-pcm: us...
1216
1217
1218
  	rtd = dpcm_get_be(card, widget, stream);
  	if (rtd)
  		return true;
5fdd022c2   Piotr Stankiewicz   ASoC: dpcm: play ...
1219
1220
1221
  
  	return false;
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
1222
  int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
1ce43acff   Lars-Peter Clausen   ASoC: dapm: Simpl...
1223
  	int stream, struct snd_soc_dapm_widget_list **list)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1224
  {
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
1225
  	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(fe, 0);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1226
  	int paths;
6e1276a5e   Bard Liao   ASoC: Return erro...
1227
1228
1229
1230
1231
1232
  	if (fe->num_cpus > 1) {
  		dev_err(fe->dev,
  			"%s doesn't support Multi CPU yet
  ", __func__);
  		return -EINVAL;
  	}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1233
  	/* get number of valid DAI paths and their widgets */
6742064ae   Piotr Stankiewicz   ASoC: dapm: suppo...
1234
  	paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list,
5fdd022c2   Piotr Stankiewicz   ASoC: dpcm: play ...
1235
  			dpcm_end_walk_at_be);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1236

103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1237
1238
  	dev_dbg(fe->dev, "ASoC: found %d audio %s paths
  ", paths,
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1239
  			stream ? "capture" : "playback");
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1240
1241
  	return paths;
  }
52645e332   Kuninori Morimoto   ASoC: soc-pcm: mo...
1242
1243
1244
1245
  void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
  {
  	snd_soc_dapm_dai_free_widgets(list);
  }
8cce6569e   Guennadi Liakhovetski   ASoC: (cosmetic) ...
1246
1247
  static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
  			      struct snd_soc_dapm_widget_list *list)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1248
  {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1249
  	struct snd_soc_dapm_widget *widget;
7afecb307   Kuninori Morimoto   ASoC: convert for...
1250
  	struct snd_soc_dai *dai;
8cce6569e   Guennadi Liakhovetski   ASoC: (cosmetic) ...
1251
  	unsigned int i;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1252
1253
  	/* is there a valid DAI widget for this BE */
  	for_each_rtd_dais(dpcm->be, i, dai) {
8cce6569e   Guennadi Liakhovetski   ASoC: (cosmetic) ...
1254
1255
1256
  		widget = snd_soc_dai_get_widget(dai, stream);
  
  		/*
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1257
  		 * The BE is pruned only if none of the dai
8cce6569e   Guennadi Liakhovetski   ASoC: (cosmetic) ...
1258
1259
1260
1261
1262
  		 * widgets are in the active list.
  		 */
  		if (widget && widget_in_list(list, widget))
  			return true;
  	}
8cce6569e   Guennadi Liakhovetski   ASoC: (cosmetic) ...
1263
1264
1265
1266
1267
1268
1269
  	return false;
  }
  
  static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
  			    struct snd_soc_dapm_widget_list **list_)
  {
  	struct snd_soc_dpcm *dpcm;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1270
1271
1272
  	int prune = 0;
  
  	/* Destroy any old FE <--> BE connections */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1273
  	for_each_dpcm_be(fe, stream, dpcm) {
8cce6569e   Guennadi Liakhovetski   ASoC: (cosmetic) ...
1274
  		if (dpcm_be_is_active(dpcm, stream, *list_))
bed646dc3   Kuninori Morimoto   ASoC: soc-pcm: fi...
1275
  			continue;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1276

103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1277
1278
  		dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1279
1280
1281
1282
1283
1284
  			stream ? "capture" : "playback",
  			dpcm->be->dai_link->name, fe->dai_link->name);
  		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
  		dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
  		prune++;
  	}
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1285
1286
  	dev_dbg(fe->dev, "ASoC: found %d old BE paths for pruning
  ", prune);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1287
1288
1289
1290
1291
1292
1293
1294
1295
  	return prune;
  }
  
  static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
  	struct snd_soc_dapm_widget_list **list_)
  {
  	struct snd_soc_card *card = fe->card;
  	struct snd_soc_dapm_widget_list *list = *list_;
  	struct snd_soc_pcm_runtime *be;
09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1296
  	struct snd_soc_dapm_widget *widget;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1297
1298
1299
  	int i, new = 0, err;
  
  	/* Create any new FE <--> BE connections */
09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1300
  	for_each_dapm_widgets(list, i, widget) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1301

09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1302
  		switch (widget->id) {
4616274d3   Mark Brown   ASoC: dapm: Treat...
1303
  		case snd_soc_dapm_dai_in:
c5b8540dc   Koro Chen   ASoC: dpcm: Add c...
1304
1305
1306
  			if (stream != SNDRV_PCM_STREAM_PLAYBACK)
  				continue;
  			break;
4616274d3   Mark Brown   ASoC: dapm: Treat...
1307
  		case snd_soc_dapm_dai_out:
c5b8540dc   Koro Chen   ASoC: dpcm: Add c...
1308
1309
  			if (stream != SNDRV_PCM_STREAM_CAPTURE)
  				continue;
4616274d3   Mark Brown   ASoC: dapm: Treat...
1310
1311
  			break;
  		default:
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1312
  			continue;
4616274d3   Mark Brown   ASoC: dapm: Treat...
1313
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1314
1315
  
  		/* is there a valid BE rtd for this widget */
09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1316
  		be = dpcm_get_be(card, widget, stream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1317
  		if (!be) {
2df8d9fca   Shengjiu Wang   MLK-11429-11: ASo...
1318
1319
  			dev_dbg(fe->dev, "ASoC: no BE found for %s
  ",
09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1320
  					widget->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1321
1322
  			continue;
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1323
  		/* don't connect if FE is not running */
236070253   Liam Girdwood   ASoC: DPCM: make ...
1324
  		if (!fe->dpcm[stream].runtime && !fe->fe_compr)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1325
1326
1327
1328
1329
  			continue;
  
  		/* newly connected FE and BE */
  		err = dpcm_be_connect(fe, be, stream);
  		if (err < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1330
1331
  			dev_err(fe->dev, "ASoC: can't connect %s
  ",
09e88f8a5   Kuninori Morimoto   ASoC: soc-pcm: ad...
1332
  				widget->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1333
1334
1335
1336
1337
1338
1339
1340
  			break;
  		} else if (err == 0) /* already connected */
  			continue;
  
  		/* new */
  		be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
  		new++;
  	}
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1341
1342
  	dev_dbg(fe->dev, "ASoC: found %d new BE paths
  ", new);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1343
1344
1345
1346
1347
1348
1349
  	return new;
  }
  
  /*
   * Find the corresponding BE DAIs that source or sink audio to this
   * FE substream.
   */
236070253   Liam Girdwood   ASoC: DPCM: make ...
1350
  int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1351
1352
1353
1354
1355
1356
1357
  	int stream, struct snd_soc_dapm_widget_list **list, int new)
  {
  	if (new)
  		return dpcm_add_paths(fe, stream, list);
  	else
  		return dpcm_prune_paths(fe, stream, list);
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
1358
  void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1359
1360
  {
  	struct snd_soc_dpcm *dpcm;
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1361
  	unsigned long flags;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1362

a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1363
  	spin_lock_irqsave(&fe->card->dpcm_lock, flags);
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1364
  	for_each_dpcm_be(fe, stream, dpcm)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1365
1366
  		dpcm->be->dpcm[stream].runtime_update =
  						SND_SOC_DPCM_UPDATE_NO;
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
1367
  	spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1368
1369
1370
1371
1372
1373
1374
1375
  }
  
  static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
  	int stream)
  {
  	struct snd_soc_dpcm *dpcm;
  
  	/* disable any enabled and non active backends */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1376
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1377
1378
1379
1380
1381
1382
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		if (be->dpcm[stream].users == 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1383
1384
  			dev_err(be->dev, "ASoC: no users %s at close - state %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
  				stream ? "capture" : "playback",
  				be->dpcm[stream].state);
  
  		if (--be->dpcm[stream].users != 0)
  			continue;
  
  		if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
  			continue;
  
  		soc_pcm_close(be_substream);
  		be_substream->runtime = NULL;
  		be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
  	}
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
1399
  int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1400
1401
1402
1403
1404
  {
  	struct snd_soc_dpcm *dpcm;
  	int err, count = 0;
  
  	/* only startup BE DAIs that are either sinks or sources to this FE DAI */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1405
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1406
1407
1408
1409
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
2062b4c5d   Russell King - ARM Linux   ASoC: dpcm: impro...
1410
1411
1412
1413
1414
1415
  		if (!be_substream) {
  			dev_err(be->dev, "ASoC: no backend %s stream
  ",
  				stream ? "capture" : "playback");
  			continue;
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1416
1417
1418
1419
1420
1421
  		/* is this op for this BE ? */
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
  
  		/* first time the dpcm is open ? */
  		if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1422
1423
  			dev_err(be->dev, "ASoC: too many users %s at open %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1424
1425
1426
1427
1428
1429
1430
1431
1432
  				stream ? "capture" : "playback",
  				be->dpcm[stream].state);
  
  		if (be->dpcm[stream].users++ != 0)
  			continue;
  
  		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
  			continue;
2062b4c5d   Russell King - ARM Linux   ASoC: dpcm: impro...
1433
1434
1435
  		dev_dbg(be->dev, "ASoC: open %s BE %s
  ",
  			stream ? "capture" : "playback", be->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1436
1437
1438
1439
  
  		be_substream->runtime = be->dpcm[stream].runtime;
  		err = soc_pcm_open(be_substream);
  		if (err < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1440
1441
  			dev_err(be->dev, "ASoC: BE open failed %d
  ", err);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1442
1443
  			be->dpcm[stream].users--;
  			if (be->dpcm[stream].users < 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1444
1445
  				dev_err(be->dev, "ASoC: no users %s at unwind %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
  					stream ? "capture" : "playback",
  					be->dpcm[stream].state);
  
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
  			goto unwind;
  		}
  
  		be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
  		count++;
  	}
  
  	return count;
  
  unwind:
  	/* disable any enabled and non active backends */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1461
  	for_each_dpcm_be_rollback(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1462
1463
1464
1465
1466
1467
1468
1469
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
  
  		if (be->dpcm[stream].users == 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1470
1471
  			dev_err(be->dev, "ASoC: no users %s at close %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  				stream ? "capture" : "playback",
  				be->dpcm[stream].state);
  
  		if (--be->dpcm[stream].users != 0)
  			continue;
  
  		if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
  			continue;
  
  		soc_pcm_close(be_substream);
  		be_substream->runtime = NULL;
  		be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
  	}
  
  	return err;
  }
08ae9b456   Lars-Peter Clausen   ASoC: dpcm: Add h...
1488
  static void dpcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1489
  				 struct snd_soc_pcm_stream *stream)
08ae9b456   Lars-Peter Clausen   ASoC: dpcm: Add h...
1490
1491
  {
  	runtime->hw.rate_min = stream->rate_min;
e33ffbd9c   Charles Keepax   ASoC: dpcm: Prope...
1492
  	runtime->hw.rate_max = min_not_zero(stream->rate_max, UINT_MAX);
08ae9b456   Lars-Peter Clausen   ASoC: dpcm: Add h...
1493
1494
  	runtime->hw.channels_min = stream->channels_min;
  	runtime->hw.channels_max = stream->channels_max;
002220a90   Lars-Peter Clausen   ASoC: dpcm: Allow...
1495
  	if (runtime->hw.formats)
435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1496
  		runtime->hw.formats &= stream->formats;
002220a90   Lars-Peter Clausen   ASoC: dpcm: Allow...
1497
  	else
435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1498
  		runtime->hw.formats = stream->formats;
08ae9b456   Lars-Peter Clausen   ASoC: dpcm: Add h...
1499
1500
  	runtime->hw.rates = stream->rates;
  }
435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1501
1502
  static void dpcm_runtime_merge_format(struct snd_pcm_substream *substream,
  				      u64 *formats)
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1503
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1504
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1505
  	struct snd_soc_dpcm *dpcm;
7afecb307   Kuninori Morimoto   ASoC: convert for...
1506
  	struct snd_soc_dai *dai;
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1507
1508
1509
  	int stream = substream->stream;
  
  	if (!fe->dai_link->dpcm_merged_format)
435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1510
  		return;
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1511
1512
1513
1514
1515
  
  	/*
  	 * It returns merged BE codec format
  	 * if FE want to use it (= dpcm_merged_format)
  	 */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1516
  	for_each_dpcm_be(fe, stream, dpcm) {
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1517
  		struct snd_soc_pcm_runtime *be = dpcm->be;
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1518
1519
  		struct snd_soc_pcm_stream *codec_stream;
  		int i;
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
1520
  		for_each_rtd_codec_dais(be, i, dai) {
4febced15   Jerome Brunet   ASoC: dpcm: don't...
1521
1522
1523
1524
  			/*
  			 * Skip CODECs which don't support the current stream
  			 * type. See soc_pcm_init_runtime_hw() for more details
  			 */
7afecb307   Kuninori Morimoto   ASoC: convert for...
1525
  			if (!snd_soc_dai_stream_valid(dai, stream))
4febced15   Jerome Brunet   ASoC: dpcm: don't...
1526
  				continue;
acf253c11   Kuninori Morimoto   ASoC: soc-pcm: ad...
1527
  			codec_stream = snd_soc_dai_get_pcm_stream(dai, stream);
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1528

435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1529
  			*formats &= codec_stream->formats;
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1530
1531
  		}
  	}
b073ed4e2   Kuninori Morimoto   ASoC: soc-pcm: DP...
1532
  }
435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1533
1534
1535
  static void dpcm_runtime_merge_chan(struct snd_pcm_substream *substream,
  				    unsigned int *channels_min,
  				    unsigned int *channels_max)
f4c277b81   Jiada Wang   ASoC: soc-pcm: DP...
1536
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1537
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
f4c277b81   Jiada Wang   ASoC: soc-pcm: DP...
1538
1539
1540
1541
1542
  	struct snd_soc_dpcm *dpcm;
  	int stream = substream->stream;
  
  	if (!fe->dai_link->dpcm_merged_chan)
  		return;
f4c277b81   Jiada Wang   ASoC: soc-pcm: DP...
1543
1544
1545
1546
  	/*
  	 * It returns merged BE codec channel;
  	 * if FE want to use it (= dpcm_merged_chan)
  	 */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1547
  	for_each_dpcm_be(fe, stream, dpcm) {
f4c277b81   Jiada Wang   ASoC: soc-pcm: DP...
1548
  		struct snd_soc_pcm_runtime *be = dpcm->be;
f4c277b81   Jiada Wang   ASoC: soc-pcm: DP...
1549
  		struct snd_soc_pcm_stream *codec_stream;
4f2bd18b1   Jerome Brunet   ASoC: dpcm: exten...
1550
  		struct snd_soc_pcm_stream *cpu_stream;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1551
1552
  		struct snd_soc_dai *dai;
  		int i;
4f2bd18b1   Jerome Brunet   ASoC: dpcm: exten...
1553

a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
1554
  		for_each_rtd_cpu_dais(be, i, dai) {
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
1555
1556
1557
1558
1559
1560
  			/*
  			 * Skip CPUs which don't support the current stream
  			 * type. See soc_pcm_init_runtime_hw() for more details
  			 */
  			if (!snd_soc_dai_stream_valid(dai, stream))
  				continue;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1561
  			cpu_stream = snd_soc_dai_get_pcm_stream(dai, stream);
4f2bd18b1   Jerome Brunet   ASoC: dpcm: exten...
1562

19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1563
1564
1565
1566
1567
  			*channels_min = max(*channels_min,
  					    cpu_stream->channels_min);
  			*channels_max = min(*channels_max,
  					    cpu_stream->channels_max);
  		}
4f2bd18b1   Jerome Brunet   ASoC: dpcm: exten...
1568
1569
1570
1571
1572
1573
  
  		/*
  		 * chan min/max cannot be enforced if there are multiple CODEC
  		 * DAIs connected to a single CPU DAI, use CPU DAI's directly
  		 */
  		if (be->num_codecs == 1) {
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
1574
  			codec_stream = snd_soc_dai_get_pcm_stream(asoc_rtd_to_codec(be, 0), stream);
f4c277b81   Jiada Wang   ASoC: soc-pcm: DP...
1575
1576
1577
1578
1579
1580
1581
1582
  
  			*channels_min = max(*channels_min,
  					    codec_stream->channels_min);
  			*channels_max = min(*channels_max,
  					    codec_stream->channels_max);
  		}
  	}
  }
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1583
1584
1585
1586
1587
  static void dpcm_runtime_merge_rate(struct snd_pcm_substream *substream,
  				    unsigned int *rates,
  				    unsigned int *rate_min,
  				    unsigned int *rate_max)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1588
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  	struct snd_soc_dpcm *dpcm;
  	int stream = substream->stream;
  
  	if (!fe->dai_link->dpcm_merged_rate)
  		return;
  
  	/*
  	 * It returns merged BE codec channel;
  	 * if FE want to use it (= dpcm_merged_chan)
  	 */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1599
  	for_each_dpcm_be(fe, stream, dpcm) {
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1600
  		struct snd_soc_pcm_runtime *be = dpcm->be;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1601
  		struct snd_soc_pcm_stream *pcm;
7afecb307   Kuninori Morimoto   ASoC: convert for...
1602
  		struct snd_soc_dai *dai;
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1603
  		int i;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1604
  		for_each_rtd_dais(be, i, dai) {
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1605
  			/*
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1606
  			 * Skip DAIs which don't support the current stream
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1607
1608
  			 * type. See soc_pcm_init_runtime_hw() for more details
  			 */
7afecb307   Kuninori Morimoto   ASoC: convert for...
1609
  			if (!snd_soc_dai_stream_valid(dai, stream))
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1610
  				continue;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1611
  			pcm = snd_soc_dai_get_pcm_stream(dai, stream);
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1612

c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1613
1614
1615
  			*rate_min = max(*rate_min, pcm->rate_min);
  			*rate_max = min_not_zero(*rate_max, pcm->rate_max);
  			*rates = snd_pcm_rate_mask_intersect(*rates, pcm->rates);
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1616
1617
1618
  		}
  	}
  }
45c0a188c   Mark Brown   ASoC: pcm: Static...
1619
  static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1620
1621
  {
  	struct snd_pcm_runtime *runtime = substream->runtime;
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1622
  	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1623
  	struct snd_soc_dai *cpu_dai;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1624
  	int i;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1625

a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
1626
  	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
0e9cf4c45   Bard Liao   ASoC: pcm: check ...
1627
1628
1629
1630
1631
1632
  		/*
  		 * Skip CPUs which don't support the current stream
  		 * type. See soc_pcm_init_runtime_hw() for more details
  		 */
  		if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
  			continue;
0c9ba720f   Kuninori Morimoto   ASoC: soc-pcm: us...
1633
1634
1635
  		dpcm_init_runtime_hw(runtime,
  			snd_soc_dai_get_pcm_stream(cpu_dai,
  						   substream->stream));
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1636
  	}
f4c277b81   Jiada Wang   ASoC: soc-pcm: DP...
1637

435ffb76f   Jerome Brunet   ASoC: dpcm: rewor...
1638
1639
1640
  	dpcm_runtime_merge_format(substream, &runtime->hw.formats);
  	dpcm_runtime_merge_chan(substream, &runtime->hw.channels_min,
  				&runtime->hw.channels_max);
baacd8d10   Jerome Brunet   ASoC: dpcm: add r...
1641
1642
  	dpcm_runtime_merge_rate(substream, &runtime->hw.rates,
  				&runtime->hw.rate_min, &runtime->hw.rate_max);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1643
  }
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
  static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
  
  /* Set FE's runtime_update state; the state is protected via PCM stream lock
   * for avoiding the race with trigger callback.
   * If the state is unset and a trigger is pending while the previous operation,
   * process the pending trigger action here.
   */
  static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
  				     int stream, enum snd_soc_dpcm_update state)
  {
  	struct snd_pcm_substream *substream =
  		snd_soc_dpcm_get_substream(fe, stream);
  
  	snd_pcm_stream_lock_irq(substream);
  	if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
  		dpcm_fe_dai_do_trigger(substream,
  				       fe->dpcm[stream].trigger_pending - 1);
  		fe->dpcm[stream].trigger_pending = 0;
  	}
  	fe->dpcm[stream].runtime_update = state;
  	snd_pcm_stream_unlock_irq(substream);
  }
906c7d690   PC Liao   ASoC: dpcm: Apply...
1666
1667
1668
1669
  static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream,
  			       int stream)
  {
  	struct snd_soc_dpcm *dpcm;
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1670
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1671
  	struct snd_soc_dai *fe_cpu_dai;
906c7d690   PC Liao   ASoC: dpcm: Apply...
1672
  	int err;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1673
  	int i;
906c7d690   PC Liao   ASoC: dpcm: Apply...
1674
1675
1676
1677
  
  	/* apply symmetry for FE */
  	if (soc_pcm_has_symmetry(fe_substream))
  		fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
1678
  	for_each_rtd_cpu_dais (fe, i, fe_cpu_dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1679
  		/* Symmetry only applies if we've got an active stream. */
b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
1680
  		if (snd_soc_dai_active(fe_cpu_dai)) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
1681
1682
1683
1684
  			err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai);
  			if (err < 0)
  				return err;
  		}
906c7d690   PC Liao   ASoC: dpcm: Apply...
1685
1686
1687
  	}
  
  	/* apply symmetry for BE */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1688
  	for_each_dpcm_be(fe, stream, dpcm) {
906c7d690   PC Liao   ASoC: dpcm: Apply...
1689
1690
1691
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
6246f283d   Jerome Brunet   ASoC: dpcm: skip ...
1692
  		struct snd_soc_pcm_runtime *rtd;
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1693
  		struct snd_soc_dai *dai;
906c7d690   PC Liao   ASoC: dpcm: Apply...
1694
  		int i;
6246f283d   Jerome Brunet   ASoC: dpcm: skip ...
1695
1696
1697
  		/* A backend may not have the requested substream */
  		if (!be_substream)
  			continue;
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1698
  		rtd = asoc_substream_to_rtd(be_substream);
f11766143   Jeeja KP   ASoC: dpcm: Don't...
1699
1700
  		if (rtd->dai_link->be_hw_params_fixup)
  			continue;
906c7d690   PC Liao   ASoC: dpcm: Apply...
1701
1702
1703
1704
  		if (soc_pcm_has_symmetry(be_substream))
  			be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
  
  		/* Symmetry only applies if we've got an active stream. */
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1705
  		for_each_rtd_dais(rtd, i, dai) {
b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
1706
  			if (snd_soc_dai_active(dai)) {
c840f7698   Kuninori Morimoto   ASoC: soc-pcm: Me...
1707
  				err = soc_pcm_apply_symmetry(fe_substream, dai);
906c7d690   PC Liao   ASoC: dpcm: Apply...
1708
1709
1710
1711
1712
1713
1714
1715
  				if (err < 0)
  					return err;
  			}
  		}
  	}
  
  	return 0;
  }
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1716
1717
  static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1718
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1719
1720
  	struct snd_pcm_runtime *runtime = fe_substream->runtime;
  	int stream = fe_substream->stream, ret = 0;
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1721
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1722

25c2f5156   Kuninori Morimoto   ASoC: soc-pcm: us...
1723
  	ret = dpcm_be_dai_startup(fe, stream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1724
  	if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1725
1726
  		dev_err(fe->dev,"ASoC: failed to start some BEs %d
  ", ret);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1727
1728
  		goto be_err;
  	}
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1729
1730
  	dev_dbg(fe->dev, "ASoC: open FE %s
  ", fe->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1731
1732
1733
1734
  
  	/* start the DAI frontend */
  	ret = soc_pcm_open(fe_substream);
  	if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1735
1736
  		dev_err(fe->dev,"ASoC: failed to start FE %d
  ", ret);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1737
1738
1739
1740
1741
1742
1743
  		goto unwind;
  	}
  
  	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
  
  	dpcm_set_fe_runtime(fe_substream);
  	snd_pcm_limit_hw_rates(runtime);
906c7d690   PC Liao   ASoC: dpcm: Apply...
1744
  	ret = dpcm_apply_symmetry(fe_substream, stream);
8a01fbf0a   Kuninori Morimoto   ASoC: soc-pcm: ti...
1745
  	if (ret < 0)
906c7d690   PC Liao   ASoC: dpcm: Apply...
1746
1747
1748
  		dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d
  ",
  			ret);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1749
1750
  
  unwind:
8a01fbf0a   Kuninori Morimoto   ASoC: soc-pcm: ti...
1751
1752
  	if (ret < 0)
  		dpcm_be_dai_startup_unwind(fe, stream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1753
  be_err:
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1754
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1755
1756
  	return ret;
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
1757
  int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1758
1759
1760
1761
  {
  	struct snd_soc_dpcm *dpcm;
  
  	/* only shutdown BEs that are either sinks or sources to this FE DAI */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1762
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		/* is this op for this BE ? */
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
  
  		if (be->dpcm[stream].users == 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1773
1774
  			dev_err(be->dev, "ASoC: no users %s at close - state %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1775
1776
1777
1778
1779
1780
1781
  				stream ? "capture" : "playback",
  				be->dpcm[stream].state);
  
  		if (--be->dpcm[stream].users != 0)
  			continue;
  
  		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
9c0ac70ad   Kai Chieh Chuang   ASoC: dpcm: fix B...
1782
1783
1784
1785
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)) {
  			soc_pcm_hw_free(be_substream);
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1786

103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1787
1788
  		dev_dbg(be->dev, "ASoC: close BE %s
  ",
94d215cc6   彭东林   ASoC: dpcm: print...
1789
  			be->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
  
  		soc_pcm_close(be_substream);
  		be_substream->runtime = NULL;
  
  		be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
  	}
  	return 0;
  }
  
  static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1801
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1802
  	int stream = substream->stream;
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1803
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1804
1805
  
  	/* shutdown the BEs */
25c2f5156   Kuninori Morimoto   ASoC: soc-pcm: us...
1806
  	dpcm_be_dai_shutdown(fe, stream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1807

103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1808
1809
  	dev_dbg(fe->dev, "ASoC: close FE %s
  ", fe->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1810
1811
1812
1813
1814
  
  	/* now shutdown the frontend */
  	soc_pcm_close(substream);
  
  	/* run the stream event for each BE */
1c5312308   Kuninori Morimoto   ASoC: soc-pcm/soc...
1815
  	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1816
1817
  
  	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1818
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1819
1820
  	return 0;
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
1821
  int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1822
1823
1824
1825
1826
  {
  	struct snd_soc_dpcm *dpcm;
  
  	/* only hw_params backends that are either sinks or sources
  	 * to this frontend DAI */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1827
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		/* is this op for this BE ? */
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
  
  		/* only free hw when no longer used - check all FEs */
  		if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
  				continue;
36fba62cc   Qiao Zhou   ASoC: soc-pcm: do...
1840
1841
1842
  		/* do not free hw if this BE is used by other FE */
  		if (be->dpcm[stream].users > 1)
  			continue;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1843
1844
1845
  		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
08b27848d   Patrick Lai   ASoC: pcm: allow ...
1846
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
5e82d2be6   Vinod Koul   ASoC: dpcm: fix t...
1847
1848
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1849
  			continue;
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1850
1851
  		dev_dbg(be->dev, "ASoC: hw_free BE %s
  ",
94d215cc6   彭东林   ASoC: dpcm: print...
1852
  			be->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1853
1854
1855
1856
1857
1858
1859
1860
  
  		soc_pcm_hw_free(be_substream);
  
  		be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
  	}
  
  	return 0;
  }
45c0a188c   Mark Brown   ASoC: pcm: Static...
1861
  static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1862
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1863
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1864
1865
1866
  	int err, stream = substream->stream;
  
  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1867
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1868

103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1869
1870
  	dev_dbg(fe->dev, "ASoC: hw_free FE %s
  ", fe->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1871
1872
1873
1874
  
  	/* call hw_free on the frontend */
  	err = soc_pcm_hw_free(substream);
  	if (err < 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1875
1876
  		dev_err(fe->dev,"ASoC: hw_free FE %s failed
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1877
1878
1879
1880
1881
1882
1883
  			fe->dai_link->name);
  
  	/* only hw_params backends that are either sinks or sources
  	 * to this frontend DAI */
  	err = dpcm_be_dai_hw_free(fe, stream);
  
  	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1884
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1885
1886
1887
1888
  
  	mutex_unlock(&fe->card->mutex);
  	return 0;
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
1889
  int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1890
1891
1892
  {
  	struct snd_soc_dpcm *dpcm;
  	int ret;
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1893
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1894
1895
1896
1897
1898
1899
1900
1901
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		/* is this op for this BE ? */
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1902
1903
1904
1905
1906
  		/* copy params for each dpcm */
  		memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
  				sizeof(struct snd_pcm_hw_params));
  
  		/* perform any hw_params fixups */
0cbbf8a03   Kuninori Morimoto   ASoC: soc-link: a...
1907
1908
1909
  		ret = snd_soc_link_be_hw_params_fixup(be, &dpcm->hw_params);
  		if (ret < 0)
  			goto unwind;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1910

ae061d2a8   Libin Yang   ASoC: pcm: save f...
1911
1912
1913
  		/* copy the fixed-up hw params for BE dai */
  		memcpy(&be->dpcm[stream].hw_params, &dpcm->hw_params,
  		       sizeof(struct snd_pcm_hw_params));
b0639bd24   Kuninori Morimoto   ASoC: soc-pcm: co...
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
  		/* only allow hw_params() if no connected FEs are running */
  		if (!snd_soc_dpcm_can_be_params(fe, be, stream))
  			continue;
  
  		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
  			continue;
  
  		dev_dbg(be->dev, "ASoC: hw_params BE %s
  ",
94d215cc6   彭东林   ASoC: dpcm: print...
1925
  			be->dai_link->name);
b0639bd24   Kuninori Morimoto   ASoC: soc-pcm: co...
1926

01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1927
1928
1929
  		ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
  		if (ret < 0) {
  			dev_err(dpcm->be->dev,
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1930
1931
  				"ASoC: hw_params BE failed %d
  ", ret);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1932
1933
1934
1935
1936
1937
1938
1939
1940
  			goto unwind;
  		}
  
  		be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
  	}
  	return 0;
  
  unwind:
  	/* disable any enabled and non active backends */
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
1941
  	for_each_dpcm_be_rollback(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
  
  		/* only allow hw_free() if no connected FEs are running */
  		if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
  			continue;
  
  		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
  		   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
  		   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
  		   (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
  			continue;
  
  		soc_pcm_hw_free(be_substream);
  	}
  
  	return ret;
  }
45c0a188c   Mark Brown   ASoC: pcm: Static...
1964
1965
  static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
  				 struct snd_pcm_hw_params *params)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1966
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
1967
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1968
1969
1970
  	int ret, stream = substream->stream;
  
  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1971
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1972

25c2f5156   Kuninori Morimoto   ASoC: soc-pcm: us...
1973
  	memcpy(&fe->dpcm[stream].hw_params, params,
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1974
  			sizeof(struct snd_pcm_hw_params));
25c2f5156   Kuninori Morimoto   ASoC: soc-pcm: us...
1975
  	ret = dpcm_be_dai_hw_params(fe, stream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1976
  	if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1977
1978
  		dev_err(fe->dev,"ASoC: hw_params BE failed %d
  ", ret);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1979
1980
  		goto out;
  	}
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1981
1982
  	dev_dbg(fe->dev, "ASoC: hw_params FE %s rate %d chan %x fmt %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1983
1984
1985
1986
1987
1988
  			fe->dai_link->name, params_rate(params),
  			params_channels(params), params_format(params));
  
  	/* call hw_params on the frontend */
  	ret = soc_pcm_hw_params(substream, params);
  	if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
1989
1990
  		dev_err(fe->dev,"ASoC: hw_params FE failed %d
  ", ret);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1991
1992
1993
1994
1995
  		dpcm_be_dai_hw_free(fe, stream);
  	 } else
  		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
  
  out:
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
1996
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
1997
1998
1999
2000
2001
2002
2003
2004
  	mutex_unlock(&fe->card->mutex);
  	return ret;
  }
  
  static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
  		struct snd_pcm_substream *substream, int cmd)
  {
  	int ret;
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2005
2006
  	dev_dbg(dpcm->be->dev, "ASoC: trigger BE %s cmd %d
  ",
94d215cc6   彭东林   ASoC: dpcm: print...
2007
  			dpcm->be->dai_link->name, cmd);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2008
2009
2010
  
  	ret = soc_pcm_trigger(substream, cmd);
  	if (ret < 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2011
2012
  		dev_err(dpcm->be->dev,"ASoC: trigger BE failed %d
  ", ret);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2013
2014
2015
  
  	return ret;
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
2016
  int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
45c0a188c   Mark Brown   ASoC: pcm: Static...
2017
  			       int cmd)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2018
2019
2020
  {
  	struct snd_soc_dpcm *dpcm;
  	int ret = 0;
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
2021
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		/* is this op for this BE ? */
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
  
  		switch (cmd) {
  		case SNDRV_PCM_TRIGGER_START:
  			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
21fca8bdb   이경택   ASoC: dpcm: allow...
2034
2035
  			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
  			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
  				continue;
  
  			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
  			if (ret)
  				return ret;
  
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
  			break;
  		case SNDRV_PCM_TRIGGER_RESUME:
  			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
  				continue;
  
  			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
  			if (ret)
  				return ret;
  
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
  			break;
  		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
  				continue;
  
  			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
  			if (ret)
  				return ret;
  
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
  			break;
  		case SNDRV_PCM_TRIGGER_STOP:
21fca8bdb   이경택   ASoC: dpcm: allow...
2065
2066
  			if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) &&
  			    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
  				continue;
  
  			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
  				continue;
  
  			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
  			if (ret)
  				return ret;
  
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
  			break;
  		case SNDRV_PCM_TRIGGER_SUSPEND:
868a6ca84   Nicolin Chen   ASoC: pcm: Fix in...
2079
  			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
  				continue;
  
  			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
  				continue;
  
  			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
  			if (ret)
  				return ret;
  
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
  			break;
  		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  			if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
  				continue;
  
  			if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
  				continue;
  
  			ret = dpcm_do_trigger(dpcm, be_substream, cmd);
  			if (ret)
  				return ret;
  
  			be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
  			break;
  		}
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2110
2111
2112
  static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
  				  int cmd, bool fe_first)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
2113
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
  	int ret;
  
  	/* call trigger on the frontend before the backend. */
  	if (fe_first) {
  		dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d
  ",
  			fe->dai_link->name, cmd);
  
  		ret = soc_pcm_trigger(substream, cmd);
  		if (ret < 0)
  			return ret;
  
  		ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
  		return ret;
  	}
  
  	/* call trigger on the frontend after the backend. */
  	ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
  	if (ret < 0)
  		return ret;
  
  	dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d
  ",
  		fe->dai_link->name, cmd);
  
  	ret = soc_pcm_trigger(substream, cmd);
  
  	return ret;
  }
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
2143
  static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2144
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
2145
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2146
2147
  	int stream = substream->stream;
  	int ret = 0;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2148
2149
2150
2151
2152
2153
  	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
  
  	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
  
  	switch (trigger) {
  	case SND_SOC_DPCM_TRIGGER_PRE:
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2154
2155
2156
2157
  		switch (cmd) {
  		case SNDRV_PCM_TRIGGER_START:
  		case SNDRV_PCM_TRIGGER_RESUME:
  		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
332a2c3b6   Cezary Rojewski   ASoC: pcm: DRAIN ...
2158
  		case SNDRV_PCM_TRIGGER_DRAIN:
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
  			ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
  			break;
  		case SNDRV_PCM_TRIGGER_STOP:
  		case SNDRV_PCM_TRIGGER_SUSPEND:
  		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  			ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
  			break;
  		default:
  			ret = -EINVAL;
  			break;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2169
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2170
2171
  		break;
  	case SND_SOC_DPCM_TRIGGER_POST:
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2172
2173
2174
2175
  		switch (cmd) {
  		case SNDRV_PCM_TRIGGER_START:
  		case SNDRV_PCM_TRIGGER_RESUME:
  		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
332a2c3b6   Cezary Rojewski   ASoC: pcm: DRAIN ...
2176
  		case SNDRV_PCM_TRIGGER_DRAIN:
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
  			ret = dpcm_dai_trigger_fe_be(substream, cmd, false);
  			break;
  		case SNDRV_PCM_TRIGGER_STOP:
  		case SNDRV_PCM_TRIGGER_SUSPEND:
  		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  			ret = dpcm_dai_trigger_fe_be(substream, cmd, true);
  			break;
  		default:
  			ret = -EINVAL;
  			break;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2187
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2188
  		break;
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2189
2190
  	case SND_SOC_DPCM_TRIGGER_BESPOKE:
  		/* bespoke trigger() - handles both FE and BEs */
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2191
2192
  		dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd %d
  ",
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2193
  				fe->dai_link->name, cmd);
30819358a   Kuninori Morimoto   ASoC: soc-dai: ad...
2194
  		ret = snd_soc_pcm_dai_bespoke_trigger(substream, cmd);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2195
  		break;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2196
  	default:
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2197
2198
  		dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s
  ", cmd,
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2199
2200
2201
2202
  				fe->dai_link->name);
  		ret = -EINVAL;
  		goto out;
  	}
acbf27746   Ranjani Sridharan   ASoC: pcm: update...
2203
2204
2205
2206
2207
2208
  	if (ret < 0) {
  		dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d
  ",
  			cmd, ret);
  		goto out;
  	}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2209
2210
2211
2212
2213
2214
2215
2216
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_RESUME:
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
  		break;
  	case SNDRV_PCM_TRIGGER_STOP:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2217
2218
  		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
  		break;
9f169b9f5   Patrick Lai   ASoC: dpcm: Avoid...
2219
2220
2221
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  		fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
  		break;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2222
2223
2224
2225
2226
2227
  	}
  
  out:
  	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
  	return ret;
  }
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
2228
2229
  static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
2230
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
  	int stream = substream->stream;
  
  	/* if FE's runtime_update is already set, we're in race;
  	 * process this trigger later at exit
  	 */
  	if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
  		fe->dpcm[stream].trigger_pending = cmd + 1;
  		return 0; /* delayed, assuming it's successful */
  	}
  
  	/* we're alone, let's trigger */
  	return dpcm_fe_dai_do_trigger(substream, cmd);
  }
236070253   Liam Girdwood   ASoC: DPCM: make ...
2244
  int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2245
2246
2247
  {
  	struct snd_soc_dpcm *dpcm;
  	int ret = 0;
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
2248
  	for_each_dpcm_be(fe, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
  
  		struct snd_soc_pcm_runtime *be = dpcm->be;
  		struct snd_pcm_substream *be_substream =
  			snd_soc_dpcm_get_substream(be, stream);
  
  		/* is this op for this BE ? */
  		if (!snd_soc_dpcm_be_can_update(fe, be, stream))
  			continue;
  
  		if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
95f444dc9   Koro Chen   ASoC: dpcm: Make ...
2259
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
5087a8f17   Libin Yang   ASoC: soc-pcm: BE...
2260
2261
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
  		    (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2262
  			continue;
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2263
2264
  		dev_dbg(be->dev, "ASoC: prepare BE %s
  ",
94d215cc6   彭东林   ASoC: dpcm: print...
2265
  			be->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2266
2267
2268
  
  		ret = soc_pcm_prepare(be_substream);
  		if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2269
2270
  			dev_err(be->dev, "ASoC: backend prepare failed %d
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2271
2272
2273
2274
2275
2276
2277
2278
  				ret);
  			break;
  		}
  
  		be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
  	}
  	return ret;
  }
45c0a188c   Mark Brown   ASoC: pcm: Static...
2279
  static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2280
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
2281
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2282
2283
2284
  	int stream = substream->stream, ret = 0;
  
  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2285
2286
  	dev_dbg(fe->dev, "ASoC: prepare FE %s
  ", fe->dai_link->name);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2287

ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
2288
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2289
2290
2291
  
  	/* there is no point preparing this FE if there are no BEs */
  	if (list_empty(&fe->dpcm[stream].be_clients)) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2292
2293
  		dev_err(fe->dev, "ASoC: no backend DAIs enabled for %s
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2294
2295
2296
2297
  				fe->dai_link->name);
  		ret = -EINVAL;
  		goto out;
  	}
25c2f5156   Kuninori Morimoto   ASoC: soc-pcm: us...
2298
  	ret = dpcm_be_dai_prepare(fe, stream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2299
2300
2301
2302
2303
2304
  	if (ret < 0)
  		goto out;
  
  	/* call prepare on the frontend */
  	ret = soc_pcm_prepare(substream);
  	if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2305
2306
  		dev_err(fe->dev,"ASoC: prepare FE %s failed
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2307
2308
2309
2310
2311
2312
2313
2314
2315
  			fe->dai_link->name);
  		goto out;
  	}
  
  	/* run the stream event for each BE */
  	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
  	fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
  
  out:
ea9d0d771   Takashi Iwai   ASoC: dpcm: Fix r...
2316
  	dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2317
2318
2319
2320
  	mutex_unlock(&fe->card->mutex);
  
  	return ret;
  }
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2321
2322
  static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
  {
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2323
2324
2325
  	struct snd_pcm_substream *substream =
  		snd_soc_dpcm_get_substream(fe, stream);
  	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2326
  	int err;
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2327
2328
  	dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s
  ",
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2329
  			stream ? "capture" : "playback", fe->dai_link->name);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2330
2331
  	if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
  		/* call bespoke trigger - FE takes care of all BE triggers */
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2332
2333
  		dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd stop
  ",
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2334
  				fe->dai_link->name);
30819358a   Kuninori Morimoto   ASoC: soc-dai: ad...
2335
  		err = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2336
  		if (err < 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2337
2338
  			dev_err(fe->dev,"ASoC: trigger FE failed %d
  ", err);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2339
  	} else {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2340
2341
  		dev_dbg(fe->dev, "ASoC: trigger FE %s cmd stop
  ",
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2342
2343
2344
2345
  			fe->dai_link->name);
  
  		err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
  		if (err < 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2346
2347
  			dev_err(fe->dev,"ASoC: trigger FE failed %d
  ", err);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2348
  	}
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2349
2350
2351
  
  	err = dpcm_be_dai_hw_free(fe, stream);
  	if (err < 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2352
2353
  		dev_err(fe->dev,"ASoC: hw_free FE failed %d
  ", err);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2354
2355
2356
  
  	err = dpcm_be_dai_shutdown(fe, stream);
  	if (err < 0)
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2357
2358
  		dev_err(fe->dev,"ASoC: shutdown FE failed %d
  ", err);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2359
2360
2361
2362
2363
2364
2365
2366
2367
  
  	/* run the stream event for each BE */
  	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
  
  	return 0;
  }
  
  static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
  {
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2368
2369
  	struct snd_pcm_substream *substream =
  		snd_soc_dpcm_get_substream(fe, stream);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2370
  	struct snd_soc_dpcm *dpcm;
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2371
  	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2372
  	int ret;
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2373
  	unsigned long flags;
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2374

103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2375
2376
  	dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s
  ",
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2377
2378
2379
2380
2381
2382
2383
2384
2385
  			stream ? "capture" : "playback", fe->dai_link->name);
  
  	/* Only start the BE if the FE is ready */
  	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
  		fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
  		return -EINVAL;
  
  	/* startup must always be called for new BEs */
  	ret = dpcm_be_dai_startup(fe, stream);
fffc0ca29   Dan Carpenter   ASoC: pcm: delete...
2386
  	if (ret < 0)
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2387
  		goto disconnect;
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2388
2389
2390
2391
  
  	/* keep going if FE state is > open */
  	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
  		return 0;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2392

618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2393
  	ret = dpcm_be_dai_hw_params(fe, stream);
fffc0ca29   Dan Carpenter   ASoC: pcm: delete...
2394
  	if (ret < 0)
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2395
  		goto close;
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2396
2397
2398
2399
2400
2401
2402
  
  	/* keep going if FE state is > hw_params */
  	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
  		return 0;
  
  
  	ret = dpcm_be_dai_prepare(fe, stream);
fffc0ca29   Dan Carpenter   ASoC: pcm: delete...
2403
  	if (ret < 0)
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2404
  		goto hw_free;
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2405
2406
2407
2408
2409
2410
2411
2412
  
  	/* run the stream event for each BE */
  	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
  
  	/* keep going if FE state is > prepare */
  	if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
  		fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
  		return 0;
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2413
2414
  	if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
  		/* call trigger on the frontend - FE takes care of all BE triggers */
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2415
2416
  		dev_dbg(fe->dev, "ASoC: bespoke trigger FE %s cmd start
  ",
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2417
  				fe->dai_link->name);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2418

30819358a   Kuninori Morimoto   ASoC: soc-dai: ad...
2419
  		ret = snd_soc_pcm_dai_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2420
  		if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2421
2422
  			dev_err(fe->dev,"ASoC: bespoke trigger FE failed %d
  ", ret);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2423
2424
2425
  			goto hw_free;
  		}
  	} else {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2426
2427
  		dev_dbg(fe->dev, "ASoC: trigger FE %s cmd start
  ",
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2428
2429
2430
2431
2432
  			fe->dai_link->name);
  
  		ret = dpcm_be_dai_trigger(fe, stream,
  					SNDRV_PCM_TRIGGER_START);
  		if (ret < 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2433
2434
  			dev_err(fe->dev,"ASoC: trigger FE failed %d
  ", ret);
07bf84aaf   Liam Girdwood   ASoC: dpcm: Add b...
2435
2436
  			goto hw_free;
  		}
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2437
2438
2439
2440
2441
2442
2443
2444
2445
  	}
  
  	return 0;
  
  hw_free:
  	dpcm_be_dai_hw_free(fe, stream);
  close:
  	dpcm_be_dai_shutdown(fe, stream);
  disconnect:
68f8043ed   朱灿灿   Subject: [PATCH v...
2446
  	/* disconnect any closed BEs */
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2447
  	spin_lock_irqsave(&fe->card->dpcm_lock, flags);
8d6258a4d   Kuninori Morimoto   ASoC: add for_eac...
2448
  	for_each_dpcm_be(fe, stream, dpcm) {
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2449
  		struct snd_soc_pcm_runtime *be = dpcm->be;
68f8043ed   朱灿灿   Subject: [PATCH v...
2450
2451
  		if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
  			dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2452
  	}
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2453
  	spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2454
2455
2456
  
  	return ret;
  }
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2457
  static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2458
  {
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2459
  	struct snd_soc_dapm_widget_list *list;
7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2460
  	int stream;
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2461
  	int count, paths;
580dff363   Kuninori Morimoto   ASoC: soc-pcm: me...
2462
  	int ret;
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2463

96bf62f01   Pierre-Louis Bossart   ASoC: soc-pcm: fi...
2464
2465
  	if (!fe->dai_link->dynamic)
  		return 0;
6e1276a5e   Bard Liao   ASoC: Return erro...
2466
2467
2468
2469
2470
2471
  	if (fe->num_cpus > 1) {
  		dev_err(fe->dev,
  			"%s doesn't support Multi CPU yet
  ", __func__);
  		return -EINVAL;
  	}
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2472
  	/* only check active links */
b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
2473
  	if (!snd_soc_dai_active(asoc_rtd_to_cpu(fe, 0)))
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2474
  		return 0;
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2475

de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2476
2477
2478
2479
  	/* DAPM sync will call this to update DSP paths */
  	dev_dbg(fe->dev, "ASoC: DPCM %s runtime update for FE %s
  ",
  		new ? "new" : "old", fe->dai_link->name);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2480

7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2481
  	for_each_pcm_streams(stream) {
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2482

7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2483
  		/* skip if FE doesn't have playback/capture capability */
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
2484
2485
  		if (!snd_soc_dai_stream_valid(asoc_rtd_to_cpu(fe, 0),   stream) ||
  		    !snd_soc_dai_stream_valid(asoc_rtd_to_codec(fe, 0), stream))
7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2486
  			continue;
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2487

7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2488
  		/* skip if FE isn't currently playing/capturing */
b3dea624b   Kuninori Morimoto   ASoC: use snd_soc...
2489
2490
  		if (!snd_soc_dai_stream_active(asoc_rtd_to_cpu(fe, 0), stream) ||
  		    !snd_soc_dai_stream_active(asoc_rtd_to_codec(fe, 0), stream))
7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2491
  			continue;
075207d24   Qiao Zhou   ASoC: soc-pcm: sk...
2492

7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2493
2494
2495
2496
2497
2498
2499
2500
2501
  		paths = dpcm_path_get(fe, stream, &list);
  		if (paths < 0) {
  			dev_warn(fe->dev, "ASoC: %s no valid %s path
  ",
  				 fe->dai_link->name,
  				 stream == SNDRV_PCM_STREAM_PLAYBACK ?
  				 "playback" : "capture");
  			return paths;
  		}
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2502

7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2503
2504
2505
  		/* update any playback/capture paths */
  		count = dpcm_process_paths(fe, stream, &list, new);
  		if (count) {
580dff363   Kuninori Morimoto   ASoC: soc-pcm: me...
2506
  			dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2507
  			if (new)
580dff363   Kuninori Morimoto   ASoC: soc-pcm: me...
2508
  				ret = dpcm_run_update_startup(fe, stream);
7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2509
  			else
580dff363   Kuninori Morimoto   ASoC: soc-pcm: me...
2510
2511
2512
2513
2514
  				ret = dpcm_run_update_shutdown(fe, stream);
  			if (ret < 0)
  				dev_err(fe->dev, "ASoC: failed to shutdown some BEs
  ");
  			dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2515

7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2516
2517
2518
  			dpcm_clear_pending_state(fe, stream);
  			dpcm_be_disconnect(fe, stream);
  		}
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2519

7083f877e   Kuninori Morimoto   ASoC: soc-pcm: us...
2520
  		dpcm_path_put(&list);
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2521
  	}
618dae11f   Liam Girdwood   ASoC: dpcm: Add r...
2522
2523
  	return 0;
  }
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2524
2525
2526
2527
  
  /* Called by DAPM mixer/mux changes to update audio routing between PCMs and
   * any DAI links.
   */
f17a14789   Guennadi Liakhovetski   ASoC: export DPCM...
2528
  int snd_soc_dpcm_runtime_update(struct snd_soc_card *card)
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2529
2530
2531
2532
2533
2534
  {
  	struct snd_soc_pcm_runtime *fe;
  	int ret = 0;
  
  	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
  	/* shutdown all old paths first */
bcb1fd1fc   Kuninori Morimoto   ASoC: add for_eac...
2535
  	for_each_card_rtds(card, fe) {
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2536
2537
2538
2539
2540
2541
  		ret = soc_dpcm_fe_runtime_update(fe, 0);
  		if (ret)
  			goto out;
  	}
  
  	/* bring new paths up */
bcb1fd1fc   Kuninori Morimoto   ASoC: add for_eac...
2542
  	for_each_card_rtds(card, fe) {
de15d7ff5   Jerome Brunet   ASoC: dpcm: impro...
2543
2544
2545
2546
2547
2548
2549
2550
2551
  		ret = soc_dpcm_fe_runtime_update(fe, 1);
  		if (ret)
  			goto out;
  	}
  
  out:
  	mutex_unlock(&card->mutex);
  	return ret;
  }
f17a14789   Guennadi Liakhovetski   ASoC: export DPCM...
2552
  EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2553

265694b67   Kuninori Morimoto   ASoC: soc-pcm: ad...
2554
  static void dpcm_fe_dai_cleanup(struct snd_pcm_substream *fe_substream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2555
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
2556
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2557
  	struct snd_soc_dpcm *dpcm;
265694b67   Kuninori Morimoto   ASoC: soc-pcm: ad...
2558
  	int stream = fe_substream->stream;
30fca26f8   Kuninori Morimoto   ASoC: soc-pcm: mo...
2559
2560
2561
2562
2563
2564
2565
2566
  
  	/* mark FE's links ready to prune */
  	for_each_dpcm_be(fe, stream, dpcm)
  		dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
  
  	dpcm_be_disconnect(fe, stream);
  
  	fe->dpcm[stream].runtime = NULL;
265694b67   Kuninori Morimoto   ASoC: soc-pcm: ad...
2567
2568
2569
2570
  }
  
  static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
2571
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
265694b67   Kuninori Morimoto   ASoC: soc-pcm: ad...
2572
2573
2574
2575
2576
2577
  	int ret;
  
  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
  	ret = dpcm_fe_dai_shutdown(fe_substream);
  
  	dpcm_fe_dai_cleanup(fe_substream);
30fca26f8   Kuninori Morimoto   ASoC: soc-pcm: mo...
2578
2579
2580
  	mutex_unlock(&fe->card->mutex);
  	return ret;
  }
45c0a188c   Mark Brown   ASoC: pcm: Static...
2581
  static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2582
  {
0ceef681e   Kuninori Morimoto   ASoC: soc-xxx: ad...
2583
  	struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(fe_substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2584
2585
2586
2587
2588
2589
  	struct snd_soc_dapm_widget_list *list;
  	int ret;
  	int stream = fe_substream->stream;
  
  	mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
  	fe->dpcm[stream].runtime = fe_substream->runtime;
8f70e515a   Qiao Zhou   ASoC: soc-pcm: fi...
2590
2591
  	ret = dpcm_path_get(fe, stream, &list);
  	if (ret < 0) {
cae06eb92   Kuninori Morimoto   ASoC: soc-pcm: us...
2592
  		goto open_end;
8f70e515a   Qiao Zhou   ASoC: soc-pcm: fi...
2593
  	} else if (ret == 0) {
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2594
2595
  		dev_dbg(fe->dev, "ASoC: %s no valid %s route
  ",
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2596
  			fe->dai_link->name, stream ? "capture" : "playback");
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2597
2598
2599
2600
2601
2602
  	}
  
  	/* calculate valid and active FE <-> BE dpcms */
  	dpcm_process_paths(fe, stream, &list, 1);
  
  	ret = dpcm_fe_dai_startup(fe_substream);
265694b67   Kuninori Morimoto   ASoC: soc-pcm: ad...
2603
2604
  	if (ret < 0)
  		dpcm_fe_dai_cleanup(fe_substream);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2605
2606
2607
  
  	dpcm_clear_pending_state(fe, stream);
  	dpcm_path_put(&list);
cae06eb92   Kuninori Morimoto   ASoC: soc-pcm: us...
2608
  open_end:
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2609
2610
2611
  	mutex_unlock(&fe->card->mutex);
  	return ret;
  }
ad2896fda   Shengjiu Wang   ASoC: fsl: imx-pc...
2612
2613
2614
  static int soc_rtdcom_ack(struct snd_pcm_substream *substream)
  {
  	struct snd_soc_pcm_runtime *rtd = substream->private_data;
ad2896fda   Shengjiu Wang   ASoC: fsl: imx-pc...
2615
  	struct snd_soc_component *component;
e5d7b6012   Dong Aisheng   LF-1011-14 ASoC: ...
2616
  	int i;
ad2896fda   Shengjiu Wang   ASoC: fsl: imx-pc...
2617

e5d7b6012   Dong Aisheng   LF-1011-14 ASoC: ...
2618
  	for_each_rtd_components(rtd, i, component) {
ad2896fda   Shengjiu Wang   ASoC: fsl: imx-pc...
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
  		if (!component->driver ||
  			!component->driver->ack)
  			continue;
  
  		/* FIXME. it returns 1st ask now */
  		return component->driver->ack(component, substream);
  	}
  
  	return -EINVAL;
  }
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2629
2630
2631
  /* create a new pcm */
  int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
  {
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
2632
  	struct snd_soc_dai *codec_dai;
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
2633
  	struct snd_soc_dai *cpu_dai;
2b544dd7b   Kuninori Morimoto   ASoC: soc-core: a...
2634
  	struct snd_soc_component *component;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2635
2636
2637
  	struct snd_pcm *pcm;
  	char new_name[64];
  	int ret = 0, playback = 0, capture = 0;
b73287f0b   Pierre-Louis Bossart   ASoC: soc-pcm: dp...
2638
  	int stream;
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
2639
  	int i;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2640

b73287f0b   Pierre-Louis Bossart   ASoC: soc-pcm: dp...
2641
2642
2643
2644
2645
2646
  	if (rtd->dai_link->dynamic && rtd->num_cpus > 1) {
  		dev_err(rtd->dev,
  			"DPCM doesn't support Multi CPU for Front-Ends yet
  ");
  		return -EINVAL;
  	}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2647
  	if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
b73287f0b   Pierre-Louis Bossart   ASoC: soc-pcm: dp...
2648
2649
  		if (rtd->dai_link->dpcm_playback) {
  			stream = SNDRV_PCM_STREAM_PLAYBACK;
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
2650
2651
2652
2653
  			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
  				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
  					playback = 1;
  					break;
b73287f0b   Pierre-Louis Bossart   ASoC: soc-pcm: dp...
2654
  				}
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
2655
2656
2657
2658
2659
2660
2661
2662
2663
  			}
  
  			if (!playback) {
  				dev_err(rtd->card->dev,
  					"No CPU DAIs support playback for stream %s
  ",
  					rtd->dai_link->stream_name);
  				return -EINVAL;
  			}
b73287f0b   Pierre-Louis Bossart   ASoC: soc-pcm: dp...
2664
2665
2666
  		}
  		if (rtd->dai_link->dpcm_capture) {
  			stream = SNDRV_PCM_STREAM_CAPTURE;
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
2667
2668
2669
2670
  			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
  				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
  					capture = 1;
  					break;
b73287f0b   Pierre-Louis Bossart   ASoC: soc-pcm: dp...
2671
  				}
4f8721542   Pierre-Louis Bossart   ASoC: core: use l...
2672
2673
2674
2675
2676
2677
2678
2679
2680
  			}
  
  			if (!capture) {
  				dev_err(rtd->card->dev,
  					"No CPU DAIs support capture for stream %s
  ",
  					rtd->dai_link->stream_name);
  				return -EINVAL;
  			}
9b5db0593   Stephan Gerhold   ASoC: soc-pcm: dp...
2681
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2682
  	} else {
a342031cd   Jerome Brunet   ASoC: create pcm ...
2683
  		/* Adapt stream for codec2codec links */
a4877a6fb   Stephan Gerhold   ASoC: soc-pcm: fi...
2684
2685
2686
2687
  		int cpu_capture = rtd->dai_link->params ?
  			SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
  		int cpu_playback = rtd->dai_link->params ?
  			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
a342031cd   Jerome Brunet   ASoC: create pcm ...
2688

a4be4187b   Kuninori Morimoto   ASoC: soc: use fo...
2689
  		for_each_rtd_codec_dais(rtd, i, codec_dai) {
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
2690
  			if (rtd->num_cpus == 1) {
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
2691
  				cpu_dai = asoc_rtd_to_cpu(rtd, 0);
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
2692
  			} else if (rtd->num_cpus == rtd->num_codecs) {
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
2693
  				cpu_dai = asoc_rtd_to_cpu(rtd, i);
19bdcc7ae   Shreyas NC   ASoC: Add multipl...
2694
2695
2696
2697
2698
2699
  			} else {
  				dev_err(rtd->card->dev,
  					"N cpus to M codecs link is not supported yet
  ");
  				return -EINVAL;
  			}
467fece8f   Kuninori Morimoto   ASoC: soc-dai: mo...
2700
  			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
a4877a6fb   Stephan Gerhold   ASoC: soc-pcm: fi...
2701
  			    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
2702
  				playback = 1;
467fece8f   Kuninori Morimoto   ASoC: soc-dai: mo...
2703
  			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
a4877a6fb   Stephan Gerhold   ASoC: soc-pcm: fi...
2704
  			    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
2705
2706
  				capture = 1;
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2707
  	}
d6bead020   Fabio Estevam   ASoC: soc-pcm: Al...
2708
2709
2710
2711
2712
2713
2714
2715
2716
  	if (rtd->dai_link->playback_only) {
  		playback = 1;
  		capture = 0;
  	}
  
  	if (rtd->dai_link->capture_only) {
  		playback = 0;
  		capture = 1;
  	}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2717
  	/* create the PCM */
a342031cd   Jerome Brunet   ASoC: create pcm ...
2718
2719
2720
2721
2722
2723
2724
  	if (rtd->dai_link->params) {
  		snprintf(new_name, sizeof(new_name), "codec2codec(%s)",
  			 rtd->dai_link->stream_name);
  
  		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
  					   playback, capture, &pcm);
  	} else if (rtd->dai_link->no_pcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
  		snprintf(new_name, sizeof(new_name), "(%s)",
  			rtd->dai_link->stream_name);
  
  		ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
  				playback, capture, &pcm);
  	} else {
  		if (rtd->dai_link->dynamic)
  			snprintf(new_name, sizeof(new_name), "%s (*)",
  				rtd->dai_link->stream_name);
  		else
  			snprintf(new_name, sizeof(new_name), "%s %s-%d",
2e5894d73   Benoit Cousson   ASoC: pcm: Add su...
2736
2737
  				rtd->dai_link->stream_name,
  				(rtd->num_codecs > 1) ?
c2233a266   Kuninori Morimoto   ASoC: soc: use as...
2738
  				"multicodec" : asoc_rtd_to_codec(rtd, 0)->name, num);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2739
2740
2741
2742
  
  		ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
  			capture, &pcm);
  	}
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2743
  	if (ret < 0) {
799827a42   Pierre-Louis Bossart   ASoC: soc-pcm: im...
2744
2745
2746
  		dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d
  ",
  			new_name, rtd->dai_link->name, ret);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2747
2748
  		return ret;
  	}
103d84a3c   Liam Girdwood   ASoC: pcm: Standa...
2749
2750
  	dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s
  ",num, new_name);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2751
2752
  
  	/* DAPM dai link stream work */
a342031cd   Jerome Brunet   ASoC: create pcm ...
2753
  	if (rtd->dai_link->params)
4bf2e385a   Curtis Malainey   ASoC: core: Init ...
2754
  		rtd->close_delayed_work_func = codec2codec_close_delayed_work;
a342031cd   Jerome Brunet   ASoC: create pcm ...
2755
  	else
83f94a2e2   Kuninori Morimoto   ASoC: soc-core: a...
2756
  		rtd->close_delayed_work_func = snd_soc_close_delayed_work;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2757

48c7699fb   Vinod Koul   ASoC: core: allow...
2758
  	pcm->nonatomic = rtd->dai_link->nonatomic;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2759
2760
  	rtd->pcm = pcm;
  	pcm->private_data = rtd;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2761

a342031cd   Jerome Brunet   ASoC: create pcm ...
2762
  	if (rtd->dai_link->no_pcm || rtd->dai_link->params) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
  		if (playback)
  			pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
  		if (capture)
  			pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
  		goto out;
  	}
  
  	/* ASoC PCM operations */
  	if (rtd->dai_link->dynamic) {
  		rtd->ops.open		= dpcm_fe_dai_open;
  		rtd->ops.hw_params	= dpcm_fe_dai_hw_params;
  		rtd->ops.prepare	= dpcm_fe_dai_prepare;
  		rtd->ops.trigger	= dpcm_fe_dai_trigger;
  		rtd->ops.hw_free	= dpcm_fe_dai_hw_free;
  		rtd->ops.close		= dpcm_fe_dai_close;
  		rtd->ops.pointer	= soc_pcm_pointer;
  	} else {
  		rtd->ops.open		= soc_pcm_open;
  		rtd->ops.hw_params	= soc_pcm_hw_params;
  		rtd->ops.prepare	= soc_pcm_prepare;
  		rtd->ops.trigger	= soc_pcm_trigger;
  		rtd->ops.hw_free	= soc_pcm_hw_free;
  		rtd->ops.close		= soc_pcm_close;
  		rtd->ops.pointer	= soc_pcm_pointer;
  	}
613fb5005   Kuninori Morimoto   ASoC: soc-core: r...
2788
  	for_each_rtd_components(rtd, i, component) {
2b544dd7b   Kuninori Morimoto   ASoC: soc-core: a...
2789
  		const struct snd_soc_component_driver *drv = component->driver;
b8135864d   Kuninori Morimoto   ASoC: snd_soc_com...
2790

ad2896fda   Shengjiu Wang   ASoC: fsl: imx-pc...
2791
2792
  		if (drv->ack)
  			rtd->ops.ack            = soc_rtdcom_ack;
3b1c952c9   Takashi Iwai   ASoC: pcm: Make i...
2793
2794
  		if (drv->ioctl)
  			rtd->ops.ioctl		= snd_soc_pcm_component_ioctl;
1e5ddb6ba   Takashi Iwai   ASoC: component: ...
2795
2796
  		if (drv->sync_stop)
  			rtd->ops.sync_stop	= snd_soc_pcm_component_sync_stop;
e9067bb50   Kuninori Morimoto   ASoC: soc-compone...
2797
  		if (drv->copy_user)
82d81f5cc   Kuninori Morimoto   ASoC: soc-compone...
2798
  			rtd->ops.copy_user	= snd_soc_pcm_component_copy_user;
e9067bb50   Kuninori Morimoto   ASoC: soc-compone...
2799
  		if (drv->page)
9c712e4f5   Kuninori Morimoto   ASoC: soc-compone...
2800
  			rtd->ops.page		= snd_soc_pcm_component_page;
e9067bb50   Kuninori Morimoto   ASoC: soc-compone...
2801
  		if (drv->mmap)
205875e1a   Kuninori Morimoto   ASoC: soc-compone...
2802
  			rtd->ops.mmap		= snd_soc_pcm_component_mmap;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2803
2804
2805
  	}
  
  	if (playback)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2806
  		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2807
2808
  
  	if (capture)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2809
  		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2810

b2b2afbb4   Kuninori Morimoto   ASoC: soc-compone...
2811
  	ret = snd_soc_pcm_component_new(rtd);
7484291e9   Kuninori Morimoto   ASoC: soc-compone...
2812
  	if (ret < 0) {
799827a42   Pierre-Louis Bossart   ASoC: soc-pcm: im...
2813
2814
2815
  		dev_err(rtd->dev, "ASoC: pcm %s constructor failed for dailink %s: %d
  ",
  			new_name, rtd->dai_link->name, ret);
7484291e9   Kuninori Morimoto   ASoC: soc-compone...
2816
  		return ret;
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2817
  	}
c641e5b20   Johan Hovold   ASoC: fix pcm-cre...
2818

3d21ef0b4   Takashi Iwai   ALSA: pcm: Suspen...
2819
  	pcm->no_device_suspend = true;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2820
  out:
1d5cd5254   Pierre-Louis Bossart   ASoC: soc-pcm/com...
2821
2822
2823
2824
  	dev_dbg(rtd->card->dev, "%s <-> %s mapping ok
  ",
  		(rtd->num_codecs > 1) ? "multicodec" : asoc_rtd_to_codec(rtd, 0)->name,
  		(rtd->num_cpus > 1)   ? "multicpu"   : asoc_rtd_to_cpu(rtd, 0)->name);
ddee627cf   Liam Girdwood   ASoC: core - Sepa...
2825
2826
  	return ret;
  }
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
  
  /* is the current PCM operation for this FE ? */
  int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
  {
  	if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
  		return 1;
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
  
  /* is the current PCM operation for this BE ? */
  int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
  		struct snd_soc_pcm_runtime *be, int stream)
  {
  	if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
  	   ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
  		  be->dpcm[stream].runtime_update))
  		return 1;
  	return 0;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
  
  /* get the substream for this BE */
  struct snd_pcm_substream *
  	snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
  {
  	return be->pcm->streams[stream].substream;
  }
  EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
085d22be0   Kuninori Morimoto   ASoC: soc-pcm: ad...
2856
2857
2858
2859
2860
  static int snd_soc_dpcm_check_state(struct snd_soc_pcm_runtime *fe,
  				    struct snd_soc_pcm_runtime *be,
  				    int stream,
  				    const enum snd_soc_dpcm_state *states,
  				    int num_states)
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2861
2862
2863
  {
  	struct snd_soc_dpcm *dpcm;
  	int state;
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2864
2865
  	int ret = 1;
  	unsigned long flags;
085d22be0   Kuninori Morimoto   ASoC: soc-pcm: ad...
2866
  	int i;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2867

a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2868
  	spin_lock_irqsave(&fe->card->dpcm_lock, flags);
d2e24d646   Kuninori Morimoto   ASoC: add for_eac...
2869
  	for_each_dpcm_fe(be, stream, dpcm) {
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2870
2871
2872
2873
2874
  
  		if (dpcm->fe == fe)
  			continue;
  
  		state = dpcm->fe->dpcm[stream].state;
085d22be0   Kuninori Morimoto   ASoC: soc-pcm: ad...
2875
2876
2877
2878
2879
  		for (i = 0; i < num_states; i++) {
  			if (state == states[i]) {
  				ret = 0;
  				break;
  			}
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2880
  		}
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2881
  	}
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2882
  	spin_unlock_irqrestore(&fe->card->dpcm_lock, flags);
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2883

085d22be0   Kuninori Morimoto   ASoC: soc-pcm: ad...
2884
  	/* it's safe to do this BE DAI */
a97648697   KaiChieh Chuang   ASoC: dpcm: preve...
2885
  	return ret;
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2886
  }
085d22be0   Kuninori Morimoto   ASoC: soc-pcm: ad...
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
  
  /*
   * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
   * are not running, paused or suspended for the specified stream direction.
   */
  int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
  		struct snd_soc_pcm_runtime *be, int stream)
  {
  	const enum snd_soc_dpcm_state state[] = {
  		SND_SOC_DPCM_STATE_START,
  		SND_SOC_DPCM_STATE_PAUSED,
  		SND_SOC_DPCM_STATE_SUSPEND,
  	};
  
  	return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
  }
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2903
2904
2905
2906
2907
2908
2909
2910
2911
  EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
  
  /*
   * We can only change hw params a BE DAI if any of it's FE are not prepared,
   * running, paused or suspended for the specified stream direction.
   */
  int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
  		struct snd_soc_pcm_runtime *be, int stream)
  {
085d22be0   Kuninori Morimoto   ASoC: soc-pcm: ad...
2912
2913
2914
2915
2916
2917
  	const enum snd_soc_dpcm_state state[] = {
  		SND_SOC_DPCM_STATE_START,
  		SND_SOC_DPCM_STATE_PAUSED,
  		SND_SOC_DPCM_STATE_SUSPEND,
  		SND_SOC_DPCM_STATE_PREPARE,
  	};
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2918

085d22be0   Kuninori Morimoto   ASoC: soc-pcm: ad...
2919
  	return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
01d7584cd   Liam Girdwood   ASoC: dpcm: Add D...
2920
2921
  }
  EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);