Example #1
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;
}
Example #2
0
static int mxs_pcm_dma_request(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct mxs_runtime_data *prtd = runtime->private_data;
	struct mxs_pcm_dma_params *dma_data =
		snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
	int desc_num = mxs_pcm_hardware.periods_max;
	int desc;
	int ret;

	if (!dma_data)
		return -ENODEV;

	prtd->params = dma_data;
	prtd->dma_ch = dma_data->dma_ch;

	ret = mxs_dma_request(prtd->dma_ch, mxs_pcm_dev,
				   prtd->params->name);
	if (ret) {
		printk(KERN_ERR "%s: Failed to request DMA channel (%d:%d)\n",
		       __func__, dma_data->dma_bus, dma_data->dma_ch);
		return ret;
	}

	/* Allocate memory for data and pio DMA descriptors */
	for (desc = 0; desc < desc_num; desc++) {
		prtd->dma_desc_array[desc] = mxs_dma_alloc_desc();
		if (prtd->dma_desc_array[desc] == NULL) {
			printk(KERN_ERR"%s Unable to allocate DMA command %d\n",
			       __func__, desc);
			goto err;
		}
	}

	ret = request_irq(prtd->params->irq, mxs_pcm_dma_irq, 0,
			  "MXS PCM DMA", substream);
	if (ret) {
		printk(KERN_ERR "%s: Unable to request DMA irq %d\n", __func__,
		       prtd->params->irq);
		goto err;
	}
	/* Enable completion interrupt */
	mxs_dma_ack_irq(prtd->dma_ch);
	mxs_dma_enable_irq(prtd->dma_ch, 1);

	return 0;

err:
	while (--desc >= 0)
		mxs_dma_free_desc(prtd->dma_desc_array[desc]);
	mxs_dma_release(prtd->dma_ch, mxs_pcm_dev);

	return ret;
}
Example #3
0
static irqreturn_t hsadc_dma_isr(int irq, void * p)
{
	struct mxs_hsadc_data *pd = (struct mxs_hsadc_data *)p;

	mxs_dma_ack_irq(pd->dma_ch);
	mxs_dma_cooked(pd->dma_ch, NULL);

	//dev_dbg(pd->dev, "dma\n");
	wake_up_interruptible(&pd->r_wait);
	return IRQ_HANDLED;
}
Example #4
0
int submit_request(struct mxs_hsadc_data* pdx, unsigned long count)
{
	unsigned long sample_count;
	memset(pdx->buf, 0, count);

	pdx->desc->cmd.cmd.bits.bytes = count;
	pdx->desc->cmd.cmd.bits.pio_words = 0;
	pdx->desc->cmd.cmd.bits.wait4end = 1;
	pdx->desc->cmd.cmd.bits.dec_sem = 1;
	pdx->desc->cmd.cmd.bits.irq = 1;
	pdx->desc->cmd.cmd.bits.command = DMA_WRITE;
	pdx->desc->cmd.address = pdx->buf_phy;
	
	if(mxs_dma_desc_append(pdx->dma_ch, pdx->desc))
	{
		return -EINVAL;
	}

	//
	// byte(s) to sample count
	//
	sample_count = 
		adc_sample_percision == 8 ? count : (count >> 1); // 10-bit & 12-bit mode a sample word is two bytes size

	writel(sample_count, pdx->hsadc_base + HSADC_SEQUENCE_SAMPLES_NUM);
	writel(1,     pdx->hsadc_base + HSADC_SEQUENCE_NUM);

	writel(1<<31 | 1<<30 | 1<<29, pdx->hsadc_base + HSADC_CTRL1); // enable irq

	mxs_dma_reset(pdx->dma_ch);
	mxs_dma_ack_irq(pdx->dma_ch);
	mxs_dma_enable_irq(pdx->dma_ch, 1);
	if(mxs_dma_enable(pdx->dma_ch))
	{
		return -EINVAL;
	}

	writel(RUN, pdx->hsadc_base + HSADC_CTRL0_SET);
	writel(SOFT_TRIGGER, pdx->hsadc_base + HSADC_CTRL0_SET);
	
	return 0;
}
Example #5
0
static int mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct mxs_runtime_data *prtd = substream->runtime->private_data;
	int ret = 0;
	switch (cmd) {

	case SNDRV_PCM_TRIGGER_START:
		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))) {
			prtd->appl_ptr_bytes =
			    frames_to_bytes(runtime,
					    runtime->control->appl_ptr);
			memmove(runtime->dma_area + 1, runtime->dma_area,
				prtd->appl_ptr_bytes - 1);
		}
		mxs_dma_enable(prtd->dma_ch);
		break;

	case SNDRV_PCM_TRIGGER_STOP:
		mxs_pcm_stop(substream);
		break;

	case SNDRV_PCM_TRIGGER_RESUME:
		if (mxs_pm_get_target() == PM_SUSPEND_MEM) {

			mxs_dma_reset(prtd->dma_ch);
			mxs_dma_ack_irq(prtd->dma_ch);
			mxs_dma_enable_irq(prtd->dma_ch, 1);
			mxs_pcm_prepare(substream);

			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))) {
				prtd->appl_ptr_bytes =
					  frames_to_bytes(runtime,
							  runtime->control->appl_ptr);
				memmove(runtime->dma_area + 1, runtime->dma_area,
					prtd->appl_ptr_bytes - 1);
			}

			mxs_dma_enable(prtd->dma_ch);
		} else
			mxs_dma_unfreeze(prtd->dma_ch);
		break;
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		mxs_dma_unfreeze(prtd->dma_ch);
		break;

	case SNDRV_PCM_TRIGGER_SUSPEND:
		if (mxs_pm_get_target() == PM_SUSPEND_MEM) {
			mxs_pcm_stop(substream);
			mdelay(30);
		}	else {
			mxs_dma_freeze(prtd->dma_ch);
			mdelay(30);
		}
		break;

	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		mxs_dma_freeze(prtd->dma_ch);
		mdelay(30);
		break;

	default:
		ret = -EINVAL;
		break;
	}

	return ret;
}