static enum hrtimer_restart jz_asoc_hrtimer_callback(struct hrtimer *hr_timer) { struct jz_pcm_runtime_data *prtd = container_of(hr_timer, struct jz_pcm_runtime_data, hr_timer); struct snd_pcm_substream *substream = prtd->substream; struct dma_chan *dma_chan = prtd->dma_chan; dma_addr_t pdma_addr = 0; dma_addr_t pdma_addr_1 = 0; size_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream); size_t curr_pos = 0; enum dma_transfer_direction direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; if (atomic_read(&prtd->stopped)) goto out; hrtimer_start(&prtd->hr_timer, prtd->expires , HRTIMER_MODE_REL); pdma_addr = dma_chan->device->get_current_trans_addr(dma_chan, NULL, NULL, direction); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { curr_pos = snd_pcm_get_pos_algin_period(substream, pdma_addr); if (curr_pos == prtd->pos) goto out; #ifdef CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM if (prtd->pos < curr_pos) { memset(snd_pcm_get_ptr(substream, prtd->pos), 0 , (curr_pos - prtd->pos)); } if (prtd->pos > curr_pos) { memset(snd_pcm_get_ptr(substream, prtd->pos), 0, (buffer_bytes - prtd->pos)); memset(snd_pcm_get_ptr(substream, 0), 0, curr_pos); } #endif prtd->pos = curr_pos; } else { curr_pos = snd_pcm_get_pos(substream, pdma_addr); if (curr_pos == prtd->pos) goto out; prtd->pos = curr_pos; /*pdma_addr_1 = pdma_addr - 64;*/ /*while(pdma_addr_1 < pdma_addr)*/ /*{*/ /*printk("[0] = 0x%08x [1] = 0x%08x\n", *(unsigned short *)(pdma_addr_1 | 0xa0000000), *(unsigned short *)((pdma_addr_1 | 0xa0000000)+2));*/ /*pdma_addr_1 += 4;*/ /*}*/ } //printk("curr_pos = %d buffer_bytes = %d\n", curr_pos, buffer_bytes); snd_pcm_period_elapsed(substream); out: return HRTIMER_NORESTART; }
static void jz_asoc_dma_callback(void *data) { struct snd_pcm_substream *substream = data; struct jz_pcm_runtime_data *prtd = substream->runtime->private_data; void* old_pos_addr = snd_pcm_get_ptr(substream, prtd->pos); DMA_SUBSTREAM_MSG(substream,"%s enter stopped_pending == %d\n", __func__, atomic_read(&prtd->stopped_pending)); if (!atomic_dec_if_positive(&prtd->stopped_pending)) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; DMA_SUBSTREAM_MSG(substream,"stop real\n"); cancel_delayed_work(&prtd->dwork_stop_dma); dmaengine_terminate_all(prtd->dma_chan); if (cpu_dai->driver->ops->trigger) cpu_dai->driver->ops->trigger(substream, prtd->stopped_cmd, cpu_dai); return; } if (!IS_ERR_OR_NULL(prtd->file) && !work_pending(&prtd->debug_work)) { prtd->copy_start = old_pos_addr; prtd->copy_length = snd_pcm_lib_period_bytes(substream); schedule_work(&prtd->debug_work); } else { #if defined(CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { DMA_DEBUG_MSG("dma start %x pos %p size %d\n", substream->runtime->dma_addr, old_pos_addr, snd_pcm_lib_period_bytes(substream)); memset(old_pos_addr, 0, snd_pcm_lib_period_bytes(substream)); } #endif } prtd->pos += snd_pcm_lib_period_bytes(substream); if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream)) prtd->pos = 0; snd_pcm_period_elapsed(substream); return; }
static int jz_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct jz_pcm_runtime_data *prtd = substream->runtime->private_data; #ifdef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; #endif #ifdef CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM size_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream); #endif int ret; DMA_SUBSTREAM_MSG(substream,"%s enter cmd %d\n", __func__, cmd); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: #ifndef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE if (atomic_read(&prtd->stopped_pending)) return -EPIPE; #endif DMA_SUBSTREAM_MSG(substream,"start trigger\n"); ret = jz_asoc_dma_prepare_and_submit(substream); if (ret) return ret; dma_async_issue_pending(prtd->dma_chan); #ifdef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE atomic_set(&prtd->stopped, 0); hrtimer_start(&prtd->hr_timer, prtd->expires , HRTIMER_MODE_REL); #endif break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: DMA_SUBSTREAM_MSG(substream,"stop trigger\n"); #ifdef CONFIG_JZ_ASOC_DMA_HRTIMER_MODE atomic_set(&prtd->stopped, 1); /* To make sure there is not data transfer on AHB bus, * then we can stop the dma, Wait tur or ror happen */ if (cpu_dai->driver->ops->trigger) { ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; } dmaengine_terminate_all(prtd->dma_chan); #else /* To make sure there is not data transfer on AHB bus, * then we can stop the dma, Wait dma callback happen */ if (dmaengine_terminate_all(prtd->dma_chan)) { prtd->stopped_cmd = cmd; atomic_set(&prtd->stopped_pending, 1); schedule_delayed_work(&prtd->dwork_stop_dma, prtd->delayed_jiffies); } #endif #ifdef CONFIG_JZ_ASOC_DMA_AUTO_CLR_DRT_MEM printk(KERN_DEBUG"show the time memset1 %d\n", buffer_bytes); memset(snd_pcm_get_ptr(substream, 0), 0, buffer_bytes); printk(KERN_DEBUG"show the time memset2 %d\n", buffer_bytes); #endif break; default: return -EINVAL; } return 0; }