1 From 8a5087fe59e31efb8641e704058328997c3c8ff1 Mon Sep 17 00:00:00 2001
2 From: Maarten ter Huurne <maarten@treewalker.org>
3 Date: Wed, 10 Aug 2011 00:25:11 +0200
4 Subject: [PATCH 16/21] ASoC: JZ4740: Support buffer size that is not a
5 multiple of period size.
7 This fixes glitches triggered by libao, which sets time-based intervals
8 instead of byte-based intervals like SDL does.
10 Thanks to Paul Cercueil for figuring out that the buffer size was causing
11 the glitches and to Lars Clausen for helping me write the fix.
13 sound/soc/jz4740/jz4740-pcm.c | 21 ++++++++++++++++++---
14 1 files changed, 18 insertions(+), 3 deletions(-)
16 --- a/sound/soc/jz4740/jz4740-pcm.c
17 +++ b/sound/soc/jz4740/jz4740-pcm.c
20 struct jz4740_runtime_data {
21 unsigned long dma_period;
22 + unsigned long dma_period_left;
26 @@ -67,10 +68,13 @@ static void jz4740_pcm_start_transfer(st
27 if (prtd->dma_pos == prtd->dma_end)
28 prtd->dma_pos = prtd->dma_start;
30 - if (prtd->dma_pos + prtd->dma_period > prtd->dma_end)
31 + if (prtd->dma_period_left == 0)
32 + prtd->dma_period_left = prtd->dma_period;
34 + if (prtd->dma_pos + prtd->dma_period_left > prtd->dma_end)
35 count = prtd->dma_end - prtd->dma_pos;
37 - count = prtd->dma_period;
38 + count = prtd->dma_period_left;
40 jz4740_dma_disable(prtd->dma);
42 @@ -85,6 +89,7 @@ static void jz4740_pcm_start_transfer(st
43 jz4740_dma_set_transfer_count(prtd->dma, count);
45 prtd->dma_pos += count;
46 + prtd->dma_period_left -= count;
48 jz4740_dma_enable(prtd->dma);
50 @@ -96,7 +101,8 @@ static void jz4740_pcm_dma_transfer_done
51 struct snd_pcm_runtime *runtime = substream->runtime;
52 struct jz4740_runtime_data *prtd = runtime->private_data;
54 - snd_pcm_period_elapsed(substream);
55 + if (prtd->dma_period_left == 0)
56 + snd_pcm_period_elapsed(substream);
58 jz4740_pcm_start_transfer(prtd, substream);
60 @@ -133,6 +139,7 @@ static int jz4740_pcm_hw_params(struct s
61 runtime->dma_bytes = params_buffer_bytes(params);
63 prtd->dma_period = params_period_bytes(params);
64 + prtd->dma_period_left = 0;
65 prtd->dma_start = runtime->dma_addr;
66 prtd->dma_pos = prtd->dma_start;
67 prtd->dma_end = prtd->dma_start + runtime->dma_bytes;
68 @@ -160,6 +167,7 @@ static int jz4740_pcm_prepare(struct snd
72 + prtd->dma_period_left = 0;
73 prtd->dma_pos = prtd->dma_start;
76 @@ -219,6 +227,13 @@ static int jz4740_pcm_open(struct snd_pc
80 + /* Force period and buffer size to be a multiple of the DMA transfer
81 + * size, which is 16 bytes. */
82 + snd_pcm_hw_constraint_step(runtime, 0,
83 + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16);
84 + snd_pcm_hw_constraint_step(runtime, 0,
85 + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
87 snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
89 runtime->private_data = prtd;