Last active
August 29, 2015 14:09
-
-
Save kangear/2ac8590da9f3c6d65a8d to your computer and use it in GitHub Desktop.
S3C2440 audio patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c | |
index 9338d11..96a1b01 100644 | |
--- a/sound/soc/samsung/dma.c | |
+++ b/sound/soc/samsung/dma.c | |
@@ -34,7 +34,9 @@ static const struct snd_pcm_hardware dma_hardware = { | |
.info = SNDRV_PCM_INFO_INTERLEAVED | | |
SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
SNDRV_PCM_INFO_MMAP | | |
- SNDRV_PCM_INFO_MMAP_VALID, | |
+ SNDRV_PCM_INFO_MMAP_VALID| | |
+ SNDRV_PCM_INFO_PAUSE | | |
+ SNDRV_PCM_INFO_RESUME, | |
.formats = SNDRV_PCM_FMTBIT_S16_LE | | |
SNDRV_PCM_FMTBIT_U16_LE | | |
SNDRV_PCM_FMTBIT_U8 | | |
@@ -57,10 +59,11 @@ struct runtime_data { | |
dma_addr_t dma_start; | |
dma_addr_t dma_pos; | |
dma_addr_t dma_end; | |
+ unsigned int dma_limit; | |
struct s3c_dma_params *params; | |
}; | |
-static void audio_buffdone(void *data); | |
+/* static void audio_buffdone(void *data); */ | |
/* dma_enqueue | |
* | |
@@ -72,74 +75,66 @@ static void dma_enqueue(struct snd_pcm_substream *substream) | |
struct runtime_data *prtd = substream->runtime->private_data; | |
dma_addr_t pos = prtd->dma_pos; | |
unsigned int limit; | |
- struct samsung_dma_prep dma_info; | |
+ int ret; | |
pr_debug("Entered %s\n", __func__); | |
- limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; | |
+ if (samsung_dma_has_circular()) | |
+ limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; | |
+ else | |
+ limit = prtd->dma_limit; | |
pr_debug("%s: loaded %d, limit %d\n", | |
__func__, prtd->dma_loaded, limit); | |
- dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE); | |
- dma_info.direction = | |
- (substream->stream == SNDRV_PCM_STREAM_PLAYBACK | |
- ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); | |
- dma_info.fp = audio_buffdone; | |
- dma_info.fp_param = substream; | |
- dma_info.period = prtd->dma_period; | |
- dma_info.len = prtd->dma_period*limit; | |
- | |
- if (dma_info.cap == DMA_CYCLIC) { | |
- dma_info.buf = pos; | |
- prtd->params->ops->prepare(prtd->params->ch, &dma_info); | |
- prtd->dma_loaded += limit; | |
- return; | |
- } | |
- | |
while (prtd->dma_loaded < limit) { | |
+ unsigned long len = prtd->dma_period; | |
pr_debug("dma_loaded: %d\n", prtd->dma_loaded); | |
- if ((pos + dma_info.period) > prtd->dma_end) { | |
- dma_info.period = prtd->dma_end - pos; | |
+ if ((pos + len) > prtd->dma_end) { | |
+ len = prtd->dma_end - pos; | |
pr_debug("%s: corrected dma len %ld\n", | |
- __func__, dma_info.period); | |
+ __func__, len); | |
} | |
- dma_info.buf = pos; | |
- prtd->params->ops->prepare(prtd->params->ch, &dma_info); | |
+ ret = s3c2410_dma_enqueue(prtd->params->channel, | |
+ substream, pos, len); | |
- prtd->dma_loaded++; | |
- pos += prtd->dma_period; | |
- if (pos >= prtd->dma_end) | |
- pos = prtd->dma_start; | |
+ if (ret == 0) { | |
+ prtd->dma_loaded++; | |
+ pos += prtd->dma_period; | |
+ if (pos >= prtd->dma_end) | |
+ pos = prtd->dma_start; | |
+ } else | |
+ break; | |
} | |
prtd->dma_pos = pos; | |
} | |
- | |
-static void audio_buffdone(void *data) | |
+static void audio_buffdone(struct s3c2410_dma_chan *channel, | |
+ void *dev_id, int size, | |
+ enum s3c2410_dma_buffresult result) | |
{ | |
- struct snd_pcm_substream *substream = data; | |
- struct runtime_data *prtd = substream->runtime->private_data; | |
+ struct snd_pcm_substream *substream = dev_id; | |
+ struct runtime_data *prtd; | |
pr_debug("Entered %s\n", __func__); | |
- if (prtd->state & ST_RUNNING) { | |
- prtd->dma_pos += prtd->dma_period; | |
- if (prtd->dma_pos >= prtd->dma_end) | |
- prtd->dma_pos = prtd->dma_start; | |
+ if (result == S3C2410_RES_ABORT || result == S3C2410_RES_ERR) | |
+ return; | |
- if (substream) | |
- snd_pcm_period_elapsed(substream); | |
+ prtd = substream->runtime->private_data; | |
- spin_lock(&prtd->lock); | |
- if (!samsung_dma_has_circular()) { | |
- prtd->dma_loaded--; | |
- dma_enqueue(substream); | |
- } | |
- spin_unlock(&prtd->lock); | |
+ if (substream) | |
+ snd_pcm_period_elapsed(substream); | |
+ | |
+ spin_lock(&prtd->lock); | |
+ if (prtd->state & ST_RUNNING && !samsung_dma_has_circular()) { | |
+ prtd->dma_loaded--; | |
+ dma_enqueue(substream); | |
} | |
+ | |
+ spin_unlock(&prtd->lock); | |
} | |
static int dma_hw_params(struct snd_pcm_substream *substream, | |
@@ -190,6 +185,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream, | |
prtd->params->ops->config(prtd->params->ch, &config); | |
} | |
+ s3c2410_dma_set_buffdone_fn(prtd->params->channel, audio_buffdone); | |
+ | |
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | |
runtime->dma_bytes = totbytes; | |
@@ -200,6 +197,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream, | |
prtd->dma_start = runtime->dma_addr; | |
prtd->dma_pos = prtd->dma_start; | |
prtd->dma_end = prtd->dma_start + totbytes; | |
+ | |
+ prtd->dma_limit = runtime->hw.periods_min; | |
spin_unlock_irq(&prtd->lock); | |
return 0; | |
@@ -227,6 +226,7 @@ static int dma_prepare(struct snd_pcm_substream *substream) | |
{ | |
struct runtime_data *prtd = substream->runtime->private_data; | |
int ret = 0; | |
+ struct samsung_dma_config config; | |
pr_debug("Entered %s\n", __func__); | |
@@ -234,7 +234,12 @@ static int dma_prepare(struct snd_pcm_substream *substream) | |
* codec <--> BT codec or GSM modem -- lg FIXME */ | |
if (!prtd->params) | |
return 0; | |
- | |
+ config.direction = | |
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK | |
+ ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM); | |
+ config.width = prtd->params->dma_size; | |
+ config.fifo = prtd->params->dma_addr; | |
+ prtd->params->ops->config(prtd->params->ch, &config); | |
/* flush the DMA channel */ | |
prtd->params->ops->flush(prtd->params->ch); | |
@@ -258,11 +263,15 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) | |
switch (cmd) { | |
case SNDRV_PCM_TRIGGER_START: | |
+ case SNDRV_PCM_TRIGGER_RESUME: | |
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
prtd->state |= ST_RUNNING; | |
prtd->params->ops->trigger(prtd->params->ch); | |
break; | |
case SNDRV_PCM_TRIGGER_STOP: | |
+ case SNDRV_PCM_TRIGGER_SUSPEND: | |
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
prtd->state &= ~ST_RUNNING; | |
prtd->params->ops->stop(prtd->params->ch); | |
break; | |
@@ -284,9 +293,20 @@ dma_pointer(struct snd_pcm_substream *substream) | |
struct runtime_data *prtd = runtime->private_data; | |
unsigned long res; | |
+ /* res = prtd->dma_pos - prtd->dma_start; */ | |
+ dma_addr_t src, dst; | |
+ | |
pr_debug("Entered %s\n", __func__); | |
- res = prtd->dma_pos - prtd->dma_start; | |
+ spin_lock(&prtd->lock); | |
+ s3c2410_dma_getposition(prtd->params->channel, &src, &dst); | |
+ | |
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | |
+ res = dst - prtd->dma_start; | |
+ else | |
+ res = src - prtd->dma_start; | |
+ | |
+ spin_unlock(&prtd->lock); | |
pr_debug("Pointer offset: %lu\n", res); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment