diff options
author | Kukjin Kim <kgene.kim@samsung.com> | 2011-10-04 05:57:38 -0400 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2011-10-04 05:57:38 -0400 |
commit | 59ca37f74a6e9d3e9367359f2fcbb286df7d9748 (patch) | |
tree | cbc0254ef952f10e99e384b56ccc7b81389e335e /sound | |
parent | 7d84b3e93757fe871d57b43c422b81cc8b94057a (diff) | |
parent | c9312209aa9fdef05b03d63bbead63bb720fd133 (diff) |
Merge branch 'next/topic-dma-samsung' into next-samsung-devel
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/samsung/ac97.c | 10 | ||||
-rw-r--r-- | sound/soc/samsung/dma.c | 146 | ||||
-rw-r--r-- | sound/soc/samsung/dma.h | 4 |
3 files changed, 71 insertions, 89 deletions
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index f97110e72e85..b4f9b0003685 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c | |||
@@ -271,7 +271,10 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | |||
271 | 271 | ||
272 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | 272 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); |
273 | 273 | ||
274 | s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); | 274 | if (!dma_data->ops) |
275 | dma_data->ops = samsung_dma_get_ops(); | ||
276 | |||
277 | dma_data->ops->started(dma_data->channel); | ||
275 | 278 | ||
276 | return 0; | 279 | return 0; |
277 | } | 280 | } |
@@ -317,7 +320,10 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
317 | 320 | ||
318 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); | 321 | writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); |
319 | 322 | ||
320 | s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); | 323 | if (!dma_data->ops) |
324 | dma_data->ops = samsung_dma_get_ops(); | ||
325 | |||
326 | dma_data->ops->started(dma_data->channel); | ||
321 | 327 | ||
322 | return 0; | 328 | return 0; |
323 | } | 329 | } |
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 9465588b02f2..851346f7d68d 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c | |||
@@ -54,7 +54,6 @@ struct runtime_data { | |||
54 | spinlock_t lock; | 54 | spinlock_t lock; |
55 | int state; | 55 | int state; |
56 | unsigned int dma_loaded; | 56 | unsigned int dma_loaded; |
57 | unsigned int dma_limit; | ||
58 | unsigned int dma_period; | 57 | unsigned int dma_period; |
59 | dma_addr_t dma_start; | 58 | dma_addr_t dma_start; |
60 | dma_addr_t dma_pos; | 59 | dma_addr_t dma_pos; |
@@ -62,77 +61,79 @@ struct runtime_data { | |||
62 | struct s3c_dma_params *params; | 61 | struct s3c_dma_params *params; |
63 | }; | 62 | }; |
64 | 63 | ||
64 | static void audio_buffdone(void *data); | ||
65 | |||
65 | /* dma_enqueue | 66 | /* dma_enqueue |
66 | * | 67 | * |
67 | * place a dma buffer onto the queue for the dma system | 68 | * place a dma buffer onto the queue for the dma system |
68 | * to handle. | 69 | * to handle. |
69 | */ | 70 | */ |
70 | static void dma_enqueue(struct snd_pcm_substream *substream) | 71 | static void dma_enqueue(struct snd_pcm_substream *substream) |
71 | { | 72 | { |
72 | struct runtime_data *prtd = substream->runtime->private_data; | 73 | struct runtime_data *prtd = substream->runtime->private_data; |
73 | dma_addr_t pos = prtd->dma_pos; | 74 | dma_addr_t pos = prtd->dma_pos; |
74 | unsigned int limit; | 75 | unsigned int limit; |
75 | int ret; | 76 | struct samsung_dma_prep_info dma_info; |
76 | 77 | ||
77 | pr_debug("Entered %s\n", __func__); | 78 | pr_debug("Entered %s\n", __func__); |
78 | 79 | ||
79 | if (s3c_dma_has_circular()) | 80 | limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; |
80 | limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; | ||
81 | else | ||
82 | limit = prtd->dma_limit; | ||
83 | 81 | ||
84 | pr_debug("%s: loaded %d, limit %d\n", | 82 | pr_debug("%s: loaded %d, limit %d\n", |
85 | __func__, prtd->dma_loaded, limit); | 83 | __func__, prtd->dma_loaded, limit); |
86 | 84 | ||
87 | while (prtd->dma_loaded < limit) { | 85 | dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); |
88 | unsigned long len = prtd->dma_period; | 86 | dma_info.direction = |
87 | (substream->stream == SNDRV_PCM_STREAM_PLAYBACK | ||
88 | ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | ||
89 | dma_info.fp = audio_buffdone; | ||
90 | dma_info.fp_param = substream; | ||
91 | dma_info.period = prtd->dma_period; | ||
92 | dma_info.len = prtd->dma_period*limit; | ||
89 | 93 | ||
94 | while (prtd->dma_loaded < limit) { | ||
90 | pr_debug("dma_loaded: %d\n", prtd->dma_loaded); | 95 | pr_debug("dma_loaded: %d\n", prtd->dma_loaded); |
91 | 96 | ||
92 | if ((pos + len) > prtd->dma_end) { | 97 | if ((pos + dma_info.period) > prtd->dma_end) { |
93 | len = prtd->dma_end - pos; | 98 | dma_info.period = prtd->dma_end - pos; |
94 | pr_debug("%s: corrected dma len %ld\n", __func__, len); | 99 | pr_debug("%s: corrected dma len %ld\n", |
100 | __func__, dma_info.period); | ||
95 | } | 101 | } |
96 | 102 | ||
97 | ret = s3c2410_dma_enqueue(prtd->params->channel, | 103 | dma_info.buf = pos; |
98 | substream, pos, len); | 104 | prtd->params->ops->prepare(prtd->params->ch, &dma_info); |
99 | 105 | ||
100 | if (ret == 0) { | 106 | prtd->dma_loaded++; |
101 | prtd->dma_loaded++; | 107 | pos += prtd->dma_period; |
102 | pos += prtd->dma_period; | 108 | if (pos >= prtd->dma_end) |
103 | if (pos >= prtd->dma_end) | 109 | pos = prtd->dma_start; |
104 | pos = prtd->dma_start; | ||
105 | } else | ||
106 | break; | ||
107 | } | 110 | } |
108 | 111 | ||
109 | prtd->dma_pos = pos; | 112 | prtd->dma_pos = pos; |
110 | } | 113 | } |
111 | 114 | ||
112 | static void audio_buffdone(struct s3c2410_dma_chan *channel, | 115 | static void audio_buffdone(void *data) |
113 | void *dev_id, int size, | ||
114 | enum s3c2410_dma_buffresult result) | ||
115 | { | 116 | { |
116 | struct snd_pcm_substream *substream = dev_id; | 117 | struct snd_pcm_substream *substream = data; |
117 | struct runtime_data *prtd; | 118 | struct runtime_data *prtd = substream->runtime->private_data; |
118 | 119 | ||
119 | pr_debug("Entered %s\n", __func__); | 120 | pr_debug("Entered %s\n", __func__); |
120 | 121 | ||
121 | if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) | 122 | if (prtd->state & ST_RUNNING) { |
122 | return; | 123 | prtd->dma_pos += prtd->dma_period; |
123 | 124 | if (prtd->dma_pos >= prtd->dma_end) | |
124 | prtd = substream->runtime->private_data; | 125 | prtd->dma_pos = prtd->dma_start; |
125 | 126 | ||
126 | if (substream) | 127 | if (substream) |
127 | snd_pcm_period_elapsed(substream); | 128 | snd_pcm_period_elapsed(substream); |
128 | 129 | ||
129 | spin_lock(&prtd->lock); | 130 | spin_lock(&prtd->lock); |
130 | if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { | 131 | if (!samsung_dma_has_circular()) { |
131 | prtd->dma_loaded--; | 132 | prtd->dma_loaded--; |
132 | dma_enqueue(substream); | 133 | dma_enqueue(substream); |
134 | } | ||
135 | spin_unlock(&prtd->lock); | ||
133 | } | 136 | } |
134 | |||
135 | spin_unlock(&prtd->lock); | ||
136 | } | 137 | } |
137 | 138 | ||
138 | static int dma_hw_params(struct snd_pcm_substream *substream, | 139 | static int dma_hw_params(struct snd_pcm_substream *substream, |
@@ -144,8 +145,7 @@ static int dma_hw_params(struct snd_pcm_substream *substream, | |||
144 | unsigned long totbytes = params_buffer_bytes(params); | 145 | unsigned long totbytes = params_buffer_bytes(params); |
145 | struct s3c_dma_params *dma = | 146 | struct s3c_dma_params *dma = |
146 | snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | 147 | snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
147 | int ret = 0; | 148 | struct samsung_dma_info dma_info; |
148 | |||
149 | 149 | ||
150 | pr_debug("Entered %s\n", __func__); | 150 | pr_debug("Entered %s\n", __func__); |
151 | 151 | ||
@@ -163,30 +163,26 @@ static int dma_hw_params(struct snd_pcm_substream *substream, | |||
163 | pr_debug("params %p, client %p, channel %d\n", prtd->params, | 163 | pr_debug("params %p, client %p, channel %d\n", prtd->params, |
164 | prtd->params->client, prtd->params->channel); | 164 | prtd->params->client, prtd->params->channel); |
165 | 165 | ||
166 | ret = s3c2410_dma_request(prtd->params->channel, | 166 | prtd->params->ops = samsung_dma_get_ops(); |
167 | prtd->params->client, NULL); | 167 | |
168 | 168 | dma_info.cap = (samsung_dma_has_circular() ? | |
169 | if (ret < 0) { | 169 | DMA_CYCLIC : DMA_SLAVE); |
170 | printk(KERN_ERR "failed to get dma channel\n"); | 170 | dma_info.client = prtd->params->client; |
171 | return ret; | 171 | dma_info.direction = |
172 | } | 172 | (substream->stream == SNDRV_PCM_STREAM_PLAYBACK |
173 | 173 | ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | |
174 | /* use the circular buffering if we have it available. */ | 174 | dma_info.width = prtd->params->dma_size; |
175 | if (s3c_dma_has_circular()) | 175 | dma_info.fifo = prtd->params->dma_addr; |
176 | s3c2410_dma_setflags(prtd->params->channel, | 176 | prtd->params->ch = prtd->params->ops->request( |
177 | S3C2410_DMAF_CIRCULAR); | 177 | prtd->params->channel, &dma_info); |
178 | } | 178 | } |
179 | 179 | ||
180 | s3c2410_dma_set_buffdone_fn(prtd->params->channel, | ||
181 | audio_buffdone); | ||
182 | |||
183 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 180 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); |
184 | 181 | ||
185 | runtime->dma_bytes = totbytes; | 182 | runtime->dma_bytes = totbytes; |
186 | 183 | ||
187 | spin_lock_irq(&prtd->lock); | 184 | spin_lock_irq(&prtd->lock); |
188 | prtd->dma_loaded = 0; | 185 | prtd->dma_loaded = 0; |
189 | prtd->dma_limit = runtime->hw.periods_min; | ||
190 | prtd->dma_period = params_period_bytes(params); | 186 | prtd->dma_period = params_period_bytes(params); |
191 | prtd->dma_start = runtime->dma_addr; | 187 | prtd->dma_start = runtime->dma_addr; |
192 | prtd->dma_pos = prtd->dma_start; | 188 | prtd->dma_pos = prtd->dma_start; |
@@ -206,7 +202,8 @@ static int dma_hw_free(struct snd_pcm_substream *substream) | |||
206 | snd_pcm_set_runtime_buffer(substream, NULL); | 202 | snd_pcm_set_runtime_buffer(substream, NULL); |
207 | 203 | ||
208 | if (prtd->params) { | 204 | if (prtd->params) { |
209 | s3c2410_dma_free(prtd->params->channel, prtd->params->client); | 205 | prtd->params->ops->release(prtd->params->ch, |
206 | prtd->params->client); | ||
210 | prtd->params = NULL; | 207 | prtd->params = NULL; |
211 | } | 208 | } |
212 | 209 | ||
@@ -225,23 +222,9 @@ static int dma_prepare(struct snd_pcm_substream *substream) | |||
225 | if (!prtd->params) | 222 | if (!prtd->params) |
226 | return 0; | 223 | return 0; |
227 | 224 | ||
228 | /* channel needs configuring for mem=>device, increment memory addr, | ||
229 | * sync to pclk, half-word transfers to the IIS-FIFO. */ | ||
230 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
231 | s3c2410_dma_devconfig(prtd->params->channel, | ||
232 | S3C2410_DMASRC_MEM, | ||
233 | prtd->params->dma_addr); | ||
234 | } else { | ||
235 | s3c2410_dma_devconfig(prtd->params->channel, | ||
236 | S3C2410_DMASRC_HW, | ||
237 | prtd->params->dma_addr); | ||
238 | } | ||
239 | |||
240 | s3c2410_dma_config(prtd->params->channel, | ||
241 | prtd->params->dma_size); | ||
242 | |||
243 | /* flush the DMA channel */ | 225 | /* flush the DMA channel */ |
244 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); | 226 | prtd->params->ops->flush(prtd->params->ch); |
227 | |||
245 | prtd->dma_loaded = 0; | 228 | prtd->dma_loaded = 0; |
246 | prtd->dma_pos = prtd->dma_start; | 229 | prtd->dma_pos = prtd->dma_start; |
247 | 230 | ||
@@ -265,14 +248,14 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) | |||
265 | case SNDRV_PCM_TRIGGER_RESUME: | 248 | case SNDRV_PCM_TRIGGER_RESUME: |
266 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 249 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
267 | prtd->state |= ST_RUNNING; | 250 | prtd->state |= ST_RUNNING; |
268 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); | 251 | prtd->params->ops->trigger(prtd->params->ch); |
269 | break; | 252 | break; |
270 | 253 | ||
271 | case SNDRV_PCM_TRIGGER_STOP: | 254 | case SNDRV_PCM_TRIGGER_STOP: |
272 | case SNDRV_PCM_TRIGGER_SUSPEND: | 255 | case SNDRV_PCM_TRIGGER_SUSPEND: |
273 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 256 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
274 | prtd->state &= ~ST_RUNNING; | 257 | prtd->state &= ~ST_RUNNING; |
275 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STOP); | 258 | prtd->params->ops->stop(prtd->params->ch); |
276 | break; | 259 | break; |
277 | 260 | ||
278 | default: | 261 | default: |
@@ -291,21 +274,12 @@ dma_pointer(struct snd_pcm_substream *substream) | |||
291 | struct snd_pcm_runtime *runtime = substream->runtime; | 274 | struct snd_pcm_runtime *runtime = substream->runtime; |
292 | struct runtime_data *prtd = runtime->private_data; | 275 | struct runtime_data *prtd = runtime->private_data; |
293 | unsigned long res; | 276 | unsigned long res; |
294 | dma_addr_t src, dst; | ||
295 | 277 | ||
296 | pr_debug("Entered %s\n", __func__); | 278 | pr_debug("Entered %s\n", __func__); |
297 | 279 | ||
298 | spin_lock(&prtd->lock); | 280 | res = prtd->dma_pos - prtd->dma_start; |
299 | s3c2410_dma_getposition(prtd->params->channel, &src, &dst); | ||
300 | |||
301 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
302 | res = dst - prtd->dma_start; | ||
303 | else | ||
304 | res = src - prtd->dma_start; | ||
305 | |||
306 | spin_unlock(&prtd->lock); | ||
307 | 281 | ||
308 | pr_debug("Pointer %x %x\n", src, dst); | 282 | pr_debug("Pointer offset: %lu\n", res); |
309 | 283 | ||
310 | /* we seem to be getting the odd error from the pcm library due | 284 | /* we seem to be getting the odd error from the pcm library due |
311 | * to out-of-bounds pointers. this is maybe due to the dma engine | 285 | * to out-of-bounds pointers. this is maybe due to the dma engine |
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index c50659269a40..7d1ead77ef21 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h | |||
@@ -6,7 +6,7 @@ | |||
6 | * Free Software Foundation; either version 2 of the License, or (at your | 6 | * Free Software Foundation; either version 2 of the License, or (at your |
7 | * option) any later version. | 7 | * option) any later version. |
8 | * | 8 | * |
9 | * ALSA PCM interface for the Samsung S3C24xx CPU | 9 | * ALSA PCM interface for the Samsung SoC |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef _S3C_AUDIO_H | 12 | #ifndef _S3C_AUDIO_H |
@@ -17,6 +17,8 @@ struct s3c_dma_params { | |||
17 | int channel; /* Channel ID */ | 17 | int channel; /* Channel ID */ |
18 | dma_addr_t dma_addr; | 18 | dma_addr_t dma_addr; |
19 | int dma_size; /* Size of the DMA transfer */ | 19 | int dma_size; /* Size of the DMA transfer */ |
20 | unsigned ch; | ||
21 | struct samsung_dma_ops *ops; | ||
20 | }; | 22 | }; |
21 | 23 | ||
22 | #endif | 24 | #endif |