summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorSumit Bhattacharya <sumitb@nvidia.com>2011-02-22 18:58:12 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-03-03 10:49:08 -0800
commit93e42ab68ea32f5722814d19aebe397f1df64690 (patch)
tree35d7bfcc06f1dc7edfe5c626febcd00b6e22a195 /sound
parenta2bf16e81127328fa074134bc5be4f8a12cac44d (diff)
tegra-alsa: return accurate pcm pointer position
Bug 793968 Change-Id: Ia4ee5a83d18b409dd223f70fb1a5a78fad16a08e Reviewed-on: http://git-master/r/20403 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/tegra/tegra_pcm.c107
-rw-r--r--sound/soc/tegra/tegra_soc.h5
2 files changed, 51 insertions, 61 deletions
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index c982eb6cddb4..da2d476b6886 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -25,31 +25,19 @@
static void tegra_pcm_play(struct tegra_runtime_data *prtd)
{
- static int reqid = 0;
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *buf = &substream->dma_buffer;
if (runtime->dma_addr) {
prtd->size = frames_to_bytes(runtime, runtime->period_size);
- if (reqid == 0) {
- if (prtd->dma_state != STATE_ABORT) {
- prtd->dma_req1.source_addr = buf->addr +
- frames_to_bytes(runtime,prtd->dma_pos);
- prtd->dma_req1.size = prtd->size;
- tegra_dma_enqueue_req(prtd->dma_chan,
- &prtd->dma_req1);
- reqid = 1;
- }
- } else {
- if (prtd->dma_state != STATE_ABORT) {
- prtd->dma_req2.source_addr = buf->addr +
- frames_to_bytes(runtime,prtd->dma_pos);
- prtd->dma_req2.size = prtd->size;
- tegra_dma_enqueue_req(prtd->dma_chan,
- &prtd->dma_req2);
- reqid = 0;
- }
+ if (prtd->dma_state != STATE_ABORT) {
+ prtd->dma_reqid_tail = (prtd->dma_reqid_tail + 1) % DMA_REQ_QCOUNT;
+ prtd->dma_req[prtd->dma_reqid_tail].source_addr = buf->addr +
+ frames_to_bytes(runtime,prtd->dma_pos);
+ prtd->dma_req[prtd->dma_reqid_tail].size = prtd->size;
+ tegra_dma_enqueue_req(prtd->dma_chan,
+ &prtd->dma_req[prtd->dma_reqid_tail]);
}
}
@@ -62,31 +50,19 @@ static void tegra_pcm_play(struct tegra_runtime_data *prtd)
static void tegra_pcm_capture(struct tegra_runtime_data *prtd)
{
- static int reqid = 0;
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *buf = &substream->dma_buffer;
if (runtime->dma_addr) {
prtd->size = frames_to_bytes(runtime, runtime->period_size);
- if (reqid == 0) {
- if (prtd->dma_state != STATE_ABORT) {
- prtd->dma_req1.dest_addr = buf->addr +
- frames_to_bytes(runtime,prtd->dma_pos);
- prtd->dma_req1.size = prtd->size;
- tegra_dma_enqueue_req(prtd->dma_chan,
- &prtd->dma_req1);
- reqid = 1;
- }
- } else {
- if (prtd->dma_state != STATE_ABORT) {
- prtd->dma_req2.dest_addr = buf->addr +
- frames_to_bytes(runtime,prtd->dma_pos);
- prtd->dma_req2.size = prtd->size;
- tegra_dma_enqueue_req(prtd->dma_chan,
- &prtd->dma_req2);
- reqid = 0;
- }
+ if (prtd->dma_state != STATE_ABORT) {
+ prtd->dma_reqid_tail = (prtd->dma_reqid_tail + 1) % DMA_REQ_QCOUNT;
+ prtd->dma_req[prtd->dma_reqid_tail].dest_addr = buf->addr +
+ frames_to_bytes(runtime,prtd->dma_pos);
+ prtd->dma_req[prtd->dma_reqid_tail].size = prtd->size;
+ tegra_dma_enqueue_req(prtd->dma_chan,
+ &prtd->dma_req[prtd->dma_reqid_tail]);
}
}
@@ -108,6 +84,7 @@ static void dma_complete_callback (struct tegra_dma_req *req)
}
if (prtd->dma_state != STATE_ABORT) {
+ prtd->dma_reqid_head = (prtd->dma_reqid_head + 1) % DMA_REQ_QCOUNT;
snd_pcm_period_elapsed(substream);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
tegra_pcm_play(prtd);
@@ -151,6 +128,8 @@ static int tegra_pcm_prepare(struct snd_pcm_substream *substream)
prtd->dma_pos = 0;
prtd->period_index = 0;
+ prtd->dma_reqid_head = 0;
+ prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1;
return 0;
}
@@ -158,7 +137,7 @@ static int tegra_pcm_prepare(struct snd_pcm_substream *substream)
static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct tegra_runtime_data *prtd = substream->runtime->private_data;
- int ret = 0;
+ int i, ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -185,17 +164,19 @@ static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
tegra_dma_cancel(prtd->dma_chan);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (prtd->dma_chan) {
- tegra_dma_dequeue_req(prtd->dma_chan,
- &prtd->dma_req1);
- tegra_dma_dequeue_req(prtd->dma_chan,
- &prtd->dma_req2);
+ for (i = 0; i < DMA_REQ_QCOUNT; i++)
+ tegra_dma_dequeue_req(prtd->dma_chan,
+ &prtd->dma_req[i]);
+ prtd->dma_reqid_head = 0;
+ prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1;
}
} else {
if (prtd->dma_chan) {
- tegra_dma_dequeue_req(prtd->dma_chan,
- &prtd->dma_req1);
- tegra_dma_dequeue_req(prtd->dma_chan,
- &prtd->dma_req2);
+ for (i = 0; i < DMA_REQ_QCOUNT; i++)
+ tegra_dma_dequeue_req(prtd->dma_chan,
+ &prtd->dma_req[i]);
+ prtd->dma_reqid_head = 0;
+ prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1;
}
}
break;
@@ -211,7 +192,13 @@ static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
int size;
- size = prtd->period_index * runtime->period_size;
+
+ size = (prtd->period_index * runtime->period_size) +
+ bytes_to_frames(runtime,
+ tegra_dma_get_transfer_count(
+ prtd->dma_chan,
+ &prtd->dma_req[prtd->dma_reqid_head],
+ false));
return (size);
}
@@ -219,7 +206,7 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = 0;
- int ret=0;
+ int i, ret=0;
/* Ensure period size is multiple of minimum DMA step size */
ret = snd_pcm_hw_constraint_step(runtime, 0,
@@ -249,15 +236,12 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
prtd->state = STATE_INVALID;
- setup_dma_request(substream,
- &prtd->dma_req1,
- dma_complete_callback,
- prtd);
-
- setup_dma_request(substream,
- &prtd->dma_req2,
- dma_complete_callback,
- prtd);
+ for (i = 0; i < DMA_REQ_QCOUNT; i++) {
+ setup_dma_request(substream,
+ &prtd->dma_req[i],
+ dma_complete_callback,
+ prtd);
+ }
prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_CONTINUOUS_DOUBLE);
if (IS_ERR(prtd->dma_chan)) {
@@ -291,6 +275,7 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct tegra_runtime_data *prtd = runtime->private_data;
+ int i;
if (!prtd) {
printk(KERN_ERR "tegra_pcm_close called with prtd == NULL\n");
@@ -301,11 +286,13 @@ static int tegra_pcm_close(struct snd_pcm_substream *substream)
if (prtd->dma_chan) {
prtd->dma_state = STATE_EXIT;
- tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req1);
- tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req2);
+ for (i = 0; i < DMA_REQ_QCOUNT; i++)
+ tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[i]);
tegra_dma_flush(prtd->dma_chan);
tegra_dma_free_channel(prtd->dma_chan);
prtd->dma_chan = NULL;
+ prtd->dma_reqid_head = 0;
+ prtd->dma_reqid_tail = DMA_REQ_QCOUNT - 1;
}
kfree(prtd);
diff --git a/sound/soc/tegra/tegra_soc.h b/sound/soc/tegra/tegra_soc.h
index 1510d6dbee76..215b4c580edb 100644
--- a/sound/soc/tegra/tegra_soc.h
+++ b/sound/soc/tegra/tegra_soc.h
@@ -76,6 +76,7 @@
#define TEGRA_VOICE_SAMPLE_RATES SNDRV_PCM_RATE_8000
#define DMA_STEP_SIZE_MIN 8
+#define DMA_REQ_QCOUNT 2
struct tegra_dma_channel;
@@ -83,7 +84,9 @@ struct tegra_runtime_data {
struct snd_pcm_substream *substream;
int size;
int dma_pos;
- struct tegra_dma_req dma_req1, dma_req2;
+ struct tegra_dma_req dma_req[DMA_REQ_QCOUNT];
+ int dma_reqid_head;
+ int dma_reqid_tail;
volatile int state;
int period_index;
int i2s_shutdown;