diff options
Diffstat (limited to 'sound/soc/omap/omap-pcm.c')
-rw-r--r-- | sound/soc/omap/omap-pcm.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 84a1950880eb..5735945788bf 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -59,16 +59,31 @@ static void omap_pcm_dma_irq(int ch, u16 stat, void *data) | |||
59 | struct omap_runtime_data *prtd = runtime->private_data; | 59 | struct omap_runtime_data *prtd = runtime->private_data; |
60 | unsigned long flags; | 60 | unsigned long flags; |
61 | 61 | ||
62 | if (cpu_is_omap1510()) { | 62 | if ((cpu_is_omap1510()) && |
63 | (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) { | ||
63 | /* | 64 | /* |
64 | * OMAP1510 doesn't support DMA chaining so have to restart | 65 | * OMAP1510 doesn't fully support DMA progress counter |
65 | * the transfer after all periods are transferred | 66 | * and there is no software emulation implemented yet, |
67 | * so have to maintain our own playback progress counter | ||
68 | * that can be used by omap_pcm_pointer() instead. | ||
66 | */ | 69 | */ |
67 | spin_lock_irqsave(&prtd->lock, flags); | 70 | spin_lock_irqsave(&prtd->lock, flags); |
71 | if ((stat == OMAP_DMA_LAST_IRQ) && | ||
72 | (prtd->period_index == runtime->periods - 1)) { | ||
73 | /* we are in sync, do nothing */ | ||
74 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
75 | return; | ||
76 | } | ||
68 | if (prtd->period_index >= 0) { | 77 | if (prtd->period_index >= 0) { |
69 | if (++prtd->period_index == runtime->periods) { | 78 | if (stat & OMAP_DMA_BLOCK_IRQ) { |
79 | /* end of buffer reached, loop back */ | ||
80 | prtd->period_index = 0; | ||
81 | } else if (stat & OMAP_DMA_LAST_IRQ) { | ||
82 | /* update the counter for the last period */ | ||
83 | prtd->period_index = runtime->periods - 1; | ||
84 | } else if (++prtd->period_index >= runtime->periods) { | ||
85 | /* end of buffer missed? loop back */ | ||
70 | prtd->period_index = 0; | 86 | prtd->period_index = 0; |
71 | omap_start_dma(prtd->dma_ch); | ||
72 | } | 87 | } |
73 | } | 88 | } |
74 | spin_unlock_irqrestore(&prtd->lock, flags); | 89 | spin_unlock_irqrestore(&prtd->lock, flags); |
@@ -100,7 +115,7 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, | |||
100 | prtd->dma_data = dma_data; | 115 | prtd->dma_data = dma_data; |
101 | err = omap_request_dma(dma_data->dma_req, dma_data->name, | 116 | err = omap_request_dma(dma_data->dma_req, dma_data->name, |
102 | omap_pcm_dma_irq, substream, &prtd->dma_ch); | 117 | omap_pcm_dma_irq, substream, &prtd->dma_ch); |
103 | if (!err && !cpu_is_omap1510()) { | 118 | if (!err) { |
104 | /* | 119 | /* |
105 | * Link channel with itself so DMA doesn't need any | 120 | * Link channel with itself so DMA doesn't need any |
106 | * reprogramming while looping the buffer | 121 | * reprogramming while looping the buffer |
@@ -119,8 +134,7 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream) | |||
119 | if (prtd->dma_data == NULL) | 134 | if (prtd->dma_data == NULL) |
120 | return 0; | 135 | return 0; |
121 | 136 | ||
122 | if (!cpu_is_omap1510()) | 137 | omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch); |
123 | omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch); | ||
124 | omap_free_dma(prtd->dma_ch); | 138 | omap_free_dma(prtd->dma_ch); |
125 | prtd->dma_data = NULL; | 139 | prtd->dma_data = NULL; |
126 | 140 | ||
@@ -148,7 +162,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
148 | */ | 162 | */ |
149 | dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; | 163 | dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; |
150 | dma_params.trigger = dma_data->dma_req; | 164 | dma_params.trigger = dma_data->dma_req; |
151 | dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; | 165 | dma_params.sync_mode = dma_data->sync_mode; |
152 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 166 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
153 | dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; | 167 | dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; |
154 | dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; | 168 | dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; |
@@ -174,7 +188,15 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
174 | dma_params.frame_count = runtime->periods; | 188 | dma_params.frame_count = runtime->periods; |
175 | omap_set_dma_params(prtd->dma_ch, &dma_params); | 189 | omap_set_dma_params(prtd->dma_ch, &dma_params); |
176 | 190 | ||
177 | omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); | 191 | if ((cpu_is_omap1510()) && |
192 | (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) | ||
193 | omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ | | ||
194 | OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ); | ||
195 | else | ||
196 | omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); | ||
197 | |||
198 | omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
199 | omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
178 | 200 | ||
179 | return 0; | 201 | return 0; |
180 | } | 202 | } |
@@ -183,6 +205,7 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
183 | { | 205 | { |
184 | struct snd_pcm_runtime *runtime = substream->runtime; | 206 | struct snd_pcm_runtime *runtime = substream->runtime; |
185 | struct omap_runtime_data *prtd = runtime->private_data; | 207 | struct omap_runtime_data *prtd = runtime->private_data; |
208 | struct omap_pcm_dma_data *dma_data = prtd->dma_data; | ||
186 | unsigned long flags; | 209 | unsigned long flags; |
187 | int ret = 0; | 210 | int ret = 0; |
188 | 211 | ||
@@ -192,6 +215,10 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
192 | case SNDRV_PCM_TRIGGER_RESUME: | 215 | case SNDRV_PCM_TRIGGER_RESUME: |
193 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 216 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
194 | prtd->period_index = 0; | 217 | prtd->period_index = 0; |
218 | /* Configure McBSP internal buffer usage */ | ||
219 | if (dma_data->set_threshold) | ||
220 | dma_data->set_threshold(substream); | ||
221 | |||
195 | omap_start_dma(prtd->dma_ch); | 222 | omap_start_dma(prtd->dma_ch); |
196 | break; | 223 | break; |
197 | 224 | ||
@@ -288,7 +315,7 @@ static struct snd_pcm_ops omap_pcm_ops = { | |||
288 | .mmap = omap_pcm_mmap, | 315 | .mmap = omap_pcm_mmap, |
289 | }; | 316 | }; |
290 | 317 | ||
291 | static u64 omap_pcm_dmamask = DMA_BIT_MASK(32); | 318 | static u64 omap_pcm_dmamask = DMA_BIT_MASK(64); |
292 | 319 | ||
293 | static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, | 320 | static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, |
294 | int stream) | 321 | int stream) |
@@ -330,7 +357,7 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
330 | } | 357 | } |
331 | } | 358 | } |
332 | 359 | ||
333 | int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 360 | static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, |
334 | struct snd_pcm *pcm) | 361 | struct snd_pcm *pcm) |
335 | { | 362 | { |
336 | int ret = 0; | 363 | int ret = 0; |
@@ -338,7 +365,7 @@ int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | |||
338 | if (!card->dev->dma_mask) | 365 | if (!card->dev->dma_mask) |
339 | card->dev->dma_mask = &omap_pcm_dmamask; | 366 | card->dev->dma_mask = &omap_pcm_dmamask; |
340 | if (!card->dev->coherent_dma_mask) | 367 | if (!card->dev->coherent_dma_mask) |
341 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | 368 | card->dev->coherent_dma_mask = DMA_BIT_MASK(64); |
342 | 369 | ||
343 | if (dai->playback.channels_min) { | 370 | if (dai->playback.channels_min) { |
344 | ret = omap_pcm_preallocate_dma_buffer(pcm, | 371 | ret = omap_pcm_preallocate_dma_buffer(pcm, |