aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2013-12-04 06:54:29 -0500
committerMark Brown <broonie@linaro.org>2013-12-04 06:54:29 -0500
commit07ac582c85ead1b972232560832c26fec09dfe04 (patch)
tree1ad64014dd6a5c898cdd9438844b630977d5e0ed
parent0b4bbae85e046042af76a65920db4bb5509c97bd (diff)
parent62e5f676f6a063e1ab0d6b8fcaef2feb026ee00e (diff)
Merge remote-tracking branch 'asoc/topic/symmetry' into asoc-core
Conflicts (Trivial add/delete): sound/soc/soc-pcm.c
-rw-r--r--include/sound/soc-dai.h6
-rw-r--r--include/sound/soc.h2
-rw-r--r--sound/soc/soc-pcm.c151
3 files changed, 138 insertions, 21 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 89d594138773..10f29a0ad5a6 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 }
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;
114} 181}
115 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
@@ -242,6 +324,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
242 &cpu_dai_drv->capture); 324 &cpu_dai_drv->capture);
243 } 325 }
244 326
327 if (soc_pcm_has_symmetry(substream))
328 runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX;
329
245 ret = -EINVAL; 330 ret = -EINVAL;
246 snd_pcm_limit_hw_rates(runtime); 331 snd_pcm_limit_hw_rates(runtime);
247 if (!runtime->hw.rates) { 332 if (!runtime->hw.rates) {
@@ -520,6 +605,10 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
520 605
521 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 606 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
522 607
608 ret = soc_pcm_params_symmetry(substream, params);
609 if (ret)
610 goto out;
611
523 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { 612 if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
524 ret = rtd->dai_link->ops->hw_params(substream, params); 613 ret = rtd->dai_link->ops->hw_params(substream, params);
525 if (ret < 0) { 614 if (ret < 0) {
@@ -556,9 +645,16 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
556 } 645 }
557 } 646 }
558 647
559 /* store the rate for each DAIs */ 648 /* store the parameters for each DAIs */
560 cpu_dai->rate = params_rate(params); 649 cpu_dai->rate = params_rate(params);
650 cpu_dai->channels = params_channels(params);
651 cpu_dai->sample_bits =
652 snd_pcm_format_physical_width(params_format(params));
653
561 codec_dai->rate = params_rate(params); 654 codec_dai->rate = params_rate(params);
655 codec_dai->channels = params_channels(params);
656 codec_dai->sample_bits =
657 snd_pcm_format_physical_width(params_format(params));
562 658
563out: 659out:
564 mutex_unlock(&rtd->pcm_mutex); 660 mutex_unlock(&rtd->pcm_mutex);
@@ -593,6 +689,19 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
593 689
594 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); 690 mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
595 691
692 /* clear the corresponding DAIs parameters when going to be inactive */
693 if (cpu_dai->active == 1) {
694 cpu_dai->rate = 0;
695 cpu_dai->channels = 0;
696 cpu_dai->sample_bits = 0;
697 }
698
699 if (codec_dai->active == 1) {
700 codec_dai->rate = 0;
701 codec_dai->channels = 0;
702 codec_dai->sample_bits = 0;
703 }
704
596 /* apply codec digital mute */ 705 /* apply codec digital mute */
597 if (!codec->active) 706 if (!codec->active)
598 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream); 707 snd_soc_dai_digital_mute(codec_dai, 1, substream->stream);