示例#1
0
/*
 * Stop circular DMA descriptor list
 * We should not stop DMA in a middle of current transaction once we receive
 * stop request from ALSA core. This function finds the next DMA descriptor
 * and set it up to decrement DMA channel semaphore. So the current transaction
 * is the last data transfer.
 */
static void mxs_pcm_stop(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct mxs_runtime_data *prtd = runtime->private_data;
	struct mxs_dma_info dma_info;
	int desc;

	int periods_num = prtd->dma_totsize / prtd->dma_period;
	/* Freez DMA channel for a moment */
	mxs_dma_freeze(prtd->dma_ch);
	mxs_dma_get_info(prtd->dma_ch, &dma_info);

	desc = (dma_info.buf_addr - runtime->dma_addr) / prtd->dma_period;

	if (desc >= periods_num)
		desc = 0;
	else if (desc < 0)
		desc = 0;

	/* Set up the next descriptor to decrement DMA channel sempahore */
	prtd->dma_desc_array[(desc + 1)%periods_num]->cmd.cmd.bits.bytes = 0;
	prtd->dma_desc_array[(desc + 1)%periods_num]->cmd.cmd.bits.pio_words = \
		0;
	prtd->dma_desc_array[(desc + 1)%periods_num]->cmd.cmd.bits.dec_sem = 1;
	prtd->dma_desc_array[(desc + 1)%periods_num]->cmd.cmd.bits.irq = 0;
	prtd->dma_desc_array[(desc + 1)%periods_num]->cmd.cmd.bits.command = \
		NO_DMA_XFER;

	mxs_dma_unfreeze(prtd->dma_ch);

	mxs_dma_disable(prtd->dma_ch);
}
示例#2
0
static irqreturn_t mxs_pcm_dma_irq(int irq, void *dev_id)
{
	struct snd_pcm_substream *substream = dev_id;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct mxs_runtime_data *prtd = substream->runtime->private_data;
	struct mxs_dma_info dma_info;
	void *pdma;
	unsigned long prev_appl_offset, appl_count, cont, appl_ptr_bytes;

	mxs_dma_get_info(prtd->dma_ch, &dma_info);

	if (dma_info.status) {
		printk(KERN_WARNING "%s: DMA audio channel %d (%s) error\n",
			__func__, prtd->params->dma_ch, prtd->params->name);
		mxs_dma_ack_irq(prtd->dma_ch);
	} else {
		if ((prtd->params->dma_ch == MXS_DMA_CHANNEL_AHB_APBX_SPDIF) &&
		    (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
		    (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) &&
		    ((prtd->format == SNDRV_PCM_FORMAT_S24_LE)
		     || (prtd->format == SNDRV_PCM_FORMAT_S20_3LE))) {

			appl_ptr_bytes =
			    frames_to_bytes(runtime,
					    runtime->control->appl_ptr);

			appl_count = appl_ptr_bytes - prtd->appl_ptr_bytes;
			prev_appl_offset =
			    prtd->appl_ptr_bytes % prtd->dma_totsize;
			cont = prtd->dma_totsize - prev_appl_offset;

			if (appl_count > cont) {
				pdma = runtime->dma_area + prev_appl_offset;
				memmove(pdma + 1, pdma, cont - 1);
				pdma = runtime->dma_area;
				memmove(pdma + 1, pdma, appl_count - cont - 1);
			} else {
				pdma = runtime->dma_area + prev_appl_offset;
				memmove(pdma + 1, pdma, appl_count - 1);
			}
			prtd->appl_ptr_bytes = appl_ptr_bytes;
		}
		mxs_dma_ack_irq(prtd->dma_ch);
		snd_pcm_period_elapsed(substream);
	}
	return IRQ_HANDLED;
}
示例#3
0
static snd_pcm_uframes_t
mxs_pcm_pointer(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct mxs_runtime_data *prtd = runtime->private_data;
	struct mxs_dma_info dma_info;
	unsigned int offset;
	dma_addr_t pos;

	mxs_dma_get_info(prtd->params->dma_ch, &dma_info);
	pos = dma_info.buf_addr;

	offset = bytes_to_frames(runtime, pos - runtime->dma_addr);

	if (offset >= runtime->buffer_size)
		offset = 0;

	return offset;
}