aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Ranostay <matt@ranostay.consulting>2017-01-31 16:21:43 -0500
committerMark Brown <broonie@kernel.org>2017-02-01 12:19:53 -0500
commit9834ffd1ecc3a401d0ce64c2d4235a726da6d4f9 (patch)
treeb9241a9299e5e8f4d26072d0eb72e540f895e272
parenta5de5b74a50113564a1e0850e2da96c37c35e55d (diff)
ASoC: omap-mcbsp: Add PM QoS support for McBSP to prevent glitches
We can get audio errors if hitting deeper idle states on omaps: [alsa.c:230] error: Fatal problem with alsa output, error -5. [audio.c:614] error: Error in writing audio (Input/output error?)! This seems to happen with off mode idle enabled as power for the whole SoC may get cut off between filling the McBSP fifo using DMA. While active DMA blocks deeper idle states in hardware, McBSP activity does not seem to do so. Basing the QoS latency calculation on the FIFO size, threshold, sample rate, and channels. Based on the original patch by Tony Lindgren Link: https://patchwork.kernel.org/patch/9305867/ Signed-off-by: Matt Ranostay <matt@ranostay.consulting> Signed-off-by: Liam Breck <kernel@networkimprov.net> Tested-by: Tony Lindgren <tony@atomide.com> Acked-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/omap/mcbsp.h3
-rw-r--r--sound/soc/omap/omap-mcbsp.c48
2 files changed, 50 insertions, 1 deletions
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
index 61e93b1c185d..46ae1269a698 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/omap/mcbsp.h
@@ -323,8 +323,11 @@ struct omap_mcbsp {
323 323
324 unsigned int fmt; 324 unsigned int fmt;
325 unsigned int in_freq; 325 unsigned int in_freq;
326 unsigned int latency[2];
326 int clk_div; 327 int clk_div;
327 int wlen; 328 int wlen;
329
330 struct pm_qos_request pm_qos_req;
328}; 331};
329 332
330void omap_mcbsp_config(struct omap_mcbsp *mcbsp, 333void omap_mcbsp_config(struct omap_mcbsp *mcbsp,
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index d018e966e533..6b40bdbef336 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -157,6 +157,17 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
157 struct snd_soc_dai *cpu_dai) 157 struct snd_soc_dai *cpu_dai)
158{ 158{
159 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 159 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
160 int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
161 int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
162 int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
163
164 if (mcbsp->latency[stream2])
165 pm_qos_update_request(&mcbsp->pm_qos_req,
166 mcbsp->latency[stream2]);
167 else if (mcbsp->latency[stream1])
168 pm_qos_remove_request(&mcbsp->pm_qos_req);
169
170 mcbsp->latency[stream1] = 0;
160 171
161 if (!cpu_dai->active) { 172 if (!cpu_dai->active) {
162 omap_mcbsp_free(mcbsp); 173 omap_mcbsp_free(mcbsp);
@@ -164,6 +175,28 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
164 } 175 }
165} 176}
166 177
178static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream,
179 struct snd_soc_dai *cpu_dai)
180{
181 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
182 struct pm_qos_request *pm_qos_req = &mcbsp->pm_qos_req;
183 int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
184 int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
185 int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
186 int latency = mcbsp->latency[stream2];
187
188 /* Prevent omap hardware from hitting off between FIFO fills */
189 if (!latency || mcbsp->latency[stream1] < latency)
190 latency = mcbsp->latency[stream1];
191
192 if (pm_qos_request_active(pm_qos_req))
193 pm_qos_update_request(pm_qos_req, latency);
194 else if (latency)
195 pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
196
197 return 0;
198}
199
167static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, 200static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
168 struct snd_soc_dai *cpu_dai) 201 struct snd_soc_dai *cpu_dai)
169{ 202{
@@ -226,6 +259,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
226 int wlen, channels, wpf; 259 int wlen, channels, wpf;
227 int pkt_size = 0; 260 int pkt_size = 0;
228 unsigned int format, div, framesize, master; 261 unsigned int format, div, framesize, master;
262 unsigned int buffer_size = mcbsp->pdata->buffer_size;
229 263
230 dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); 264 dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
231 channels = params_channels(params); 265 channels = params_channels(params);
@@ -240,7 +274,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
240 default: 274 default:
241 return -EINVAL; 275 return -EINVAL;
242 } 276 }
243 if (mcbsp->pdata->buffer_size) { 277 if (buffer_size) {
278 int latency;
279
244 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { 280 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
245 int period_words, max_thrsh; 281 int period_words, max_thrsh;
246 int divider = 0; 282 int divider = 0;
@@ -271,6 +307,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
271 /* Use packet mode for non mono streams */ 307 /* Use packet mode for non mono streams */
272 pkt_size = channels; 308 pkt_size = channels;
273 } 309 }
310
311 latency = ((((buffer_size - pkt_size) / channels) * 1000)
312 / (params->rate_num / params->rate_den));
313
314 mcbsp->latency[substream->stream] = latency;
315
274 omap_mcbsp_set_threshold(substream, pkt_size); 316 omap_mcbsp_set_threshold(substream, pkt_size);
275 } 317 }
276 318
@@ -554,6 +596,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
554static const struct snd_soc_dai_ops mcbsp_dai_ops = { 596static const struct snd_soc_dai_ops mcbsp_dai_ops = {
555 .startup = omap_mcbsp_dai_startup, 597 .startup = omap_mcbsp_dai_startup,
556 .shutdown = omap_mcbsp_dai_shutdown, 598 .shutdown = omap_mcbsp_dai_shutdown,
599 .prepare = omap_mcbsp_dai_prepare,
557 .trigger = omap_mcbsp_dai_trigger, 600 .trigger = omap_mcbsp_dai_trigger,
558 .delay = omap_mcbsp_dai_delay, 601 .delay = omap_mcbsp_dai_delay,
559 .hw_params = omap_mcbsp_dai_hw_params, 602 .hw_params = omap_mcbsp_dai_hw_params,
@@ -835,6 +878,9 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
835 if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) 878 if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
836 mcbsp->pdata->ops->free(mcbsp->id); 879 mcbsp->pdata->ops->free(mcbsp->id);
837 880
881 if (pm_qos_request_active(&mcbsp->pm_qos_req))
882 pm_qos_remove_request(&mcbsp->pm_qos_req);
883
838 omap_mcbsp_cleanup(mcbsp); 884 omap_mcbsp_cleanup(mcbsp);
839 885
840 clk_put(mcbsp->fclk); 886 clk_put(mcbsp->fclk);