aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-pcm.c
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2014-01-02 08:01:50 -0500
committerMark Brown <broonie@linaro.org>2014-01-02 08:01:50 -0500
commit729b47a007345d0af214f7f64a784c6bb3ad4832 (patch)
treed7e7a2f28dd07f7106c6eec1f44ca637cdf22614 /sound/soc/soc-pcm.c
parent30010a279657144f7de0a94f89896e4e2d3bbb75 (diff)
parente41975edc73d2c16d0784e5fa87a6162e2fcab80 (diff)
Merge remote-tracking branch 'asoc/topic/core' into asoc-next
Diffstat (limited to 'sound/soc/soc-pcm.c')
-rw-r--r--sound/soc/soc-pcm.c156
1 files changed, 130 insertions, 26 deletions
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 891b9a9bcbf8..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
@@ -249,6 +331,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
249 &cpu_dai_drv->capture); 331 &cpu_dai_drv->capture);
250 } 332 }
251 333
334 if (soc_pcm_has_symmetry(substream))
335 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
336
252 ret = -EINVAL; 337 ret = -EINVAL;
253 if (!runtime->hw.rates) { 338 if (!runtime->hw.rates) {
254 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n", 339 printk(KERN_ERR "ASoC: %s <-> %s No matching rates\n",
@@ -396,11 +481,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
396 if (!codec_dai->active) 481 if (!codec_dai->active)
397 codec_dai->rate = 0; 482 codec_dai->rate = 0;
398 483
399 /* Muting the DAC suppresses artifacts caused during digital
400 * shutdown, for example from stopping clocks.
401 */
402 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);
403
404 if (cpu_dai->driver->ops->shutdown) 484 if (cpu_dai->driver->ops->shutdown)
405 cpu_dai->driver->ops->shutdown(substream, cpu_dai); 485 cpu_dai->driver->ops->shutdown(substream, cpu_dai);
406 486
@@ -531,6 +611,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
531 611
532 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 612 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
533 613
614 ret = soc_pcm_params_symmetry(substream, params);
615 if (ret)
616 goto out;
617
534 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { 618 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
535 ret = rtd->dai_link->ops->hw_params(substream, params); 619 ret = rtd->dai_link->ops->hw_params(substream, params);
536 if (ret < 0) { 620 if (ret < 0) {
@@ -567,9 +651,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
567 } 651 }
568 } 652 }
569 653
570 /* store the rate for each DAIs */ 654 /* store the parameters for each DAIs */
571 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
572 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));
573 664
574out: 665out:
575 mutex_unlock(&rtd->pcm_mutex); 666 mutex_unlock(&rtd->pcm_mutex);
@@ -604,6 +695,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
604 695
605 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 696 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
606 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
607 /* apply codec digital mute */ 711 /* apply codec digital mute */
608 if ((playback && codec_dai->playback_active == 1) || 712 if ((playback && codec_dai->playback_active == 1) ||
609 (!playback && codec_dai->capture_active == 1)) 713 (!playback && codec_dai->capture_active == 1))