aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/samsung
diff options
context:
space:
mode:
authorBoojin Kim <boojin.kim@samsung.com>2011-09-01 20:44:43 -0400
committerVinod Koul <vinod.koul@intel.com>2011-09-14 01:40:04 -0400
commit344b4c48887a443f7478fc7047d1397b20821ed3 (patch)
treea3fdf36f35b43d41f1402f2e6939fe761f575be8 /sound/soc/samsung
parent82ab8cd7ec32194757ac73a66633be73ba88ea69 (diff)
ASoC: Samsung: Update DMA interface
This patch adds to support the DMA PL330 driver that uses DMA generic API. Samsung sound driver uses DMA generic API if architecture supports it. Otherwise, use samsung specific S3C-PL330 API driver to transfer PCM data. Signed-off-by: Boojin Kim <boojin.kim@samsung.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Vinod Koul <vinod.koul@intel.com> Cc: Jassi Brar <jassisinghbrar@gmail.com> Cc: Liam Girdwood <lrg@ti.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> [kgene.kim@samsung.com: removed useless variable] Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'sound/soc/samsung')
-rw-r--r--sound/soc/samsung/ac97.c10
-rw-r--r--sound/soc/samsung/dma.c146
-rw-r--r--sound/soc/samsung/dma.h4
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
64static 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 */
70static void dma_enqueue(struct snd_pcm_substream *substream) 71static 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
112static void audio_buffdone(struct s3c2410_dma_chan *channel, 115static 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
138static int dma_hw_params(struct snd_pcm_substream *substream, 139static 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