diff options
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r-- | sound/soc/soc-pcm.c | 581 |
1 files changed, 401 insertions, 180 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 54d18f22a33e..731fdb5b5f9b 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Copyright (C) 2010 Texas Instruments Inc. | 7 | * Copyright (C) 2010 Texas Instruments Inc. |
8 | * | 8 | * |
9 | * Authors: Liam Girdwood <lrg@ti.com> | 9 | * Authors: Liam Girdwood <lrg@ti.com> |
10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | 10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify it | 12 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 13 | * under the terms of the GNU General Public License as published by the |
@@ -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; | ||
269 | 290 | ||
270 | return cpu_driver->symmetric_rates || codec_driver->symmetric_rates || | 291 | symmetry = cpu_driver->symmetric_rates || link->symmetric_rates || |
271 | link->symmetric_rates || cpu_driver->symmetric_channels || | 292 | cpu_driver->symmetric_channels || link->symmetric_channels || |
272 | codec_driver->symmetric_channels || link->symmetric_channels || | 293 | cpu_driver->symmetric_samplebits || link->symmetric_samplebits; |
273 | cpu_driver->symmetric_samplebits || | 294 | |
274 | codec_driver->symmetric_samplebits || | 295 | for (i = 0; i < rtd->num_codecs; i++) |
275 | link->symmetric_samplebits; | 296 | symmetry = symmetry || |
297 | rtd->codec_dais[i]->driver->symmetric_rates || | ||
298 | rtd->codec_dais[i]->driver->symmetric_channels || | ||
299 | rtd->codec_dais[i]->driver->symmetric_samplebits; | ||
300 | |||
301 | return symmetry; | ||
276 | } | 302 | } |
277 | 303 | ||
278 | /* | 304 | /* |
@@ -284,15 +310,10 @@ static int sample_sizes[] = { | |||
284 | 24, 32, | 310 | 24, 32, |
285 | }; | 311 | }; |
286 | 312 | ||
287 | static void soc_pcm_apply_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) | ||
289 | { | 314 | { |
290 | int ret, i, bits; | 315 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
291 | 316 | int ret, i; | |
292 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
293 | bits = dai->driver->playback.sig_bits; | ||
294 | else | ||
295 | bits = dai->driver->capture.sig_bits; | ||
296 | 317 | ||
297 | if (!bits) | 318 | if (!bits) |
298 | return; | 319 | return; |
@@ -304,38 +325,105 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream, | |||
304 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, | 325 | ret = snd_pcm_hw_constraint_msbits(substream->runtime, 0, |
305 | sample_sizes[i], bits); | 326 | sample_sizes[i], bits); |
306 | if (ret != 0) | 327 | if (ret != 0) |
307 | dev_warn(dai->dev, | 328 | dev_warn(rtd->dev, |
308 | "ASoC: Failed to set MSB %d/%d: %d\n", | 329 | "ASoC: Failed to set MSB %d/%d: %d\n", |
309 | bits, sample_sizes[i], ret); | 330 | bits, sample_sizes[i], ret); |
310 | } | 331 | } |
311 | } | 332 | } |
312 | 333 | ||
313 | static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime, | 334 | static void soc_pcm_apply_msb(struct snd_pcm_substream *substream) |
314 | struct snd_soc_pcm_stream *codec_stream, | 335 | { |
315 | struct snd_soc_pcm_stream *cpu_stream) | 336 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
337 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
338 | struct snd_soc_dai *codec_dai; | ||
339 | int i; | ||
340 | unsigned int bits = 0, cpu_bits; | ||
341 | |||
342 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
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 | } | ||
351 | cpu_bits = cpu_dai->driver->playback.sig_bits; | ||
352 | } else { | ||
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 | } | ||
361 | cpu_bits = cpu_dai->driver->capture.sig_bits; | ||
362 | } | ||
363 | |||
364 | soc_pcm_set_msb(substream, bits); | ||
365 | soc_pcm_set_msb(substream, cpu_bits); | ||
366 | } | ||
367 | |||
368 | static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) | ||
316 | { | 369 | { |
370 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
317 | 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; | ||
318 | 382 | ||
319 | hw->channels_min = max(codec_stream->channels_min, | 383 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
320 | cpu_stream->channels_min); | 384 | cpu_stream = &cpu_dai_drv->playback; |
321 | hw->channels_max = min(codec_stream->channels_max, | ||
322 | cpu_stream->channels_max); | ||
323 | if (hw->formats) | ||
324 | hw->formats &= codec_stream->formats & cpu_stream->formats; | ||
325 | else | 385 | else |
326 | hw->formats = codec_stream->formats & cpu_stream->formats; | 386 | cpu_stream = &cpu_dai_drv->capture; |
327 | hw->rates = snd_pcm_rate_mask_intersect(codec_stream->rates, | ||
328 | cpu_stream->rates); | ||
329 | 387 | ||
330 | hw->rate_min = 0; | 388 | /* first calculate min/max only for CODECs in the DAI link */ |
331 | 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); | ||
332 | 420 | ||
333 | snd_pcm_limit_hw_rates(runtime); | 421 | snd_pcm_limit_hw_rates(runtime); |
334 | 422 | ||
335 | hw->rate_min = max(hw->rate_min, cpu_stream->rate_min); | 423 | hw->rate_min = max(hw->rate_min, cpu_stream->rate_min); |
336 | hw->rate_min = max(hw->rate_min, codec_stream->rate_min); | 424 | hw->rate_min = max(hw->rate_min, rate_min); |
337 | 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); |
338 | 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); |
339 | } | 427 | } |
340 | 428 | ||
341 | /* | 429 | /* |
@@ -349,15 +437,16 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
349 | struct snd_pcm_runtime *runtime = substream->runtime; | 437 | struct snd_pcm_runtime *runtime = substream->runtime; |
350 | struct snd_soc_platform *platform = rtd->platform; | 438 | struct snd_soc_platform *platform = rtd->platform; |
351 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 439 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
352 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 440 | struct snd_soc_dai *codec_dai; |
353 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | 441 | const char *codec_dai_name = "multicodec"; |
354 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; | 442 | int i, ret = 0; |
355 | int ret = 0; | ||
356 | 443 | ||
357 | pinctrl_pm_select_default_state(cpu_dai->dev); | 444 | pinctrl_pm_select_default_state(cpu_dai->dev); |
358 | 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); | ||
359 | pm_runtime_get_sync(cpu_dai->dev); | 447 | pm_runtime_get_sync(cpu_dai->dev); |
360 | 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); | ||
361 | pm_runtime_get_sync(platform->dev); | 450 | pm_runtime_get_sync(platform->dev); |
362 | 451 | ||
363 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 452 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
@@ -376,18 +465,28 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
376 | ret = platform->driver->ops->open(substream); | 465 | ret = platform->driver->ops->open(substream); |
377 | if (ret < 0) { | 466 | if (ret < 0) { |
378 | dev_err(platform->dev, "ASoC: can't open platform" | 467 | dev_err(platform->dev, "ASoC: can't open platform" |
379 | " %s: %d\n", platform->name, ret); | 468 | " %s: %d\n", platform->component.name, ret); |
380 | goto platform_err; | 469 | goto platform_err; |
381 | } | 470 | } |
382 | } | 471 | } |
383 | 472 | ||
384 | if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { | 473 | for (i = 0; i < rtd->num_codecs; i++) { |
385 | ret = codec_dai->driver->ops->startup(substream, codec_dai); | 474 | codec_dai = rtd->codec_dais[i]; |
386 | if (ret < 0) { | 475 | if (codec_dai->driver->ops && codec_dai->driver->ops->startup) { |
387 | dev_err(codec_dai->dev, "ASoC: can't open codec" | 476 | ret = codec_dai->driver->ops->startup(substream, |
388 | " %s: %d\n", codec_dai->name, ret); | 477 | codec_dai); |
389 | 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 | } | ||
390 | } | 484 | } |
485 | |||
486 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
487 | codec_dai->tx_mask = 0; | ||
488 | else | ||
489 | codec_dai->rx_mask = 0; | ||
391 | } | 490 | } |
392 | 491 | ||
393 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { | 492 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { |
@@ -404,13 +503,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
404 | goto dynamic; | 503 | goto dynamic; |
405 | 504 | ||
406 | /* Check that the codec and cpu DAIs are compatible */ | 505 | /* Check that the codec and cpu DAIs are compatible */ |
407 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 506 | soc_pcm_init_runtime_hw(substream); |
408 | soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback, | 507 | |
409 | &cpu_dai_drv->playback); | 508 | if (rtd->num_codecs == 1) |
410 | } else { | 509 | codec_dai_name = rtd->codec_dai->name; |
411 | soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture, | ||
412 | &cpu_dai_drv->capture); | ||
413 | } | ||
414 | 510 | ||
415 | if (soc_pcm_has_symmetry(substream)) | 511 | if (soc_pcm_has_symmetry(substream)) |
416 | runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; | 512 | runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; |
@@ -418,23 +514,22 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
418 | ret = -EINVAL; | 514 | ret = -EINVAL; |
419 | if (!runtime->hw.rates) { | 515 | if (!runtime->hw.rates) { |
420 | printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", | 516 | printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", |
421 | codec_dai->name, cpu_dai->name); | 517 | codec_dai_name, cpu_dai->name); |
422 | goto config_err; | 518 | goto config_err; |
423 | } | 519 | } |
424 | if (!runtime->hw.formats) { | 520 | if (!runtime->hw.formats) { |
425 | printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", | 521 | printk(KERN_ERR "ASoC: %s <-> %s No matching formats\n", |
426 | codec_dai->name, cpu_dai->name); | 522 | codec_dai_name, cpu_dai->name); |
427 | goto config_err; | 523 | goto config_err; |
428 | } | 524 | } |
429 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || | 525 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || |
430 | runtime->hw.channels_min > runtime->hw.channels_max) { | 526 | runtime->hw.channels_min > runtime->hw.channels_max) { |
431 | printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", | 527 | printk(KERN_ERR "ASoC: %s <-> %s No matching channels\n", |
432 | codec_dai->name, cpu_dai->name); | 528 | codec_dai_name, cpu_dai->name); |
433 | goto config_err; | 529 | goto config_err; |
434 | } | 530 | } |
435 | 531 | ||
436 | soc_pcm_apply_msb(substream, codec_dai); | 532 | soc_pcm_apply_msb(substream); |
437 | soc_pcm_apply_msb(substream, cpu_dai); | ||
438 | 533 | ||
439 | /* Symmetry only applies if we've already got an active stream. */ | 534 | /* Symmetry only applies if we've already got an active stream. */ |
440 | if (cpu_dai->active) { | 535 | if (cpu_dai->active) { |
@@ -443,14 +538,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
443 | goto config_err; | 538 | goto config_err; |
444 | } | 539 | } |
445 | 540 | ||
446 | if (codec_dai->active) { | 541 | for (i = 0; i < rtd->num_codecs; i++) { |
447 | ret = soc_pcm_apply_symmetry(substream, codec_dai); | 542 | if (rtd->codec_dais[i]->active) { |
448 | if (ret != 0) | 543 | ret = soc_pcm_apply_symmetry(substream, |
449 | goto config_err; | 544 | rtd->codec_dais[i]); |
545 | if (ret != 0) | ||
546 | goto config_err; | ||
547 | } | ||
450 | } | 548 | } |
451 | 549 | ||
452 | pr_debug("ASoC: %s <-> %s info:\n", | 550 | pr_debug("ASoC: %s <-> %s info:\n", |
453 | codec_dai->name, cpu_dai->name); | 551 | codec_dai_name, cpu_dai->name); |
454 | pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); | 552 | pr_debug("ASoC: rate mask 0x%x\n", runtime->hw.rates); |
455 | 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, |
456 | runtime->hw.channels_max); | 554 | runtime->hw.channels_max); |
@@ -469,10 +567,15 @@ config_err: | |||
469 | rtd->dai_link->ops->shutdown(substream); | 567 | rtd->dai_link->ops->shutdown(substream); |
470 | 568 | ||
471 | machine_err: | 569 | machine_err: |
472 | if (codec_dai->driver->ops->shutdown) | 570 | i = rtd->num_codecs; |
473 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
474 | 571 | ||
475 | 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 | |||
476 | if (platform->driver->ops && platform->driver->ops->close) | 579 | if (platform->driver->ops && platform->driver->ops->close) |
477 | platform->driver->ops->close(substream); | 580 | platform->driver->ops->close(substream); |
478 | 581 | ||
@@ -483,10 +586,13 @@ out: | |||
483 | mutex_unlock(&rtd->pcm_mutex); | 586 | mutex_unlock(&rtd->pcm_mutex); |
484 | 587 | ||
485 | pm_runtime_put(platform->dev); | 588 | pm_runtime_put(platform->dev); |
486 | pm_runtime_put(codec_dai->dev); | 589 | for (i = 0; i < rtd->num_codecs; i++) |
590 | pm_runtime_put(rtd->codec_dais[i]->dev); | ||
487 | pm_runtime_put(cpu_dai->dev); | 591 | pm_runtime_put(cpu_dai->dev); |
488 | if (!codec_dai->active) | 592 | for (i = 0; i < rtd->num_codecs; i++) { |
489 | 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 | } | ||
490 | if (!cpu_dai->active) | 596 | if (!cpu_dai->active) |
491 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 597 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
492 | 598 | ||
@@ -502,7 +608,7 @@ static void close_delayed_work(struct work_struct *work) | |||
502 | { | 608 | { |
503 | struct snd_soc_pcm_runtime *rtd = | 609 | struct snd_soc_pcm_runtime *rtd = |
504 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | 610 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); |
505 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 611 | struct snd_soc_dai *codec_dai = rtd->codec_dais[0]; |
506 | 612 | ||
507 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 613 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
508 | 614 | ||
@@ -531,7 +637,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
531 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 637 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
532 | struct snd_soc_platform *platform = rtd->platform; | 638 | struct snd_soc_platform *platform = rtd->platform; |
533 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 639 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
534 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 640 | struct snd_soc_dai *codec_dai; |
641 | int i; | ||
535 | 642 | ||
536 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 643 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
537 | 644 | ||
@@ -541,14 +648,20 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
541 | if (!cpu_dai->active) | 648 | if (!cpu_dai->active) |
542 | cpu_dai->rate = 0; | 649 | cpu_dai->rate = 0; |
543 | 650 | ||
544 | if (!codec_dai->active) | 651 | for (i = 0; i < rtd->num_codecs; i++) { |
545 | codec_dai->rate = 0; | 652 | codec_dai = rtd->codec_dais[i]; |
653 | if (!codec_dai->active) | ||
654 | codec_dai->rate = 0; | ||
655 | } | ||
546 | 656 | ||
547 | if (cpu_dai->driver->ops->shutdown) | 657 | if (cpu_dai->driver->ops->shutdown) |
548 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 658 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
549 | 659 | ||
550 | if (codec_dai->driver->ops->shutdown) | 660 | for (i = 0; i < rtd->num_codecs; i++) { |
551 | 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 | } | ||
552 | 665 | ||
553 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | 666 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) |
554 | rtd->dai_link->ops->shutdown(substream); | 667 | rtd->dai_link->ops->shutdown(substream); |
@@ -578,10 +691,13 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
578 | mutex_unlock(&rtd->pcm_mutex); | 691 | mutex_unlock(&rtd->pcm_mutex); |
579 | 692 | ||
580 | pm_runtime_put(platform->dev); | 693 | pm_runtime_put(platform->dev); |
581 | pm_runtime_put(codec_dai->dev); | 694 | for (i = 0; i < rtd->num_codecs; i++) |
695 | pm_runtime_put(rtd->codec_dais[i]->dev); | ||
582 | pm_runtime_put(cpu_dai->dev); | 696 | pm_runtime_put(cpu_dai->dev); |
583 | if (!codec_dai->active) | 697 | for (i = 0; i < rtd->num_codecs; i++) { |
584 | 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 | } | ||
585 | if (!cpu_dai->active) | 701 | if (!cpu_dai->active) |
586 | pinctrl_pm_select_sleep_state(cpu_dai->dev); | 702 | pinctrl_pm_select_sleep_state(cpu_dai->dev); |
587 | 703 | ||
@@ -598,8 +714,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
598 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 714 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
599 | struct snd_soc_platform *platform = rtd->platform; | 715 | struct snd_soc_platform *platform = rtd->platform; |
600 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 716 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
601 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 717 | struct snd_soc_dai *codec_dai; |
602 | int ret = 0; | 718 | int i, ret = 0; |
603 | 719 | ||
604 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 720 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
605 | 721 | ||
@@ -621,12 +737,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
621 | } | 737 | } |
622 | } | 738 | } |
623 | 739 | ||
624 | if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { | 740 | for (i = 0; i < rtd->num_codecs; i++) { |
625 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); | 741 | codec_dai = rtd->codec_dais[i]; |
626 | if (ret < 0) { | 742 | if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { |
627 | dev_err(codec_dai->dev, "ASoC: DAI prepare error: %d\n", | 743 | ret = codec_dai->driver->ops->prepare(substream, |
628 | ret); | 744 | codec_dai); |
629 | goto out; | 745 | if (ret < 0) { |
746 | dev_err(codec_dai->dev, | ||
747 | "ASoC: DAI prepare error: %d\n", ret); | ||
748 | goto out; | ||
749 | } | ||
630 | } | 750 | } |
631 | } | 751 | } |
632 | 752 | ||
@@ -649,13 +769,44 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
649 | snd_soc_dapm_stream_event(rtd, substream->stream, | 769 | snd_soc_dapm_stream_event(rtd, substream->stream, |
650 | SND_SOC_DAPM_STREAM_START); | 770 | SND_SOC_DAPM_STREAM_START); |
651 | 771 | ||
652 | 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); | ||
653 | 775 | ||
654 | out: | 776 | out: |
655 | mutex_unlock(&rtd->pcm_mutex); | 777 | mutex_unlock(&rtd->pcm_mutex); |
656 | return ret; | 778 | return ret; |
657 | } | 779 | } |
658 | 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 | |||
792 | int soc_dai_hw_params(struct snd_pcm_substream *substream, | ||
793 | struct snd_pcm_hw_params *params, | ||
794 | struct snd_soc_dai *dai) | ||
795 | { | ||
796 | int ret; | ||
797 | |||
798 | if (dai->driver->ops && dai->driver->ops->hw_params) { | ||
799 | ret = dai->driver->ops->hw_params(substream, params, dai); | ||
800 | if (ret < 0) { | ||
801 | dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n", | ||
802 | dai->name, ret); | ||
803 | return ret; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
659 | /* | 810 | /* |
660 | * Called by ALSA when the hardware params are set by application. This | 811 | * Called by ALSA when the hardware params are set by application. This |
661 | * function can also be called multiple times and can allocate buffers | 812 | * function can also be called multiple times and can allocate buffers |
@@ -667,8 +818,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
667 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 818 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
668 | struct snd_soc_platform *platform = rtd->platform; | 819 | struct snd_soc_platform *platform = rtd->platform; |
669 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 820 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
670 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 821 | int i, ret = 0; |
671 | int ret = 0; | ||
672 | 822 | ||
673 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 823 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
674 | 824 | ||
@@ -685,29 +835,40 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
685 | } | 835 | } |
686 | } | 836 | } |
687 | 837 | ||
688 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_params) { | 838 | for (i = 0; i < rtd->num_codecs; i++) { |
689 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); | 839 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
690 | if (ret < 0) { | 840 | struct snd_pcm_hw_params codec_params; |
691 | dev_err(codec_dai->dev, "ASoC: can't set %s hw params:" | 841 | |
692 | " %d\n", codec_dai->name, ret); | 842 | /* copy params for each codec */ |
843 | codec_params = *params; | ||
844 | |||
845 | /* fixup params based on TDM slot masks */ | ||
846 | if (codec_dai->tx_mask) | ||
847 | soc_pcm_codec_params_fixup(&codec_params, | ||
848 | codec_dai->tx_mask); | ||
849 | if (codec_dai->rx_mask) | ||
850 | soc_pcm_codec_params_fixup(&codec_params, | ||
851 | codec_dai->rx_mask); | ||
852 | |||
853 | ret = soc_dai_hw_params(substream, &codec_params, codec_dai); | ||
854 | if(ret < 0) | ||
693 | goto codec_err; | 855 | goto codec_err; |
694 | } | ||
695 | } | ||
696 | 856 | ||
697 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_params) { | 857 | codec_dai->rate = params_rate(&codec_params); |
698 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); | 858 | codec_dai->channels = params_channels(&codec_params); |
699 | if (ret < 0) { | 859 | codec_dai->sample_bits = snd_pcm_format_physical_width( |
700 | dev_err(cpu_dai->dev, "ASoC: %s hw params failed: %d\n", | 860 | params_format(&codec_params)); |
701 | cpu_dai->name, ret); | ||
702 | goto interface_err; | ||
703 | } | ||
704 | } | 861 | } |
705 | 862 | ||
863 | ret = soc_dai_hw_params(substream, params, cpu_dai); | ||
864 | if (ret < 0) | ||
865 | goto interface_err; | ||
866 | |||
706 | if (platform->driver->ops && platform->driver->ops->hw_params) { | 867 | if (platform->driver->ops && platform->driver->ops->hw_params) { |
707 | ret = platform->driver->ops->hw_params(substream, params); | 868 | ret = platform->driver->ops->hw_params(substream, params); |
708 | if (ret < 0) { | 869 | if (ret < 0) { |
709 | dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", | 870 | dev_err(platform->dev, "ASoC: %s hw params failed: %d\n", |
710 | platform->name, ret); | 871 | platform->component.name, ret); |
711 | goto platform_err; | 872 | goto platform_err; |
712 | } | 873 | } |
713 | } | 874 | } |
@@ -718,11 +879,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
718 | cpu_dai->sample_bits = | 879 | cpu_dai->sample_bits = |
719 | snd_pcm_format_physical_width(params_format(params)); | 880 | snd_pcm_format_physical_width(params_format(params)); |
720 | 881 | ||
721 | codec_dai->rate = params_rate(params); | ||
722 | codec_dai->channels = params_channels(params); | ||
723 | codec_dai->sample_bits = | ||
724 | snd_pcm_format_physical_width(params_format(params)); | ||
725 | |||
726 | out: | 882 | out: |
727 | mutex_unlock(&rtd->pcm_mutex); | 883 | mutex_unlock(&rtd->pcm_mutex); |
728 | return ret; | 884 | return ret; |
@@ -732,10 +888,16 @@ platform_err: | |||
732 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 888 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
733 | 889 | ||
734 | interface_err: | 890 | interface_err: |
735 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | 891 | i = rtd->num_codecs; |
736 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
737 | 892 | ||
738 | codec_err: | 893 | codec_err: |
894 | while (--i >= 0) { | ||
895 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; | ||
896 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | ||
897 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
898 | codec_dai->rate = 0; | ||
899 | } | ||
900 | |||
739 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 901 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
740 | rtd->dai_link->ops->hw_free(substream); | 902 | rtd->dai_link->ops->hw_free(substream); |
741 | 903 | ||
@@ -751,8 +913,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
751 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 913 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
752 | struct snd_soc_platform *platform = rtd->platform; | 914 | struct snd_soc_platform *platform = rtd->platform; |
753 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 915 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
754 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 916 | struct snd_soc_dai *codec_dai; |
755 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 917 | bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
918 | int i; | ||
756 | 919 | ||
757 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 920 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
758 | 921 | ||
@@ -763,16 +926,22 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
763 | cpu_dai->sample_bits = 0; | 926 | cpu_dai->sample_bits = 0; |
764 | } | 927 | } |
765 | 928 | ||
766 | if (codec_dai->active == 1) { | 929 | for (i = 0; i < rtd->num_codecs; i++) { |
767 | codec_dai->rate = 0; | 930 | codec_dai = rtd->codec_dais[i]; |
768 | codec_dai->channels = 0; | 931 | if (codec_dai->active == 1) { |
769 | codec_dai->sample_bits = 0; | 932 | codec_dai->rate = 0; |
933 | codec_dai->channels = 0; | ||
934 | codec_dai->sample_bits = 0; | ||
935 | } | ||
770 | } | 936 | } |
771 | 937 | ||
772 | /* apply codec digital mute */ | 938 | /* apply codec digital mute */ |
773 | if ((playback && codec_dai->playback_active == 1) || | 939 | for (i = 0; i < rtd->num_codecs; i++) { |
774 | (!playback && codec_dai->capture_active == 1)) | 940 | if ((playback && rtd->codec_dais[i]->playback_active == 1) || |
775 | snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); | 941 | (!playback && rtd->codec_dais[i]->capture_active == 1)) |
942 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 1, | ||
943 | substream->stream); | ||
944 | } | ||
776 | 945 | ||
777 | /* free any machine hw params */ | 946 | /* free any machine hw params */ |
778 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | 947 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) |
@@ -783,8 +952,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | |||
783 | platform->driver->ops->hw_free(substream); | 952 | platform->driver->ops->hw_free(substream); |
784 | 953 | ||
785 | /* now free hw params for the DAIs */ | 954 | /* now free hw params for the DAIs */ |
786 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | 955 | for (i = 0; i < rtd->num_codecs; i++) { |
787 | codec_dai->driver->ops->hw_free(substream, codec_dai); | 956 | codec_dai = rtd->codec_dais[i]; |
957 | if (codec_dai->driver->ops && codec_dai->driver->ops->hw_free) | ||
958 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
959 | } | ||
788 | 960 | ||
789 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) | 961 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->hw_free) |
790 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | 962 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); |
@@ -798,13 +970,17 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
798 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 970 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
799 | struct snd_soc_platform *platform = rtd->platform; | 971 | struct snd_soc_platform *platform = rtd->platform; |
800 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 972 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
801 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 973 | struct snd_soc_dai *codec_dai; |
802 | int ret; | 974 | int i, ret; |
803 | 975 | ||
804 | if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { | 976 | for (i = 0; i < rtd->num_codecs; i++) { |
805 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); | 977 | codec_dai = rtd->codec_dais[i]; |
806 | if (ret < 0) | 978 | if (codec_dai->driver->ops && codec_dai->driver->ops->trigger) { |
807 | return ret; | 979 | ret = codec_dai->driver->ops->trigger(substream, |
980 | cmd, codec_dai); | ||
981 | if (ret < 0) | ||
982 | return ret; | ||
983 | } | ||
808 | } | 984 | } |
809 | 985 | ||
810 | if (platform->driver->ops && platform->driver->ops->trigger) { | 986 | if (platform->driver->ops && platform->driver->ops->trigger) { |
@@ -834,14 +1010,18 @@ static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream, | |||
834 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1010 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
835 | struct snd_soc_platform *platform = rtd->platform; | 1011 | struct snd_soc_platform *platform = rtd->platform; |
836 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1012 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
837 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 1013 | struct snd_soc_dai *codec_dai; |
838 | int ret; | 1014 | int i, ret; |
839 | 1015 | ||
840 | if (codec_dai->driver->ops && | 1016 | for (i = 0; i < rtd->num_codecs; i++) { |
841 | codec_dai->driver->ops->bespoke_trigger) { | 1017 | codec_dai = rtd->codec_dais[i]; |
842 | ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai); | 1018 | if (codec_dai->driver->ops && |
843 | if (ret < 0) | 1019 | codec_dai->driver->ops->bespoke_trigger) { |
844 | return ret; | 1020 | ret = codec_dai->driver->ops->bespoke_trigger(substream, |
1021 | cmd, codec_dai); | ||
1022 | if (ret < 0) | ||
1023 | return ret; | ||
1024 | } | ||
845 | } | 1025 | } |
846 | 1026 | ||
847 | if (platform->driver->bespoke_trigger) { | 1027 | if (platform->driver->bespoke_trigger) { |
@@ -867,10 +1047,12 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | |||
867 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1047 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
868 | struct snd_soc_platform *platform = rtd->platform; | 1048 | struct snd_soc_platform *platform = rtd->platform; |
869 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1049 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
870 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 1050 | struct snd_soc_dai *codec_dai; |
871 | struct snd_pcm_runtime *runtime = substream->runtime; | 1051 | struct snd_pcm_runtime *runtime = substream->runtime; |
872 | snd_pcm_uframes_t offset = 0; | 1052 | snd_pcm_uframes_t offset = 0; |
873 | snd_pcm_sframes_t delay = 0; | 1053 | snd_pcm_sframes_t delay = 0; |
1054 | snd_pcm_sframes_t codec_delay = 0; | ||
1055 | int i; | ||
874 | 1056 | ||
875 | if (platform->driver->ops && platform->driver->ops->pointer) | 1057 | if (platform->driver->ops && platform->driver->ops->pointer) |
876 | offset = platform->driver->ops->pointer(substream); | 1058 | offset = platform->driver->ops->pointer(substream); |
@@ -878,11 +1060,21 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | |||
878 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) | 1060 | if (cpu_dai->driver->ops && cpu_dai->driver->ops->delay) |
879 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); | 1061 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); |
880 | 1062 | ||
881 | if (codec_dai->driver->ops && codec_dai->driver->ops->delay) | 1063 | for (i = 0; i < rtd->num_codecs; i++) { |
882 | delay += codec_dai->driver->ops->delay(substream, codec_dai); | 1064 | codec_dai = rtd->codec_dais[i]; |
1065 | if (codec_dai->driver->ops && codec_dai->driver->ops->delay) | ||
1066 | codec_delay = max(codec_delay, | ||
1067 | codec_dai->driver->ops->delay(substream, | ||
1068 | codec_dai)); | ||
1069 | } | ||
1070 | delay += codec_delay; | ||
883 | 1071 | ||
1072 | /* | ||
1073 | * None of the existing platform drivers implement delay(), so | ||
1074 | * for now the codec_dai of first multicodec entry is used | ||
1075 | */ | ||
884 | if (platform->driver->delay) | 1076 | if (platform->driver->delay) |
885 | delay += platform->driver->delay(substream, codec_dai); | 1077 | delay += platform->driver->delay(substream, rtd->codec_dais[0]); |
886 | 1078 | ||
887 | runtime->delay = delay; | 1079 | runtime->delay = delay; |
888 | 1080 | ||
@@ -985,7 +1177,7 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
985 | struct snd_soc_dapm_widget *widget, int stream) | 1177 | struct snd_soc_dapm_widget *widget, int stream) |
986 | { | 1178 | { |
987 | struct snd_soc_pcm_runtime *be; | 1179 | struct snd_soc_pcm_runtime *be; |
988 | int i; | 1180 | int i, j; |
989 | 1181 | ||
990 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1182 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
991 | for (i = 0; i < card->num_links; i++) { | 1183 | for (i = 0; i < card->num_links; i++) { |
@@ -994,9 +1186,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
994 | if (!be->dai_link->no_pcm) | 1186 | if (!be->dai_link->no_pcm) |
995 | continue; | 1187 | continue; |
996 | 1188 | ||
997 | if (be->cpu_dai->playback_widget == widget || | 1189 | if (be->cpu_dai->playback_widget == widget) |
998 | be->codec_dai->playback_widget == widget) | ||
999 | return be; | 1190 | return be; |
1191 | |||
1192 | for (j = 0; j < be->num_codecs; j++) { | ||
1193 | struct snd_soc_dai *dai = be->codec_dais[j]; | ||
1194 | if (dai->playback_widget == widget) | ||
1195 | return be; | ||
1196 | } | ||
1000 | } | 1197 | } |
1001 | } else { | 1198 | } else { |
1002 | 1199 | ||
@@ -1006,9 +1203,14 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, | |||
1006 | if (!be->dai_link->no_pcm) | 1203 | if (!be->dai_link->no_pcm) |
1007 | continue; | 1204 | continue; |
1008 | 1205 | ||
1009 | if (be->cpu_dai->capture_widget == widget || | 1206 | if (be->cpu_dai->capture_widget == widget) |
1010 | be->codec_dai->capture_widget == widget) | ||
1011 | return be; | 1207 | return be; |
1208 | |||
1209 | for (j = 0; j < be->num_codecs; j++) { | ||
1210 | struct snd_soc_dai *dai = be->codec_dais[j]; | ||
1211 | if (dai->capture_widget == widget) | ||
1212 | return be; | ||
1213 | } | ||
1012 | } | 1214 | } |
1013 | } | 1215 | } |
1014 | 1216 | ||
@@ -1071,6 +1273,7 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | |||
1071 | 1273 | ||
1072 | /* Destroy any old FE <--> BE connections */ | 1274 | /* Destroy any old FE <--> BE connections */ |
1073 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { | 1275 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { |
1276 | unsigned int i; | ||
1074 | 1277 | ||
1075 | /* is there a valid CPU DAI widget for this BE */ | 1278 | /* is there a valid CPU DAI widget for this BE */ |
1076 | widget = dai_get_widget(dpcm->be->cpu_dai, stream); | 1279 | widget = dai_get_widget(dpcm->be->cpu_dai, stream); |
@@ -1080,11 +1283,14 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, | |||
1080 | continue; | 1283 | continue; |
1081 | 1284 | ||
1082 | /* is there a valid CODEC DAI widget for this BE */ | 1285 | /* is there a valid CODEC DAI widget for this BE */ |
1083 | widget = dai_get_widget(dpcm->be->codec_dai, stream); | 1286 | for (i = 0; i < dpcm->be->num_codecs; i++) { |
1287 | struct snd_soc_dai *dai = dpcm->be->codec_dais[i]; | ||
1288 | widget = dai_get_widget(dai, stream); | ||
1084 | 1289 | ||
1085 | /* prune the BE if it's no longer in our active list */ | 1290 | /* prune the BE if it's no longer in our active list */ |
1086 | if (widget && widget_in_list(list, widget)) | 1291 | if (widget && widget_in_list(list, widget)) |
1087 | continue; | 1292 | continue; |
1293 | } | ||
1088 | 1294 | ||
1089 | dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", | 1295 | dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n", |
1090 | stream ? "capture" : "playback", | 1296 | stream ? "capture" : "playback", |
@@ -2069,6 +2275,7 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) | |||
2069 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); | 2275 | dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK); |
2070 | } | 2276 | } |
2071 | 2277 | ||
2278 | dpcm_path_put(&list); | ||
2072 | capture: | 2279 | capture: |
2073 | /* skip if FE doesn't have capture capability */ | 2280 | /* skip if FE doesn't have capture capability */ |
2074 | if (!fe->cpu_dai->driver->capture.channels_min) | 2281 | if (!fe->cpu_dai->driver->capture.channels_min) |
@@ -2113,16 +2320,22 @@ int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute) | |||
2113 | list_for_each_entry(dpcm, clients, list_be) { | 2320 | list_for_each_entry(dpcm, clients, list_be) { |
2114 | 2321 | ||
2115 | struct snd_soc_pcm_runtime *be = dpcm->be; | 2322 | struct snd_soc_pcm_runtime *be = dpcm->be; |
2116 | struct snd_soc_dai *dai = be->codec_dai; | 2323 | int i; |
2117 | struct snd_soc_dai_driver *drv = dai->driver; | ||
2118 | 2324 | ||
2119 | if (be->dai_link->ignore_suspend) | 2325 | if (be->dai_link->ignore_suspend) |
2120 | continue; | 2326 | continue; |
2121 | 2327 | ||
2122 | dev_dbg(be->dev, "ASoC: BE digital mute %s\n", be->dai_link->name); | 2328 | for (i = 0; i < be->num_codecs; i++) { |
2329 | struct snd_soc_dai *dai = be->codec_dais[i]; | ||
2330 | struct snd_soc_dai_driver *drv = dai->driver; | ||
2331 | |||
2332 | dev_dbg(be->dev, "ASoC: BE digital mute %s\n", | ||
2333 | be->dai_link->name); | ||
2123 | 2334 | ||
2124 | if (drv->ops && drv->ops->digital_mute && dai->playback_active) | 2335 | if (drv->ops && drv->ops->digital_mute && |
2125 | drv->ops->digital_mute(dai, mute); | 2336 | dai->playback_active) |
2337 | drv->ops->digital_mute(dai, mute); | ||
2338 | } | ||
2126 | } | 2339 | } |
2127 | 2340 | ||
2128 | return 0; | 2341 | return 0; |
@@ -2187,22 +2400,27 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) | |||
2187 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | 2400 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
2188 | { | 2401 | { |
2189 | struct snd_soc_platform *platform = rtd->platform; | 2402 | struct snd_soc_platform *platform = rtd->platform; |
2190 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 2403 | struct snd_soc_dai *codec_dai; |
2191 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 2404 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
2192 | struct snd_pcm *pcm; | 2405 | struct snd_pcm *pcm; |
2193 | char new_name[64]; | 2406 | char new_name[64]; |
2194 | int ret = 0, playback = 0, capture = 0; | 2407 | int ret = 0, playback = 0, capture = 0; |
2408 | int i; | ||
2195 | 2409 | ||
2196 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { | 2410 | if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) { |
2197 | playback = rtd->dai_link->dpcm_playback; | 2411 | playback = rtd->dai_link->dpcm_playback; |
2198 | capture = rtd->dai_link->dpcm_capture; | 2412 | capture = rtd->dai_link->dpcm_capture; |
2199 | } else { | 2413 | } else { |
2200 | if (codec_dai->driver->playback.channels_min && | 2414 | for (i = 0; i < rtd->num_codecs; i++) { |
2201 | cpu_dai->driver->playback.channels_min) | 2415 | codec_dai = rtd->codec_dais[i]; |
2202 | playback = 1; | 2416 | if (codec_dai->driver->playback.channels_min) |
2203 | if (codec_dai->driver->capture.channels_min && | 2417 | playback = 1; |
2204 | cpu_dai->driver->capture.channels_min) | 2418 | if (codec_dai->driver->capture.channels_min) |
2205 | capture = 1; | 2419 | capture = 1; |
2420 | } | ||
2421 | |||
2422 | capture = capture && cpu_dai->driver->capture.channels_min; | ||
2423 | playback = playback && cpu_dai->driver->playback.channels_min; | ||
2206 | } | 2424 | } |
2207 | 2425 | ||
2208 | if (rtd->dai_link->playback_only) { | 2426 | if (rtd->dai_link->playback_only) { |
@@ -2228,7 +2446,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2228 | rtd->dai_link->stream_name); | 2446 | rtd->dai_link->stream_name); |
2229 | else | 2447 | else |
2230 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | 2448 | snprintf(new_name, sizeof(new_name), "%s %s-%d", |
2231 | rtd->dai_link->stream_name, codec_dai->name, num); | 2449 | rtd->dai_link->stream_name, |
2450 | (rtd->num_codecs > 1) ? | ||
2451 | "multicodec" : rtd->codec_dai->name, num); | ||
2232 | 2452 | ||
2233 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, | 2453 | ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback, |
2234 | capture, &pcm); | 2454 | capture, &pcm); |
@@ -2301,8 +2521,9 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2301 | 2521 | ||
2302 | pcm->private_free = platform->driver->pcm_free; | 2522 | pcm->private_free = platform->driver->pcm_free; |
2303 | out: | 2523 | out: |
2304 | dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", codec_dai->name, | 2524 | dev_info(rtd->card->dev, "%s <-> %s mapping ok\n", |
2305 | cpu_dai->name); | 2525 | (rtd->num_codecs > 1) ? "multicodec" : rtd->codec_dai->name, |
2526 | cpu_dai->name); | ||
2306 | return ret; | 2527 | return ret; |
2307 | } | 2528 | } |
2308 | 2529 | ||