diff options
author | Benoit Cousson <bcousson@baylibre.com> | 2014-07-08 17:19:35 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-07-16 18:04:52 -0400 |
commit | 2e5894d73789ee60d4d406fd3342a9a5152ec23c (patch) | |
tree | 76980121719de615fba7495eebd3b526557797b9 | |
parent | 88bd870f02dff5c9445286e185f21873f25a977f (diff) |
ASoC: pcm: Add support for DAI multicodec
Add multicodec support in soc-pcm.c
Signed-off-by: Benoit Cousson <bcousson@baylibre.com>
Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Signed-off-by: Fabien Parent <fparent@baylibre.com>
Tested-by: Lars-Peter Clausen <lars@metafoo.de>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r-- | sound/soc/soc-pcm.c | 534 |
1 files changed, 368 insertions, 166 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 3bf0355ca30f..ec56d1831a86 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -47,22 +47,26 @@ | |||
47 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | 47 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) |
48 | { | 48 | { |
49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
50 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 50 | int i; |
51 | 51 | ||
52 | lockdep_assert_held(&rtd->pcm_mutex); | 52 | lockdep_assert_held(&rtd->pcm_mutex); |
53 | 53 | ||
54 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 54 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
55 | cpu_dai->playback_active++; | 55 | cpu_dai->playback_active++; |
56 | codec_dai->playback_active++; | 56 | for (i = 0; i < rtd->num_codecs; i++) |
57 | rtd->codec_dais[i]->playback_active++; | ||
57 | } else { | 58 | } else { |
58 | cpu_dai->capture_active++; | 59 | cpu_dai->capture_active++; |
59 | codec_dai->capture_active++; | 60 | for (i = 0; i < rtd->num_codecs; i++) |
61 | rtd->codec_dais[i]->capture_active++; | ||
60 | } | 62 | } |
61 | 63 | ||
62 | cpu_dai->active++; | 64 | cpu_dai->active++; |
63 | codec_dai->active++; | ||
64 | cpu_dai->component->active++; | 65 | cpu_dai->component->active++; |
65 | codec_dai->component->active++; | 66 | for (i = 0; i < rtd->num_codecs; i++) { |
67 | rtd->codec_dais[i]->active++; | ||
68 | rtd->codec_dais[i]->component->active++; | ||
69 | } | ||
66 | } | 70 | } |
67 | 71 | ||
68 | /** | 72 | /** |
@@ -78,22 +82,26 @@ void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | |||
78 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | 82 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) |
79 | { | 83 | { |
80 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 84 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 85 | int i; |
82 | 86 | ||
83 | lockdep_assert_held(&rtd->pcm_mutex); | 87 | lockdep_assert_held(&rtd->pcm_mutex); |
84 | 88 | ||
85 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 89 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
86 | cpu_dai->playback_active--; | 90 | cpu_dai->playback_active--; |
87 | codec_dai->playback_active--; | 91 | for (i = 0; i < rtd->num_codecs; i++) |
92 | rtd->codec_dais[i]->playback_active--; | ||
88 | } else { | 93 | } else { |
89 | cpu_dai->capture_active--; | 94 | cpu_dai->capture_active--; |
90 | codec_dai->capture_active--; | 95 | for (i = 0; i < rtd->num_codecs; i++) |
96 | rtd->codec_dais[i]->capture_active--; | ||
91 | } | 97 | } |
92 | 98 | ||
93 | cpu_dai->active--; | 99 | cpu_dai->active--; |
94 | codec_dai->active--; | ||
95 | cpu_dai->component->active--; | 100 | cpu_dai->component->active--; |
96 | codec_dai->component->active--; | 101 | for (i = 0; i < rtd->num_codecs; i++) { |
102 | rtd->codec_dais[i]->component->active--; | ||
103 | rtd->codec_dais[i]->active--; | ||
104 | } | ||
97 | } | 105 | } |
98 | 106 | ||
99 | /** | 107 | /** |
@@ -107,11 +115,16 @@ void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | |||
107 | */ | 115 | */ |
108 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) | 116 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) |
109 | { | 117 | { |
118 | int i; | ||
119 | bool ignore = true; | ||
120 | |||
110 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) | 121 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) |
111 | return true; | 122 | return true; |
112 | 123 | ||
113 | return rtd->cpu_dai->component->ignore_pmdown_time && | 124 | for (i = 0; i < rtd->num_codecs; i++) |
114 | rtd->codec_dai->component->ignore_pmdown_time; | 125 | ignore &= rtd->codec_dais[i]->component->ignore_pmdown_time; |
126 | |||
127 | return rtd->cpu_dai->component->ignore_pmdown_time && ignore; | ||
115 | } | 128 | } |
116 | 129 | ||
117 | /** | 130 | /** |
@@ -222,8 +235,7 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
222 | { | 235 | { |
223 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 236 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
224 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 237 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
225 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 238 | unsigned int rate, channels, sample_bits, symmetry, i; |
226 | unsigned int rate, channels, sample_bits, symmetry; | ||
227 | 239 | ||
228 | rate = params_rate(params); | 240 | rate = params_rate(params); |
229 | channels = params_channels(params); | 241 | channels = params_channels(params); |
@@ -231,8 +243,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
231 | 243 | ||
232 | /* reject unmatched parameters when applying symmetry */ | 244 | /* reject unmatched parameters when applying symmetry */ |
233 | symmetry = cpu_dai->driver->symmetric_rates || | 245 | symmetry = cpu_dai->driver->symmetric_rates || |
234 | codec_dai->driver->symmetric_rates || | ||
235 | rtd->dai_link->symmetric_rates; | 246 | rtd->dai_link->symmetric_rates; |
247 | |||
248 | for (i = 0; i < rtd->num_codecs; i++) | ||
249 | symmetry |= rtd->codec_dais[i]->driver->symmetric_rates; | ||
250 | |||
236 | if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { | 251 | if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) { |
237 | dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", | 252 | dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n", |
238 | cpu_dai->rate, rate); | 253 | cpu_dai->rate, rate); |
@@ -240,8 +255,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
240 | } | 255 | } |
241 | 256 | ||
242 | symmetry = cpu_dai->driver->symmetric_channels || | 257 | symmetry = cpu_dai->driver->symmetric_channels || |
243 | codec_dai->driver->symmetric_channels || | ||
244 | rtd->dai_link->symmetric_channels; | 258 | rtd->dai_link->symmetric_channels; |
259 | |||
260 | for (i = 0; i < rtd->num_codecs; i++) | ||
261 | symmetry |= rtd->codec_dais[i]->driver->symmetric_channels; | ||
262 | |||
245 | if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { | 263 | if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) { |
246 | dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", | 264 | dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n", |
247 | cpu_dai->channels, channels); | 265 | cpu_dai->channels, channels); |
@@ -249,8 +267,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, | |||
249 | } | 267 | } |
250 | 268 | ||
251 | symmetry = cpu_dai->driver->symmetric_samplebits || | 269 | symmetry = cpu_dai->driver->symmetric_samplebits || |
252 | codec_dai->driver->symmetric_samplebits || | ||
253 | rtd->dai_link->symmetric_samplebits; | 270 | rtd->dai_link->symmetric_samplebits; |
271 | |||
272 | for (i = 0; i < rtd->num_codecs; i++) | ||
273 | symmetry |= rtd->codec_dais[i]->driver->symmetric_samplebits; | ||
274 | |||
254 | if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { | 275 | if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) { |
255 | dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", | 276 | dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n", |
256 | cpu_dai->sample_bits, sample_bits); | 277 | cpu_dai->sample_bits, sample_bits); |
@@ -264,15 +285,20 @@ static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream) | |||
264 | { | 285 | { |
265 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 286 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
266 | struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; | 287 | struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver; |
267 | struct snd_soc_dai_driver *codec_driver = rtd->codec_dai->driver; | ||
268 | struct snd_soc_dai_link *link = rtd->dai_link; | 288 | struct snd_soc_dai_link *link = rtd->dai_link; |
289 | unsigned int symmetry, i; | ||
290 | |||
291 | symmetry = cpu_driver->symmetric_rates || link->symmetric_rates || | ||
292 | cpu_driver->symmetric_channels || link->symmetric_channels || | ||
293 | cpu_driver->symmetric_samplebits || link->symmetric_samplebits; | ||
269 | 294 | ||
270 | return cpu_driver->symmetric_rates || codec_driver->symmetric_rates || | 295 | for (i = 0; i < rtd->num_codecs; i++) |
271 | link->symmetric_rates || cpu_driver->symmetric_channels || | 296 | symmetry = symmetry || |
272 | codec_driver->symmetric_channels || link->symmetric_channels || | 297 | rtd->codec_dais[i]->driver->symmetric_rates || |
273 | cpu_driver->symmetric_samplebits || | 298 | rtd->codec_dais[i]->driver->symmetric_channels || |
274 | codec_driver->symmetric_samplebits || | 299 | rtd->codec_dais[i]->driver->symmetric_samplebits; |
275 | link->symmetric_samplebits; | 300 | |
301 | return symmetry; | ||
276 | } | 302 | } |
277 | 303 | ||
278 | /* | 304 | /* |
@@ -284,9 +310,9 @@ static int sample_sizes[] = { | |||
284 | 24, 32, | 310 | 24, 32, |
285 | }; | 311 | }; |
286 | 312 | ||
287 | static void soc_pcm_set_msb(struct snd_pcm_substream *substream, | 313 | static void soc_pcm_set_msb(struct snd_pcm_substream *substream, int bits) |
288 | struct snd_soc_dai *dai, int bits) | ||
289 | { | 314 | { |
315 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
290 | int ret, i; | 316 | int ret, i; |
291 | 317 | ||
292 | if (!bits) | 318 | if (!bits) |
@@ -299,7 +325,7 @@ static void soc_pcm_set_msb(struct snd_pcm_substream *substream, | |||
299 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, | 325 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, |
300 | sample_sizes[i], bits); | 326 | sample_sizes[i], bits); |
301 | if (ret != 0) | 327 | if (ret != 0) |
302 | dev_warn(dai->dev, | 328 | dev_warn(rtd->dev, |
303 | "ASoC: Failed to set MSB %d/%d: %d\n", | 329 | "ASoC: Failed to set MSB %d/%d: %d\n", |
304 | bits, sample_sizes[i], ret); | 330 | bits, sample_sizes[i], ret); |
305 | } | 331 | } |
@@ -309,47 +335,95 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) | |||
309 | { | 335 | { |
310 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 336 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
311 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 337 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
312 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 338 | struct snd_soc_dai *codec_dai; |
339 | int i; | ||
313 | unsigned int bits = 0, cpu_bits; | 340 | unsigned int bits = 0, cpu_bits; |
314 | 341 | ||
315 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 342 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
316 | bits = codec_dai->driver->playback.sig_bits; | 343 | for (i = 0; i < rtd->num_codecs; i++) { |
344 | codec_dai = rtd->codec_dais[i]; | ||
345 | if (codec_dai->driver->playback.sig_bits == 0) { | ||
346 | bits = 0; | ||
347 | break; | ||
348 | } | ||
349 | bits = max(codec_dai->driver->playback.sig_bits, bits); | ||
350 | } | ||
317 | cpu_bits = cpu_dai->driver->playback.sig_bits; | 351 | cpu_bits = cpu_dai->driver->playback.sig_bits; |
318 | } else { | 352 | } else { |
319 | bits = codec_dai->driver->capture.sig_bits; | 353 | for (i = 0; i < rtd->num_codecs; i++) { |
354 | codec_dai = rtd->codec_dais[i]; | ||
355 | if (codec_dai->driver->playback.sig_bits == 0) { | ||
356 | bits = 0; | ||
357 | break; | ||
358 | } | ||
359 | bits = max(codec_dai->driver->capture.sig_bits, bits); | ||
360 | } | ||
320 | cpu_bits = cpu_dai->driver->capture.sig_bits; | 361 | cpu_bits = cpu_dai->driver->capture.sig_bits; |
321 | } | 362 | } |
322 | 363 | ||
323 | soc_pcm_set_msb(substream, codec_dai, bits); | 364 | soc_pcm_set_msb(substream, bits); |
324 | soc_pcm_set_msb(substream, cpu_dai, cpu_bits); | 365 | soc_pcm_set_msb(substream, cpu_bits); |
325 | } | 366 | } |
326 | 367 | ||
327 | static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime, | 368 | static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) |
328 | struct snd_soc_pcm_stream *codec_stream, | ||
329 | struct snd_soc_pcm_stream *cpu_stream) | ||
330 | { | 369 | { |
370 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
331 | struct snd_pcm_hardware *hw = &runtime->hw; | 371 | struct snd_pcm_hardware *hw = &runtime->hw; |
372 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
373 | struct snd_soc_dai_driver *cpu_dai_drv = rtd->cpu_dai->driver; | ||
374 | struct snd_soc_dai_driver *codec_dai_drv; | ||
375 | struct snd_soc_pcm_stream *codec_stream; | ||
376 | struct snd_soc_pcm_stream *cpu_stream; | ||
377 | unsigned int chan_min = 0, chan_max = UINT_MAX; | ||
378 | unsigned int rate_min = 0, rate_max = UINT_MAX; | ||
379 | unsigned int rates = UINT_MAX; | ||
380 | u64 formats = ULLONG_MAX; | ||
381 | int i; | ||
332 | 382 | ||
333 | hw->channels_min = max(codec_stream->channels_min, | 383 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
334 | cpu_stream->channels_min); | 384 | cpu_stream = &cpu_dai_drv->playback; |
335 | hw->channels_max = min(codec_stream->channels_max, | ||
336 | cpu_stream->channels_max); | ||
337 | if (hw->formats) | ||
338 | hw->formats &= codec_stream->formats & cpu_stream->formats; | ||
339 | else | 385 | else |
340 | hw->formats = codec_stream->formats & cpu_stream->formats; | 386 | cpu_stream = &cpu_dai_drv->capture; |
341 | hw->rates = snd_pcm_rate_mask_intersect(codec_stream->rates, | ||
342 | cpu_stream->rates); | ||
343 | 387 | ||
344 | hw->rate_min = 0; | 388 | /* first calculate min/max only for CODECs in the DAI link */ |
345 | hw->rate_max = UINT_MAX; | 389 | for (i = 0; i < rtd->num_codecs; i++) { |
390 | codec_dai_drv = rtd->codec_dais[i]->driver; | ||
391 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
392 | codec_stream = &codec_dai_drv->playback; | ||
393 | else | ||
394 | codec_stream = &codec_dai_drv->capture; | ||
395 | chan_min = max(chan_min, codec_stream->channels_min); | ||
396 | chan_max = min(chan_max, codec_stream->channels_max); | ||
397 | rate_min = max(rate_min, codec_stream->rate_min); | ||
398 | rate_max = min_not_zero(rate_max, codec_stream->rate_max); | ||
399 | formats &= codec_stream->formats; | ||
400 | rates = snd_pcm_rate_mask_intersect(codec_stream->rates, rates); | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * chan min/max cannot be enforced if there are multiple CODEC DAIs | ||
405 | * connected to a single CPU DAI, use CPU DAI's directly and let | ||
406 | * channel allocation be fixed up later | ||
407 | */ | ||
408 | if (rtd->num_codecs > 1) { | ||
409 | chan_min = cpu_stream->channels_min; | ||
410 | chan_max = cpu_stream->channels_max; | ||
411 | } | ||
412 | |||
413 | hw->channels_min = max(chan_min, cpu_stream->channels_min); | ||
414 | hw->channels_max = min(chan_max, cpu_stream->channels_max); | ||
415 | if (hw->formats) | ||
416 | hw->formats &= formats & cpu_stream->formats; | ||
417 | else | ||
418 | hw->formats = formats & cpu_stream->formats; | ||
419 | hw->rates = snd_pcm_rate_mask_intersect(rates, cpu_stream->rates); | ||
346 | 420 | ||
347 | snd_pcm_limit_hw_rates(runtime); | 421 | snd_pcm_limit_hw_rates(runtime); |
348 | 422 | ||
349 | hw->rate_min = max(hw->rate_min, cpu_stream->rate_min); | 423 | hw->rate_min = max(hw->rate_min, cpu_stream->rate_min); |
350 | hw->rate_min = max(hw->rate_min, codec_stream->rate_min); | 424 | hw->rate_min = max(hw->rate_min, rate_min); |
351 | hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max); | 425 | hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max); |
352 | hw->rate_max = min_not_zero(hw->rate_max, codec_stream->rate_max); | 426 | hw->rate_max = min_not_zero(hw->rate_max, rate_max); |
353 | } | 427 | } |
354 | 428 | ||
355 | /* | 429 | /* |
@@ -363,15 +437,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
363 | struct snd_pcm_runtime *runtime = substream->runtime; | 437 | struct snd_pcm_runtime *runtime = substream->runtime; |
364 | struct snd_soc_platform *platform = rtd->platform; | 438 | struct snd_soc_platform *platform = rtd->platform; |
365 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 439 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
366 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 440 | struct snd_soc_dai *codec_dai; |
367 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | 441 | const char *codec_dai_name = "multicodec"; |
368 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; | 442 | int i, ret = 0; |
369 | int ret = 0; | ||
370 | 443 | ||
371 | pinctrl_pm_select_default_state(cpu_dai->dev); | 444 | pinctrl_pm_select_default_state(cpu_dai->dev); |
372 | pinctrl_pm_select_default_state(codec_dai->dev); | 445 | for (i = 0; i < rtd->num_codecs; i++) |
446 | pinctrl_pm_select_default_state(rtd->codec_dais[i]->dev); | ||
373 | pm_runtime_get_sync(cpu_dai->dev); | 447 | pm_runtime_get_sync(cpu_dai->dev); |
374 | pm_runtime_get_sync(codec_dai->dev); | 448 | for (i = 0; i < rtd->num_codecs; i++) |
449 | pm_runtime_get_sync(rtd->codec_dais[i]->dev); | ||
375 | pm_runtime_get_sync(platform->dev); | 450 | pm_runtime_get_sync(platform->dev); |
376 | 451 | ||
377 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 452 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
@@ -395,13 +470,23 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
395 | } | 470 | } |
396 | } | 471 | } |
397 | 472 | ||
398 | if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { | 473 | for (i = 0; i < rtd->num_codecs; i++) { |
399 | ret = codec_dai->driver->ops->startup(substream, codec_dai); | 474 | codec_dai = rtd->codec_dais[i]; |
400 | if (ret < 0) { | 475 | if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { |
401 | dev_err(codec_dai->dev, "ASoC: can't open codec" | 476 | ret = codec_dai->driver->ops->startup(substream, |
402 | " %s: %d\n", codec_dai->name, ret); | 477 | codec_dai); |
403 | goto codec_dai_err; | 478 | if (ret < 0) { |
479 | dev_err(codec_dai->dev, | ||
480 | "ASoC: can't open codec %s: %d\n", | ||
481 | codec_dai->name, ret); | ||
482 | goto codec_dai_err; | ||
483 | } | ||
404 | } | 484 | } |
485 | |||
486 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
487 | codec_dai->tx_mask = 0; | ||
488 | else | ||
489 | codec_dai->rx_mask = 0; | ||
405 | } | 490 | } |
406 | 491 | ||
407 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { | 492 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { |
@@ -418,13 +503,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
418 | goto dynamic; | 503 | goto dynamic; |
419 | 504 | ||
420 | /* Check that the codec and cpu DAIs are compatible */ | 505 | /* Check that the codec and cpu DAIs are compatible */ |
421 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 506 | soc_pcm_init_runtime_hw(substream); |
422 | soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback, | 507 | |
423 | &cpu_dai_drv->playback); | 508 | if (rtd->num_codecs == 1) |
424 | } else { | 509 | codec_dai_name = rtd->codec_dai->name; |
425 | soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture, | ||
426 | &cpu_dai_drv->capture); | ||
427 | } | ||
428 | 510 | ||
429 | if (soc_pcm_has_symmetry(substream)) | 511 | if (soc_pcm_has_symmetry(substream)) |
430 | runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; | 512 | runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; |
@@ -432,18 +514,18 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
432 | ret = -EINVAL; | 514 | ret = -EINVAL; |
433 | if (!runtime->hw.rates) { | 515 | if (!runtime->hw.rates) { |
434 | printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", | 516 | printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", |
435 | codec_dai->name, cpu_dai->name); | 517 | codec_dai_name, cpu_dai->name); |
436 | goto config_err; | 518 | goto config_err; |
437 | } | 519 | } |
438 | if (!runtime->hw.formats) { | 520 | if (!runtime->hw.formats) { |
439 | printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", | 521 | printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", |
440 | codec_dai->name, cpu_dai->name); | 522 | codec_dai_name, cpu_dai->name); |
441 | goto config_err; | 523 | goto config_err; |
442 | } | 524 | } |
443 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || | 525 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || |
444 | runtime->hw.channels_min > runtime->hw.channels_max) { | 526 | runtime->hw.channels_min > runtime->hw.channels_max) { |
445 | printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", | 527 | printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", |
446 | codec_dai->name, cpu_dai->name); | 528 | codec_dai_name, cpu_dai->name); |
447 | goto config_err; | 529 | goto config_err; |
448 | } | 530 | } |
449 | 531 | ||
@@ -456,14 +538,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
456 | goto config_err; | 538 | goto config_err; |
457 | } | 539 | } |
458 | 540 | ||
459 | if (codec_dai->active) { | 541 | for (i = 0; i < rtd->num_codecs; i++) { |
460 | ret = soc_pcm_apply_symmetry(substream, codec_dai); | 542 | if (rtd->codec_dais[i]->active) { |
461 | if (ret != 0) | 543 | ret = soc_pcm_apply_symmetry(substream, |
462 | goto config_err; | 544 | rtd->codec_dais[i]); |
545 | if (ret != 0) | ||
546 | goto config_err; | ||
547 | } | ||
463 | } | 548 | } |
464 | 549 | ||
465 | pr_debug("ASoC: %s <-> %s info:\n", | 550 | pr_debug("ASoC: %s <-> %s info:\n", |
466 | codec_dai->name, cpu_dai->name); | 551 | codec_dai_name, cpu_dai->name); |
467 | pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); | 552 | pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); |
468 | pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, | 553 | pr_debug("ASoC: min ch %d max ch %d\n", runtime->hw.channels_min, |
469 | runtime->hw.channels_max); | 554 | runtime->hw.channels_max); |
@@ -482,10 +567,15 @@ config_err: | |||
482 | rtd->dai_link->ops->shutdown(substream); | 567 | rtd->dai_link->ops->shutdown(substream); |
483 | 568 | ||
484 | machine_err: | 569 | machine_err: |
485 | if (codec_dai->driver->ops->shutdown) | 570 | i = rtd->num_codecs; |
486 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
487 | 571 | ||
488 | codec_dai_err: | 572 | codec_dai_err: |
573 | while (--i >= 0) { | ||
574 | codec_dai = rtd->codec_dais[i]; | ||
575 | if (codec_dai->driver->ops->shutdown) | ||
576 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
577 | } | ||
578 | |||
489 | if (platform->driver->ops && platform->driver->ops->close) | 579 | if (platform->driver->ops && platform->driver->ops->close) |
490 | platform->driver->ops->close(substream); | 580 | platform->driver->ops->close(substream); |
491 | 581 | ||
@@ -496,10 +586,13 @@ out: | |||
496 | mutex_unlock(&rtd->pcm_mutex); | 586 | mutex_unlock(&rtd->pcm_mutex); |
497 | 587 | ||
498 | pm_runtime_put(platform->dev); | 588 | pm_runtime_put(platform->dev); |
499 | pm_runtime_put(codec_dai->dev); | 589 | for (i = 0; i < rtd->num_codecs; i++) |
590 | pm_runtime_put(rtd->codec_dais[i]->dev); | ||
500 | pm_runtime_put(cpu_dai->dev); | 591 | pm_runtime_put(cpu_dai->dev); |
501 | if (!codec_dai->active) | 592 | for (i = 0; i < rtd->num_codecs; i++) { |
502 | pinctrl_pm_select_sleep_state(codec_dai->dev); | 593 | if (!rtd->codec_dais[i]->active) |
594 | pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); | ||
595 | } | ||
503 | if (!cpu_dai->active) | 596 | if (!cpu_dai->active) |
504 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 597 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
505 | 598 | ||
@@ -515,7 +608,7 @@ static void close_delayed_work(struct work_struct *work) | |||
515 | { | 608 | { |
516 | struct snd_soc_pcm_runtime *rtd = | 609 | struct snd_soc_pcm_runtime *rtd = |
517 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | 610 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); |
518 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 611 | struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; |
519 | 612 | ||
520 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 613 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
521 | 614 | ||
@@ -544,7 +637,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
544 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 637 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
545 | struct snd_soc_platform *platform = rtd->platform; | 638 | struct snd_soc_platform *platform = rtd->platform; |
546 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 639 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
547 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 640 | struct snd_soc_dai *codec_dai; |
641 | int i; | ||
548 | 642 | ||
549 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 643 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
550 | 644 | ||
@@ -554,14 +648,20 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
554 | if (!cpu_dai->active) | 648 | if (!cpu_dai->active) |
555 | cpu_dai->rate = 0; | 649 | cpu_dai->rate = 0; |
556 | 650 | ||
557 | if (!codec_dai->active) | 651 | for (i = 0; i < rtd->num_codecs; i++) { |
558 | codec_dai->rate = 0; | 652 | codec_dai = rtd->codec_dais[i]; |
653 | if (!codec_dai->active) | ||
654 | codec_dai->rate = 0; | ||
655 | } | ||
559 | 656 | ||
560 | if (cpu_dai->driver->ops->shutdown) | 657 | if (cpu_dai->driver->ops->shutdown) |
561 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 658 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
562 | 659 | ||
563 | if (codec_dai->driver->ops->shutdown) | 660 | for (i = 0; i < rtd->num_codecs; i++) { |
564 | codec_dai->driver->ops->shutdown(substream, codec_dai); | 661 | codec_dai = rtd->codec_dais[i]; |
662 | if (codec_dai->driver->ops->shutdown) | ||
663 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
664 | } | ||
565 | 665 | ||
566 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | 666 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) |
567 | rtd->dai_link->ops->shutdown(substream); | 667 | rtd->dai_link->ops->shutdown(substream); |
@@ -591,10 +691,13 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
591 | mutex_unlock(&rtd->pcm_mutex); | 691 | mutex_unlock(&rtd->pcm_mutex); |
592 | 692 | ||
593 | pm_runtime_put(platform->dev); | 693 | pm_runtime_put(platform->dev); |
594 | pm_runtime_put(codec_dai->dev); | 694 | for (i = 0; i < rtd->num_codecs; i++) |
695 | pm_runtime_put(rtd->codec_dais[i]->dev); | ||
595 | pm_runtime_put(cpu_dai->dev); | 696 | pm_runtime_put(cpu_dai->dev); |
596 | if (!codec_dai->active) | 697 | for (i = 0; i < rtd->num_codecs; i++) { |
597 | pinctrl_pm_select_sleep_state(codec_dai->dev); | 698 | if (!rtd->codec_dais[i]->active) |
699 | pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); | ||
700 | } | ||
598 | if (!cpu_dai->active) | 701 | if (!cpu_dai->active) |
599 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 702 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
600 | 703 | ||
@@ -611,8 +714,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
611 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 714 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
612 | struct snd_soc_platform *platform = rtd->platform; | 715 | struct snd_soc_platform *platform = rtd->platform; |
613 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 716 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
614 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 717 | struct snd_soc_dai *codec_dai; |
615 | int ret = 0; | 718 | int i, ret = 0; |
616 | 719 | ||
617 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 720 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
618 | 721 | ||
@@ -634,12 +737,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
634 | } | 737 | } |
635 | } | 738 | } |
636 | 739 | ||
637 | if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { | 740 | for (i = 0; i < rtd->num_codecs; i++) { |
638 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); | 741 | codec_dai = rtd->codec_dais[i]; |
639 | if (ret < 0) { | 742 | if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { |
640 | dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n", | 743 | ret = codec_dai->driver->ops->prepare(substream, |
641 | ret); | 744 | codec_dai); |
642 | goto out; | 745 | if (ret < 0) { |
746 | dev_err(codec_dai->dev, | ||
747 | "ASoC: DAI prepare error: %d\n", ret); | ||
748 | goto out; | ||
749 | } | ||
643 | } | 750 | } |
644 | } | 751 | } |
645 | 752 | ||
@@ -662,13 +769,26 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
662 | snd_soc_dapm_stream_event(rtd, substream->stream, | 769 | snd_soc_dapm_stream_event(rtd, substream->stream, |
663 | SND_SOC_DAPM_STREAM_START); | 770 | SND_SOC_DAPM_STREAM_START); |
664 | 771 | ||
665 | snd_soc_dai_digital_mute(codec_dai, 0, substream->stream); | 772 | for (i = 0; i < rtd->num_codecs; i++) |
773 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, | ||
774 | substream->stream); | ||
666 | 775 | ||
667 | out: | 776 | out: |
668 | mutex_unlock(&rtd->pcm_mutex); | 777 | mutex_unlock(&rtd->pcm_mutex); |
669 | return ret; | 778 | return ret; |
670 | } | 779 | } |
671 | 780 | ||
781 | static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params, | ||
782 | unsigned int mask) | ||
783 | { | ||
784 | struct snd_interval *interval; | ||
785 | int channels = hweight_long(mask); | ||
786 | |||
787 | interval = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
788 | interval->min = channels; | ||
789 | interval->max = channels; | ||
790 | } | ||
791 | |||
672 | /* | 792 | /* |
673 | * Called by ALSA when the hardware params are set by application. This | 793 | * Called by ALSA when the hardware params are set by application. This |
674 | * function can also be called multiple times and can allocate buffers | 794 | * function can also be called multiple times and can allocate buffers |
@@ -680,8 +800,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
680 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 800 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
681 | struct snd_soc_platform *platform = rtd->platform; | 801 | struct snd_soc_platform *platform = rtd->platform; |
682 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 802 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
683 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 803 | int i, ret = 0; |
684 | int ret = 0; | ||
685 | 804 | ||
686 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 805 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
687 | 806 | ||
@@ -698,13 +817,37 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
698 | } | 817 | } |
699 | } | 818 | } |
700 | 819 | ||
701 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_params) { | 820 | for (i = 0; i < rtd->num_codecs; i++) { |
702 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); | 821 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
703 | if (ret < 0) { | 822 | struct snd_pcm_hw_params codec_params; |
704 | dev_err(codec_dai->dev, "ASoC: can't set %s hw params:" | 823 | |
705 | " %d\n", codec_dai->name, ret); | 824 | /* copy params for each codec */ |
706 | goto codec_err; | 825 | codec_params = *params; |
826 | |||
827 | /* fixup params based on TDM slot masks */ | ||
828 | if (codec_dai->tx_mask) | ||
829 | soc_pcm_codec_params_fixup(&codec_params, | ||
830 | codec_dai->tx_mask); | ||
831 | if (codec_dai->rx_mask) | ||
832 | soc_pcm_codec_params_fixup(&codec_params, | ||
833 | codec_dai->rx_mask); | ||
834 | |||
835 | if (codec_dai->driver->ops && | ||
836 | codec_dai->driver->ops->hw_params) { | ||
837 | ret = codec_dai->driver->ops->hw_params(substream, | ||
838 | &codec_params, codec_dai); | ||
839 | if (ret < 0) { | ||
840 | dev_err(codec_dai->dev, | ||
841 | "ASoC: can't set %s hw params: %d\n", | ||
842 | codec_dai->name, ret); | ||
843 | goto codec_err; | ||
844 | } | ||
707 | } | 845 | } |
846 | |||
847 | codec_dai->rate = params_rate(&codec_params); | ||
848 | codec_dai->channels = params_channels(&codec_params); | ||
849 | codec_dai->sample_bits = snd_pcm_format_physical_width( | ||
850 | params_format(&codec_params)); | ||
708 | } | 851 | } |
709 | 852 | ||
710 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) { | 853 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) { |
@@ -731,11 +874,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
731 | cpu_dai->sample_bits = | 874 | cpu_dai->sample_bits = |
732 | snd_pcm_format_physical_width(params_format(params)); | 875 | snd_pcm_format_physical_width(params_format(params)); |
733 | 876 | ||
734 | codec_dai->rate = params_rate(params); | ||
735 | codec_dai->channels = params_channels(params); | ||
736 | codec_dai->sample_bits = | ||
737 | snd_pcm_format_physical_width(params_format(params)); | ||
738 | |||
739 | out: | 877 | out: |
740 | mutex_unlock(&rtd->pcm_mutex); | 878 | mutex_unlock(&rtd->pcm_mutex); |
741 | return ret; | 879 | return ret; |
@@ -745,10 +883,16 @@ platform_err: | |||
745 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 883 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
746 | 884 | ||
747 | interface_err: | 885 | interface_err: |
748 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | 886 | i = rtd->num_codecs; |
749 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
750 | 887 | ||
751 | codec_err: | 888 | codec_err: |
889 | while (--i >= 0) { | ||
890 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; | ||
891 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | ||
892 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
893 | codec_dai->rate = 0; | ||
894 | } | ||
895 | |||
752 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 896 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
753 | rtd->dai_link->ops->hw_free(substream); | 897 | rtd->dai_link->ops->hw_free(substream); |
754 | 898 | ||
@@ -764,8 +908,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
764 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 908 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
765 | struct snd_soc_platform *platform = rtd->platform; | 909 | struct snd_soc_platform *platform = rtd->platform; |
766 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 910 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
767 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 911 | struct snd_soc_dai *codec_dai; |
768 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 912 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
913 | int i; | ||
769 | 914 | ||
770 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 915 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
771 | 916 | ||
@@ -776,16 +921,22 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
776 | cpu_dai->sample_bits = 0; | 921 | cpu_dai->sample_bits = 0; |
777 | } | 922 | } |
778 | 923 | ||
779 | if (codec_dai->active == 1) { | 924 | for (i = 0; i < rtd->num_codecs; i++) { |
780 | codec_dai->rate = 0; | 925 | codec_dai = rtd->codec_dais[i]; |
781 | codec_dai->channels = 0; | 926 | if (codec_dai->active == 1) { |
782 | codec_dai->sample_bits = 0; | 927 | codec_dai->rate = 0; |
928 | codec_dai->channels = 0; | ||
929 | codec_dai->sample_bits = 0; | ||
930 | } | ||
783 | } | 931 | } |
784 | 932 | ||
785 | /* apply codec digital mute */ | 933 | /* apply codec digital mute */ |
786 | if ((playback && codec_dai->playback_active == 1) || | 934 | for (i = 0; i < rtd->num_codecs; i++) { |
787 | (!playback && codec_dai->capture_active == 1)) | 935 | if ((playback && rtd->codec_dais[i]->playback_active == 1) || |
788 | snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); | 936 | (!playback && rtd->codec_dais[i]->capture_active == 1)) |
937 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 1, | ||
938 | substream->stream); | ||
939 | } | ||
789 | 940 | ||
790 | /* free any machine hw params */ | 941 | /* free any machine hw params */ |
791 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 942 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
@@ -796,8 +947,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
796 | platform->driver->ops->hw_free(substream); | 947 | platform->driver->ops->hw_free(substream); |
797 | 948 | ||
798 | /* now free hw params for the DAIs */ | 949 | /* now free hw params for the DAIs */ |
799 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | 950 | for (i = 0; i < rtd->num_codecs; i++) { |
800 | codec_dai->driver->ops->hw_free(substream, codec_dai); | 951 | codec_dai = rtd->codec_dais[i]; |
952 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | ||
953 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
954 | } | ||
801 | 955 | ||
802 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) | 956 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) |
803 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 957 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
@@ -811,13 +965,17 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
811 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 965 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
812 | struct snd_soc_platform *platform = rtd->platform; | 966 | struct snd_soc_platform *platform = rtd->platform; |
813 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 967 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
814 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 968 | struct snd_soc_dai *codec_dai; |
815 | int ret; | 969 | int i, ret; |
816 | 970 | ||
817 | if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { | 971 | for (i = 0; i < rtd->num_codecs; i++) { |
818 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); | 972 | codec_dai = rtd->codec_dais[i]; |
819 | if (ret < 0) | 973 | if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { |
820 | return ret; | 974 | ret = codec_dai->driver->ops->trigger(substream, |
975 | cmd, codec_dai); | ||
976 | if (ret < 0) | ||
977 | return ret; | ||
978 | } | ||
821 | } | 979 | } |
822 | 980 | ||
823 | if (platform->driver->ops && platform->driver->ops->trigger) { | 981 | if (platform->driver->ops && platform->driver->ops->trigger) { |
@@ -847,14 +1005,18 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, | |||
847 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1005 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
848 | struct snd_soc_platform *platform = rtd->platform; | 1006 | struct snd_soc_platform *platform = rtd->platform; |
849 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1007 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
850 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 1008 | struct snd_soc_dai *codec_dai; |
851 | int ret; | 1009 | int i, ret; |
852 | 1010 | ||
853 | if (codec_dai->driver->ops && | 1011 | for (i = 0; i < rtd->num_codecs; i++) { |
854 | codec_dai->driver->ops->bespoke_trigger) { | 1012 | codec_dai = rtd->codec_dais[i]; |
855 | ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); | 1013 | if (codec_dai->driver->ops && |
856 | if (ret < 0) | 1014 | codec_dai->driver->ops->bespoke_trigger) { |
857 | return ret; | 1015 | ret = codec_dai->driver->ops->bespoke_trigger(substream, |
1016 | cmd, codec_dai); | ||
1017 | if (ret < 0) | ||
1018 | return ret; | ||
1019 | } | ||
858 | } | 1020 | } |
859 | 1021 | ||
860 | if (platform->driver->bespoke_trigger) { | 1022 | if (platform->driver->bespoke_trigger) { |
@@ -880,10 +1042,12 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | |||
880 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1042 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
881 | struct snd_soc_platform *platform = rtd->platform; | 1043 | struct snd_soc_platform *platform = rtd->platform; |
882 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1044 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
883 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 1045 | struct snd_soc_dai *codec_dai; |
884 | struct snd_pcm_runtime *runtime = substream->runtime; | 1046 | struct snd_pcm_runtime *runtime = substream->runtime; |
885 | snd_pcm_uframes_t offset = 0; | 1047 | snd_pcm_uframes_t offset = 0; |
886 | snd_pcm_sframes_t delay = 0; | 1048 | snd_pcm_sframes_t delay = 0; |
1049 | snd_pcm_sframes_t codec_delay = 0; | ||
1050 | int i; | ||
887 | 1051 | ||
888 | if (platform->driver->ops && platform->driver->ops->pointer) | 1052 | if (platform->driver->ops && platform->driver->ops->pointer) |
889 | offset = platform->driver->ops->pointer(substream); | 1053 | offset = platform->driver->ops->pointer(substream); |
@@ -891,11 +1055,21 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | |||
891 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) | 1055 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) |
892 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); | 1056 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); |
893 | 1057 | ||
894 | if (codec_dai->driver->ops && codec_dai->driver->ops->delay) | 1058 | for (i = 0; i < rtd->num_codecs; i++) { |
895 | delay += codec_dai->driver->ops->delay(substream, codec_dai); | 1059 | codec_dai = rtd->codec_dais[i]; |
1060 | if (codec_dai->driver->ops && codec_dai->driver->ops->delay) | ||
1061 | codec_delay = max(codec_delay, | ||
1062 | codec_dai->driver->ops->delay(substream, | ||
1063 | codec_dai)); | ||
1064 | } | ||
1065 | delay += codec_delay; | ||
896 | 1066 | ||
1067 | /* | ||
1068 | * None of the existing platform drivers implement delay(), so | ||
1069 | * for now the codec_dai of first multicodec entry is used | ||
1070 | */ | ||
897 | if (platform->driver->delay) | 1071 | if (platform->driver->delay) |
898 | delay += platform->driver->delay(substream, codec_dai); | 1072 | delay += platform->driver->delay(substream, rtd->codec_dais[0]); |
899 | 1073 | ||
900 | runtime->delay = delay; | 1074 | runtime->delay = delay; |
901 | 1075 | ||
@@ -998,7 +1172,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
998 | struct snd_soc_dapm_widget *widget, int stream) | 1172 | struct snd_soc_dapm_widget *widget, int stream) |
999 | { | 1173 | { |
1000 | struct snd_soc_pcm_runtime *be; | 1174 | struct snd_soc_pcm_runtime *be; |
1001 | int i; | 1175 | int i, j; |
1002 | 1176 | ||
1003 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1177 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
1004 | for (i = 0; i < card->num_links; i++) { | 1178 | for (i = 0; i < card->num_links; i++) { |
@@ -1007,9 +1181,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
1007 | if (!be->dai_link->no_pcm) | 1181 | if (!be->dai_link->no_pcm) |
1008 | continue; | 1182 | continue; |
1009 | 1183 | ||
1010 | if (be->cpu_dai->playback_widget == widget || | 1184 | if (be->cpu_dai->playback_widget == widget) |
1011 | be->codec_dai->playback_widget == widget) | ||
1012 | return be; | 1185 | return be; |
1186 | |||
1187 | for (j = 0; j < be->num_codecs; j++) { | ||
1188 | struct snd_soc_dai *dai = be->codec_dais[j]; | ||
1189 | if (dai->playback_widget == widget) | ||
1190 | return be; | ||
1191 | } | ||
1013 | } | 1192 | } |
1014 | } else { | 1193 | } else { |
1015 | 1194 | ||
@@ -1019,9 +1198,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
1019 | if (!be->dai_link->no_pcm) | 1198 | if (!be->dai_link->no_pcm) |
1020 | continue; | 1199 | continue; |
1021 | 1200 | ||
1022 | if (be->cpu_dai->capture_widget == widget || | 1201 | if (be->cpu_dai->capture_widget == widget) |
1023 | be->codec_dai->capture_widget == widget) | ||
1024 | return be; | 1202 | return be; |
1203 | |||
1204 | for (j = 0; j < be->num_codecs; j++) { | ||
1205 | struct snd_soc_dai *dai = be->codec_dais[j]; | ||
1206 | if (dai->capture_widget == widget) | ||
1207 | return be; | ||
1208 | } | ||
1025 | } | 1209 | } |
1026 | } | 1210 | } |
1027 | 1211 | ||
@@ -1084,6 +1268,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | |||
1084 | 1268 | ||
1085 | /* Destroy any old FE <--> BE connections */ | 1269 | /* Destroy any old FE <--> BE connections */ |
1086 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1270 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1271 | unsigned int i; | ||
1087 | 1272 | ||
1088 | /* is there a valid CPU DAI widget for this BE */ | 1273 | /* is there a valid CPU DAI widget for this BE */ |
1089 | widget = dai_get_widget(dpcm->be->cpu_dai, stream); | 1274 | widget = dai_get_widget(dpcm->be->cpu_dai, stream); |
@@ -1093,11 +1278,14 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | |||
1093 | continue; | 1278 | continue; |
1094 | 1279 | ||
1095 | /* is there a valid CODEC DAI widget for this BE */ | 1280 | /* is there a valid CODEC DAI widget for this BE */ |
1096 | widget = dai_get_widget(dpcm->be->codec_dai, stream); | 1281 | for (i = 0; i < dpcm->be->num_codecs; i++) { |
1282 | struct snd_soc_dai *dai = dpcm->be->codec_dais[i]; | ||
1283 | widget = dai_get_widget(dai, stream); | ||
1097 | 1284 | ||
1098 | /* prune the BE if it's no longer in our active list */ | 1285 | /* prune the BE if it's no longer in our active list */ |
1099 | if (widget && widget_in_list(list, widget)) | 1286 | if (widget && widget_in_list(list, widget)) |
1100 | continue; | 1287 | continue; |
1288 | } | ||
1101 | 1289 | ||
1102 | dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", | 1290 | dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", |
1103 | stream ? "capture" : "playback", | 1291 | stream ? "capture" : "playback", |
@@ -2126,16 +2314,22 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) | |||
2126 | list_for_each_entry(dpcm, clients, list_be) { | 2314 | list_for_each_entry(dpcm, clients, list_be) { |
2127 | 2315 | ||
2128 | struct snd_soc_pcm_runtime *be = dpcm->be; | 2316 | struct snd_soc_pcm_runtime *be = dpcm->be; |
2129 | struct snd_soc_dai *dai = be->codec_dai; | 2317 | int i; |
2130 | struct snd_soc_dai_driver *drv = dai->driver; | ||
2131 | 2318 | ||
2132 | if (be->dai_link->ignore_suspend) | 2319 | if (be->dai_link->ignore_suspend) |
2133 | continue; | 2320 | continue; |
2134 | 2321 | ||
2135 | dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name); | 2322 | for (i = 0; i < be->num_codecs; i++) { |
2323 | struct snd_soc_dai *dai = be->codec_dais[i]; | ||
2324 | struct snd_soc_dai_driver *drv = dai->driver; | ||
2325 | |||
2326 | dev_dbg(be->dev, "ASoC: BE digital mute %s\n", | ||
2327 | be->dai_link->name); | ||
2136 | 2328 | ||
2137 | if (drv->ops && drv->ops->digital_mute && dai->playback_active) | 2329 | if (drv->ops && drv->ops->digital_mute && |
2138 | drv->ops->digital_mute(dai, mute); | 2330 | dai->playback_active) |
2331 | drv->ops->digital_mute(dai, mute); | ||
2332 | } | ||
2139 | } | 2333 | } |
2140 | 2334 | ||
2141 | return 0; | 2335 | return 0; |
@@ -2200,22 +2394,27 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) | |||
2200 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | 2394 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
2201 | { | 2395 | { |
2202 | struct snd_soc_platform *platform = rtd->platform; | 2396 | struct snd_soc_platform *platform = rtd->platform; |
2203 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 2397 | struct snd_soc_dai *codec_dai; |
2204 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 2398 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2205 | struct snd_pcm *pcm; | 2399 | struct snd_pcm *pcm; |
2206 | char new_name[64]; | 2400 | char new_name[64]; |
2207 | int ret = 0, playback = 0, capture = 0; | 2401 | int ret = 0, playback = 0, capture = 0; |
2402 | int i; | ||
2208 | 2403 | ||
2209 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { | 2404 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { |
2210 | playback = rtd->dai_link->dpcm_playback; | 2405 | playback = rtd->dai_link->dpcm_playback; |
2211 | capture = rtd->dai_link->dpcm_capture; | 2406 | capture = rtd->dai_link->dpcm_capture; |
2212 | } else { | 2407 | } else { |
2213 | if (codec_dai->driver->playback.channels_min && | 2408 | for (i = 0; i < rtd->num_codecs; i++) { |
2214 | cpu_dai->driver->playback.channels_min) | 2409 | codec_dai = rtd->codec_dais[i]; |
2215 | playback = 1; | 2410 | if (codec_dai->driver->playback.channels_min) |
2216 | if (codec_dai->driver->capture.channels_min && | 2411 | playback = 1; |
2217 | cpu_dai->driver->capture.channels_min) | 2412 | if (codec_dai->driver->capture.channels_min) |
2218 | capture = 1; | 2413 | capture = 1; |
2414 | } | ||
2415 | |||
2416 | capture = capture && cpu_dai->driver->capture.channels_min; | ||
2417 | playback = playback && cpu_dai->driver->playback.channels_min; | ||
2219 | } | 2418 | } |
2220 | 2419 | ||
2221 | if (rtd->dai_link->playback_only) { | 2420 | if (rtd->dai_link->playback_only) { |
@@ -2241,7 +2440,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2241 | rtd->dai_link->stream_name); | 2440 | rtd->dai_link->stream_name); |
2242 | else | 2441 | else |
2243 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 2442 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
2244 | rtd->dai_link->stream_name, codec_dai->name, num); | 2443 | rtd->dai_link->stream_name, |
2444 | (rtd->num_codecs > 1) ? | ||
2445 | "multicodec" : rtd->codec_dai->name, num); | ||
2245 | 2446 | ||
2246 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, | 2447 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, |
2247 | capture, &pcm); | 2448 | capture, &pcm); |
@@ -2314,8 +2515,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2314 | 2515 | ||
2315 | pcm->private_free = platform->driver->pcm_free; | 2516 | pcm->private_free = platform->driver->pcm_free; |
2316 | out: | 2517 | out: |
2317 | dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name, | 2518 | dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", |
2318 | cpu_dai->name); | 2519 | (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, |
2520 | cpu_dai->name); | ||
2319 | return ret; | 2521 | return ret; |
2320 | } | 2522 | } |
2321 | 2523 | ||