aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/soc-dai.h6
-rw-r--r--include/sound/soc.h2
-rw-r--r--sound/soc/soc-pcm.c130
3 files changed, 115 insertions, 23 deletions
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 800c101bb096..243d3b689699 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -220,6 +220,8 @@ struct snd_soc_dai_driver {
220 struct snd_soc_pcm_stream capture; 220 struct snd_soc_pcm_stream capture;
221 struct snd_soc_pcm_stream playback; 221 struct snd_soc_pcm_stream playback;
222 unsigned int symmetric_rates:1; 222 unsigned int symmetric_rates:1;
223 unsigned int symmetric_channels:1;
224 unsigned int symmetric_samplebits:1;
223 225
224 /* probe ordering - for components with runtime dependencies */ 226 /* probe ordering - for components with runtime dependencies */
225 int probe_order; 227 int probe_order;
@@ -244,6 +246,8 @@ struct snd_soc_dai {
244 unsigned int capture_active:1; /* stream is in use */ 246 unsigned int capture_active:1; /* stream is in use */
245 unsigned int playback_active:1; /* stream is in use */ 247 unsigned int playback_active:1; /* stream is in use */
246 unsigned int symmetric_rates:1; 248 unsigned int symmetric_rates:1;
249 unsigned int symmetric_channels:1;
250 unsigned int symmetric_samplebits:1;
247 struct snd_pcm_runtime *runtime; 251 struct snd_pcm_runtime *runtime;
248 unsigned int active; 252 unsigned int active;
249 unsigned char probed:1; 253 unsigned char probed:1;
@@ -258,6 +262,8 @@ struct snd_soc_dai {
258 262
259 /* Symmetry data - only valid if symmetry is being enforced */ 263 /* Symmetry data - only valid if symmetry is being enforced */
260 unsigned int rate; 264 unsigned int rate;
265 unsigned int channels;
266 unsigned int sample_bits;
261 267
262 /* parent platform/codec */ 268 /* parent platform/codec */
263 struct snd_soc_platform *platform; 269 struct snd_soc_platform *platform;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 1f741cb24f33..1cda7d343d16 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -879,6 +879,8 @@ struct snd_soc_dai_link {
879 879
880 /* Symmetry requirements */ 880 /* Symmetry requirements */
881 unsigned int symmetric_rates:1; 881 unsigned int symmetric_rates:1;
882 unsigned int symmetric_channels:1;
883 unsigned int symmetric_samplebits:1;
882 884
883 /* Do not create a PCM for this DAI link (Backend link) */ 885 /* Do not create a PCM for this DAI link (Backend link) */
884 unsigned int no_pcm:1; 886 unsigned int no_pcm:1;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 42782c01e413..ed1e077114a2 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -84,30 +84,97 @@ 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 }
135 }
136
137 return 0;
138}
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;
111 } 178 }
112 179
113 return 0; 180 return 0;
@@ -384,11 +451,17 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
384 codec->active--; 451 codec->active--;
385 452
386 /* clear the corresponding DAIs rate when inactive */ 453 /* clear the corresponding DAIs rate when inactive */
387 if (!cpu_dai->active) 454 if (!cpu_dai->active) {
388 cpu_dai->rate = 0; 455 cpu_dai->rate = 0;
456 cpu_dai->channels = 0;
457 cpu_dai->sample_bits = 0;
458 }
389 459
390 if (!codec_dai->active) 460 if (!codec_dai->active) {
391 codec_dai->rate = 0; 461 codec_dai->rate = 0;
462 codec_dai->channels = 0;
463 codec_dai->sample_bits = 0;
464 }
392 465
393 /* Muting the DAC suppresses artifacts caused during digital 466 /* Muting the DAC suppresses artifacts caused during digital
394 * shutdown, for example from stopping clocks. 467 * shutdown, for example from stopping clocks.
@@ -525,6 +598,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
525 598
526 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 599 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
527 600
601 ret = soc_pcm_params_symmetry(substream, params);
602 if (ret)
603 goto out;
604
528 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { 605 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
529 ret = rtd->dai_link->ops->hw_params(substream, params); 606 ret = rtd->dai_link->ops->hw_params(substream, params);
530 if (ret < 0) { 607 if (ret < 0) {
@@ -561,9 +638,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
561 } 638 }
562 } 639 }
563 640
564 /* store the rate for each DAIs */ 641 /* store the parameters for each DAIs */
565 cpu_dai->rate = params_rate(params); 642 cpu_dai->rate = params_rate(params);
643 cpu_dai->channels = params_channels(params);
644 cpu_dai->sample_bits =
645 snd_pcm_format_physical_width(params_format(params));
646
566 codec_dai->rate = params_rate(params); 647 codec_dai->rate = params_rate(params);
648 codec_dai->channels = params_channels(params);
649 codec_dai->sample_bits =
650 snd_pcm_format_physical_width(params_format(params));
567 651
568out: 652out:
569 mutex_unlock(&rtd->pcm_mutex); 653 mutex_unlock(&rtd->pcm_mutex);