aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r--sound/soc/soc-pcm.c179
1 files changed, 145 insertions, 34 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 42782c01e413..604e7e9a2ef8 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -84,35 +84,117 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
84 struct snd_soc_pcm_runtime *rtd = substream->private_data; 84 struct snd_soc_pcm_runtime *rtd = substream->private_data;
85 int ret; 85 int ret;
86 86
87 if (!soc_dai->driver->symmetric_rates && 87 if (soc_dai->rate && (soc_dai->driver->symmetric_rates ||
88 !rtd->dai_link->symmetric_rates) 88 rtd->dai_link->symmetric_rates)) {
89 return 0; 89 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n",
90 soc_dai->rate);
91
92 ret = snd_pcm_hw_constraint_minmax(substream->runtime,
93 SNDRV_PCM_HW_PARAM_RATE,
94 soc_dai->rate, soc_dai->rate);
95 if (ret < 0) {
96 dev_err(soc_dai->dev,
97 "ASoC: Unable to apply rate constraint: %d\n",
98 ret);
99 return ret;
100 }
101 }
90 102
91 /* This can happen if multiple streams are starting simultaneously - 103 if (soc_dai->channels && (soc_dai->driver->symmetric_channels ||
92 * the second can need to get its constraints before the first has 104 rtd->dai_link->symmetric_channels)) {
93 * picked a rate. Complain and allow the application to carry on. 105 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d channel(s)\n",
94 */ 106 soc_dai->channels);
95 if (!soc_dai->rate) { 107
96 dev_warn(soc_dai->dev, 108 ret = snd_pcm_hw_constraint_minmax(substream->runtime,
97 "ASoC: Not enforcing symmetric_rates due to race\n"); 109 SNDRV_PCM_HW_PARAM_CHANNELS,
98 return 0; 110 soc_dai->channels,
111 soc_dai->channels);
112 if (ret < 0) {
113 dev_err(soc_dai->dev,
114 "ASoC: Unable to apply channel symmetry constraint: %d\n",
115 ret);
116 return ret;
117 }
99 } 118 }
100 119
101 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %dHz rate\n", soc_dai->rate); 120 if (soc_dai->sample_bits && (soc_dai->driver->symmetric_samplebits ||
121 rtd->dai_link->symmetric_samplebits)) {
122 dev_dbg(soc_dai->dev, "ASoC: Symmetry forces %d sample bits\n",
123 soc_dai->sample_bits);
102 124
103 ret = snd_pcm_hw_constraint_minmax(substream->runtime, 125 ret = snd_pcm_hw_constraint_minmax(substream->runtime,
104 SNDRV_PCM_HW_PARAM_RATE, 126 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
105 soc_dai->rate, soc_dai->rate); 127 soc_dai->sample_bits,
106 if (ret < 0) { 128 soc_dai->sample_bits);
107 dev_err(soc_dai->dev, 129 if (ret < 0) {
108 "ASoC: Unable to apply rate symmetry constraint: %d\n", 130 dev_err(soc_dai->dev,
109 ret); 131 "ASoC: Unable to apply sample bits symmetry constraint: %d\n",
110 return ret; 132 ret);
133 return ret;
134 }
111 } 135 }
112 136
113 return 0; 137 return 0;
114} 138}
115 139
140static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
141 struct snd_pcm_hw_params *params)
142{
143 struct snd_soc_pcm_runtime *rtd = substream->private_data;
144 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
145 struct snd_soc_dai *codec_dai = rtd->codec_dai;
146 unsigned int rate, channels, sample_bits, symmetry;
147
148 rate = params_rate(params);
149 channels = params_channels(params);
150 sample_bits = snd_pcm_format_physical_width(params_format(params));
151
152 /* reject unmatched parameters when applying symmetry */
153 symmetry = cpu_dai->driver->symmetric_rates ||
154 codec_dai->driver->symmetric_rates ||
155 rtd->dai_link->symmetric_rates;
156 if (symmetry && cpu_dai->rate && cpu_dai->rate != rate) {
157 dev_err(rtd->dev, "ASoC: unmatched rate symmetry: %d - %d\n",
158 cpu_dai->rate, rate);
159 return -EINVAL;
160 }
161
162 symmetry = cpu_dai->driver->symmetric_channels ||
163 codec_dai->driver->symmetric_channels ||
164 rtd->dai_link->symmetric_channels;
165 if (symmetry && cpu_dai->channels && cpu_dai->channels != channels) {
166 dev_err(rtd->dev, "ASoC: unmatched channel symmetry: %d - %d\n",
167 cpu_dai->channels, channels);
168 return -EINVAL;
169 }
170
171 symmetry = cpu_dai->driver->symmetric_samplebits ||
172 codec_dai->driver->symmetric_samplebits ||
173 rtd->dai_link->symmetric_samplebits;
174 if (symmetry && cpu_dai->sample_bits && cpu_dai->sample_bits != sample_bits) {
175 dev_err(rtd->dev, "ASoC: unmatched sample bits symmetry: %d - %d\n",
176 cpu_dai->sample_bits, sample_bits);
177 return -EINVAL;
178 }
179
180 return 0;
181}
182
183static bool soc_pcm_has_symmetry(struct snd_pcm_substream *substream)
184{
185 struct snd_soc_pcm_runtime *rtd = substream->private_data;
186 struct snd_soc_dai_driver *cpu_driver = rtd->cpu_dai->driver;
187 struct snd_soc_dai_driver *codec_driver = rtd->codec_dai->driver;
188 struct snd_soc_dai_link *link = rtd->dai_link;
189
190 return cpu_driver->symmetric_rates || codec_driver->symmetric_rates ||
191 link->symmetric_rates || cpu_driver->symmetric_channels ||
192 codec_driver->symmetric_channels || link->symmetric_channels ||
193 cpu_driver->symmetric_samplebits ||
194 codec_driver->symmetric_samplebits ||
195 link->symmetric_samplebits;
196}
197
116/* 198/*
117 * List of sample sizes that might go over the bus for parameter 199 * List of sample sizes that might go over the bus for parameter
118 * application. There ought to be a wildcard sample size for things 200 * application. There ought to be a wildcard sample size for things
@@ -148,12 +230,12 @@ static void soc_pcm_apply_msb(struct snd_pcm_substream *substream,
148 } 230 }
149} 231}
150 232
151static void soc_pcm_init_runtime_hw(struct snd_pcm_hardware *hw, 233static void soc_pcm_init_runtime_hw(struct snd_pcm_runtime *runtime,
152 struct snd_soc_pcm_stream *codec_stream, 234 struct snd_soc_pcm_stream *codec_stream,
153 struct snd_soc_pcm_stream *cpu_stream) 235 struct snd_soc_pcm_stream *cpu_stream)
154{ 236{
155 hw->rate_min = max(codec_stream->rate_min, cpu_stream->rate_min); 237 struct snd_pcm_hardware *hw = &runtime->hw;
156 hw->rate_max = max(codec_stream->rate_max, cpu_stream->rate_max); 238
157 hw->channels_min = max(codec_stream->channels_min, 239 hw->channels_min = max(codec_stream->channels_min,
158 cpu_stream->channels_min); 240 cpu_stream->channels_min);
159 hw->channels_max = min(codec_stream->channels_max, 241 hw->channels_max = min(codec_stream->channels_max,
@@ -166,6 +248,13 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_hardware *hw,
166 if (cpu_stream->rates 248 if (cpu_stream->rates
167 & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) 249 & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
168 hw->rates |= codec_stream->rates; 250 hw->rates |= codec_stream->rates;
251
252 snd_pcm_limit_hw_rates(runtime);
253
254 hw->rate_min = max(hw->rate_min, cpu_stream->rate_min);
255 hw->rate_min = max(hw->rate_min, codec_stream->rate_min);
256 hw->rate_max = min_not_zero(hw->rate_max, cpu_stream->rate_max);
257 hw->rate_max = min_not_zero(hw->rate_max, codec_stream->rate_max);
169} 258}
170 259
171/* 260/*
@@ -235,15 +324,17 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
235 324
236 /* Check that the codec and cpu DAIs are compatible */ 325 /* Check that the codec and cpu DAIs are compatible */
237 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 326 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
238 soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->playback, 327 soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->playback,
239 &cpu_dai_drv->playback); 328 &cpu_dai_drv->playback);
240 } else { 329 } else {
241 soc_pcm_init_runtime_hw(&runtime->hw, &codec_dai_drv->capture, 330 soc_pcm_init_runtime_hw(runtime, &codec_dai_drv->capture,
242 &cpu_dai_drv->capture); 331 &cpu_dai_drv->capture);
243 } 332 }
244 333
334 if (soc_pcm_has_symmetry(substream))
335 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
336
245 ret = -EINVAL; 337 ret = -EINVAL;
246 snd_pcm_limit_hw_rates(runtime);
247 if (!runtime->hw.rates) { 338 if (!runtime->hw.rates) {
248 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", 339 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
249 codec_dai->name, cpu_dai->name); 340 codec_dai->name, cpu_dai->name);
@@ -390,11 +481,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
390 if (!codec_dai->active) 481 if (!codec_dai->active)
391 codec_dai->rate = 0; 482 codec_dai->rate = 0;
392 483
393 /* Muting the DAC suppresses artifacts caused during digital
394 * shutdown, for example from stopping clocks.
395 */
396 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
397
398 if (cpu_dai->driver->ops->shutdown) 484 if (cpu_dai->driver->ops->shutdown)
399 cpu_dai->driver->ops->shutdown(substream, cpu_dai); 485 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
400 486
@@ -525,6 +611,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
525 611
526 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 612 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
527 613
614 ret = soc_pcm_params_symmetry(substream, params);
615 if (ret)
616 goto out;
617
528 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { 618 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
529 ret = rtd->dai_link->ops->hw_params(substream, params); 619 ret = rtd->dai_link->ops->hw_params(substream, params);
530 if (ret < 0) { 620 if (ret < 0) {
@@ -561,9 +651,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
561 } 651 }
562 } 652 }
563 653
564 /* store the rate for each DAIs */ 654 /* store the parameters for each DAIs */
565 cpu_dai->rate = params_rate(params); 655 cpu_dai->rate = params_rate(params);
656 cpu_dai->channels = params_channels(params);
657 cpu_dai->sample_bits =
658 snd_pcm_format_physical_width(params_format(params));
659
566 codec_dai->rate = params_rate(params); 660 codec_dai->rate = params_rate(params);
661 codec_dai->channels = params_channels(params);
662 codec_dai->sample_bits =
663 snd_pcm_format_physical_width(params_format(params));
567 664
568out: 665out:
569 mutex_unlock(&rtd->pcm_mutex); 666 mutex_unlock(&rtd->pcm_mutex);
@@ -594,12 +691,26 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
594 struct snd_soc_platform *platform = rtd->platform; 691 struct snd_soc_platform *platform = rtd->platform;
595 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 692 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
596 struct snd_soc_dai *codec_dai = rtd->codec_dai; 693 struct snd_soc_dai *codec_dai = rtd->codec_dai;
597 struct snd_soc_codec *codec = rtd->codec; 694 bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
598 695
599 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 696 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
600 697
698 /* clear the corresponding DAIs parameters when going to be inactive */
699 if (cpu_dai->active == 1) {
700 cpu_dai->rate = 0;
701 cpu_dai->channels = 0;
702 cpu_dai->sample_bits = 0;
703 }
704
705 if (codec_dai->active == 1) {
706 codec_dai->rate = 0;
707 codec_dai->channels = 0;
708 codec_dai->sample_bits = 0;
709 }
710
601 /* apply codec digital mute */ 711 /* apply codec digital mute */
602 if (!codec->active) 712 if ((playback && codec_dai->playback_active == 1) ||
713 (!playback && codec_dai->capture_active == 1))
603 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); 714 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
604 715
605 /* free any machine hw params */ 716 /* free any machine hw params */