xburst: add support for 3.8
[openwrt.git] / target / linux / xburst / patches-3.8 / 0016-ASoC-JZ4740-Support-buffer-size-that-is-not-a-multip.patch
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.
6
7 This fixes glitches triggered by libao, which sets time-based intervals
8 instead of byte-based intervals like SDL does.
9
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.
12 ---
13  sound/soc/jz4740/jz4740-pcm.c |   21 ++++++++++++++++++---
14  1 files changed, 18 insertions(+), 3 deletions(-)
15
16 --- a/sound/soc/jz4740/jz4740-pcm.c
17 +++ b/sound/soc/jz4740/jz4740-pcm.c
18 @@ -31,6 +31,7 @@
19  
20  struct jz4740_runtime_data {
21         unsigned long dma_period;
22 +       unsigned long dma_period_left;
23         dma_addr_t dma_start;
24         dma_addr_t dma_pos;
25         dma_addr_t dma_end;
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;
29  
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;
33 +
34 +       if (prtd->dma_pos + prtd->dma_period_left > prtd->dma_end)
35                 count = prtd->dma_end - prtd->dma_pos;
36         else
37 -               count = prtd->dma_period;
38 +               count = prtd->dma_period_left;
39  
40         jz4740_dma_disable(prtd->dma);
41  
42 @@ -85,6 +89,7 @@ static void jz4740_pcm_start_transfer(st
43         jz4740_dma_set_transfer_count(prtd->dma, count);
44  
45         prtd->dma_pos += count;
46 +       prtd->dma_period_left -= count;
47  
48         jz4740_dma_enable(prtd->dma);
49  }
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;
53  
54 -       snd_pcm_period_elapsed(substream);
55 +       if (prtd->dma_period_left == 0)
56 +               snd_pcm_period_elapsed(substream);
57  
58         jz4740_pcm_start_transfer(prtd, substream);
59  }
60 @@ -133,6 +139,7 @@ static int jz4740_pcm_hw_params(struct s
61         runtime->dma_bytes = params_buffer_bytes(params);
62  
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
69         if (!prtd->dma)
70                 return -EBUSY;
71  
72 +       prtd->dma_period_left = 0;
73         prtd->dma_pos = prtd->dma_start;
74  
75         return 0;
76 @@ -219,6 +227,13 @@ static int jz4740_pcm_open(struct snd_pc
77         if (prtd == NULL)
78                 return -ENOMEM;
79  
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);
86 +
87         snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware);
88  
89         runtime->private_data = prtd;