static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; unsigned long flags; switch (cmd) { case SNDRV_PCM_TRIGGER_START: prtd->dma_pos = 0; prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size); prtd->period_index = 0; prtd->dma_req_idx = 0; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: spin_lock_irqsave(&prtd->lock, flags); prtd->running = 1; #if 0 if( prtd->dma_chan ){ prtd->pcm_timeout_tick = jiffies; del_timer(&prtd->pcm_timeout); prtd->pcm_timeout.function = pcm_timeout_func; prtd->pcm_timeout.expires = jiffies + msecs_to_jiffies((runtime->period_size/(runtime->rate/1000))*runtime->periods*2); prtd->pcm_timeout.data = (unsigned long)prtd; add_timer(&prtd->pcm_timeout); prtd->callback_time = jiffies; } #endif spin_unlock_irqrestore(&prtd->lock, flags); if( prtd->dma_chan ){ tegra_pcm_queue_dma(prtd); tegra_pcm_queue_dma(prtd); } break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: spin_lock_irqsave(&prtd->lock, flags); prtd->running = 0; #if 0 if( prtd->dma_chan ){ del_timer(&prtd->pcm_timeout); } #endif spin_unlock_irqrestore(&prtd->lock, flags); if( prtd->dma_chan ){ tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[0]); tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[1]); } break; default: return -EINVAL; } return 0; }
static void dma_complete_callback(struct tegra_dma_req *req) { struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev; struct snd_pcm_substream *substream = prtd->substream; struct snd_pcm_runtime *runtime = substream->runtime; spin_lock(&prtd->lock); if (!prtd->running) { spin_unlock(&prtd->lock); return; } if (++prtd->period_index >= runtime->periods) prtd->period_index = 0; tegra_pcm_queue_dma(prtd); #if 0 prtd->pcm_timeout_tick = jiffies; del_timer(&prtd->pcm_timeout); prtd->pcm_timeout.function = pcm_timeout_func; prtd->pcm_timeout.expires = jiffies + msecs_to_jiffies((runtime->period_size/(runtime->rate/1000))*runtime->periods*2); prtd->pcm_timeout.data = (unsigned long)prtd; add_timer(&prtd->pcm_timeout); // for error debuging. if( jiffies_to_msecs(jiffies - prtd->callback_time) > (runtime->period_size/(runtime->rate/1000))*2 ) dev_err(substream->pcm->dev, "dma_complete_callback time error!!!\n"); prtd->callback_time = jiffies; #endif spin_unlock(&prtd->lock); snd_pcm_period_elapsed(substream); }
int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_pcm_dma_params * dmap; unsigned long flags; int i; dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (!dmap) return 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: prtd->dma_pos = 0; prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size); prtd->period_index = 0; prtd->dma_req_idx = 0; if (prtd->disable_intr) { prtd->dma_req_count = 1; prtd->dma_req[0].complete = NULL; } else if (!prtd->dma_req[0].complete) { prtd->dma_req[0].complete = dma_complete_callback; prtd->dma_req_count = (MAX_DMA_REQ_COUNT <= runtime->periods) ? MAX_DMA_REQ_COUNT : runtime->periods; } /* Fall-through */ case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: spin_lock_irqsave(&prtd->lock, flags); prtd->running = 1; spin_unlock_irqrestore(&prtd->lock, flags); for (i = 0; i < prtd->dma_req_count; i++) tegra_pcm_queue_dma(prtd); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: spin_lock_irqsave(&prtd->lock, flags); prtd->running = 0; spin_unlock_irqrestore(&prtd->lock, flags); tegra_dma_cancel(prtd->dma_chan); for (i = 0; i < prtd->dma_req_count; i++) { if (prtd->dma_req[i].complete && (prtd->dma_req[i].status == -TEGRA_DMA_REQ_ERROR_ABORTED)) prtd->dma_req[i].complete(&prtd->dma_req[i]); } break; default: return -EINVAL; } return 0; }
static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; unsigned long flags; switch (cmd) { case SNDRV_PCM_TRIGGER_START: prtd->dma_pos = 0; prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size); prtd->period_index = 0; prtd->dma_req_idx = 0; /* Fall-through */ case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: #ifdef CONFIG_HAS_WAKELOCK wake_lock(&prtd->tegra_wake_lock); #endif spin_lock_irqsave(&prtd->lock, flags); prtd->running = 1; spin_unlock_irqrestore(&prtd->lock, flags); tegra_pcm_queue_dma(prtd); tegra_pcm_queue_dma(prtd); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: spin_lock_irqsave(&prtd->lock, flags); prtd->running = 0; spin_unlock_irqrestore(&prtd->lock, flags); tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[0]); tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[1]); #ifdef CONFIG_HAS_WAKELOCK wake_unlock(&prtd->tegra_wake_lock); #endif break; default: return -EINVAL; } return 0; }
static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct tegra_runtime_data *prtd = runtime->private_data; unsigned long flags; switch (cmd) { case SNDRV_PCM_TRIGGER_START: prtd->dma_pos = 0; prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size); prtd->period_index = 0; prtd->dma_req_idx = 0; /* Fall-through */ case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: spin_lock_irqsave(&prtd->lock, flags); prtd->running = 1; spin_unlock_irqrestore(&prtd->lock, flags); tegra_pcm_queue_dma(prtd); tegra_pcm_queue_dma(prtd); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: spin_lock_irqsave(&prtd->lock, flags); prtd->running = 0; spin_unlock_irqrestore(&prtd->lock, flags); tegra_dma_cancel(prtd->dma_chan); if (prtd->dma_req[0].status == -TEGRA_DMA_REQ_ERROR_ABORTED) prtd->dma_req[0].complete(&prtd->dma_req[0]); if (prtd->dma_req[1].status == -TEGRA_DMA_REQ_ERROR_ABORTED) prtd->dma_req[1].complete(&prtd->dma_req[1]); break; default: return -EINVAL; } return 0; }
static void dma_complete_callback(struct tegra_dma_req *req) { struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev; struct snd_pcm_substream *substream = prtd->substream; struct snd_pcm_runtime *runtime = substream->runtime; spin_lock(&prtd->lock); if (!prtd->running) { spin_unlock(&prtd->lock); return; } if (++prtd->period_index >= runtime->periods) prtd->period_index = 0; tegra_pcm_queue_dma(prtd); spin_unlock(&prtd->lock); snd_pcm_period_elapsed(substream); }