|
@@ -157,6 +157,17 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
|
|
|
struct snd_soc_dai *cpu_dai)
|
|
|
{
|
|
|
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
|
|
|
+ int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
|
|
|
+ int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
|
|
|
+ int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
|
|
+
|
|
|
+ if (mcbsp->latency[stream2])
|
|
|
+ pm_qos_update_request(&mcbsp->pm_qos_req,
|
|
|
+ mcbsp->latency[stream2]);
|
|
|
+ else if (mcbsp->latency[stream1])
|
|
|
+ pm_qos_remove_request(&mcbsp->pm_qos_req);
|
|
|
+
|
|
|
+ mcbsp->latency[stream1] = 0;
|
|
|
|
|
|
if (!cpu_dai->active) {
|
|
|
omap_mcbsp_free(mcbsp);
|
|
@@ -164,6 +175,28 @@ static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream,
|
|
|
+ struct snd_soc_dai *cpu_dai)
|
|
|
+{
|
|
|
+ struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
|
|
|
+ struct pm_qos_request *pm_qos_req = &mcbsp->pm_qos_req;
|
|
|
+ int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
|
|
|
+ int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
|
|
|
+ int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
|
|
|
+ int latency = mcbsp->latency[stream2];
|
|
|
+
|
|
|
+ /* Prevent omap hardware from hitting off between FIFO fills */
|
|
|
+ if (!latency || mcbsp->latency[stream1] < latency)
|
|
|
+ latency = mcbsp->latency[stream1];
|
|
|
+
|
|
|
+ if (pm_qos_request_active(pm_qos_req))
|
|
|
+ pm_qos_update_request(pm_qos_req, latency);
|
|
|
+ else if (latency)
|
|
|
+ pm_qos_add_request(pm_qos_req, PM_QOS_CPU_DMA_LATENCY, latency);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
|
|
struct snd_soc_dai *cpu_dai)
|
|
|
{
|
|
@@ -226,6 +259,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
|
|
int wlen, channels, wpf;
|
|
|
int pkt_size = 0;
|
|
|
unsigned int format, div, framesize, master;
|
|
|
+ unsigned int buffer_size = mcbsp->pdata->buffer_size;
|
|
|
|
|
|
dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
|
|
|
channels = params_channels(params);
|
|
@@ -240,7 +274,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
|
|
default:
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
- if (mcbsp->pdata->buffer_size) {
|
|
|
+ if (buffer_size) {
|
|
|
+ int latency;
|
|
|
+
|
|
|
if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
|
|
|
int period_words, max_thrsh;
|
|
|
int divider = 0;
|
|
@@ -271,6 +307,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
|
|
/* Use packet mode for non mono streams */
|
|
|
pkt_size = channels;
|
|
|
}
|
|
|
+
|
|
|
+ latency = ((((buffer_size - pkt_size) / channels) * 1000)
|
|
|
+ / (params->rate_num / params->rate_den));
|
|
|
+
|
|
|
+ mcbsp->latency[substream->stream] = latency;
|
|
|
+
|
|
|
omap_mcbsp_set_threshold(substream, pkt_size);
|
|
|
}
|
|
|
|
|
@@ -554,6 +596,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
|
|
|
static const struct snd_soc_dai_ops mcbsp_dai_ops = {
|
|
|
.startup = omap_mcbsp_dai_startup,
|
|
|
.shutdown = omap_mcbsp_dai_shutdown,
|
|
|
+ .prepare = omap_mcbsp_dai_prepare,
|
|
|
.trigger = omap_mcbsp_dai_trigger,
|
|
|
.delay = omap_mcbsp_dai_delay,
|
|
|
.hw_params = omap_mcbsp_dai_hw_params,
|
|
@@ -835,6 +878,9 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
|
|
|
if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
|
|
|
mcbsp->pdata->ops->free(mcbsp->id);
|
|
|
|
|
|
+ if (pm_qos_request_active(&mcbsp->pm_qos_req))
|
|
|
+ pm_qos_remove_request(&mcbsp->pm_qos_req);
|
|
|
+
|
|
|
omap_mcbsp_cleanup(mcbsp);
|
|
|
|
|
|
clk_put(mcbsp->fclk);
|