Beispiel #1
0
static int mxs_pcm_close(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct mxs_runtime_data *prtd = runtime->private_data;
	int desc_num = mxs_pcm_hardware.periods_max;
	int desc;
	int timeo = 20;

	static LIST_HEAD(list);
	mxs_dma_disable(prtd->dma_ch);

	/* Wait until the DMA chain is finished. */
	while (mxs_dma_read_semaphore(prtd->dma_ch)) {
		if (!timeo--)
			break;
		pr_debug("The sema is not zero now\n");
		msleep(10);
	}
	if (timeo <= 0)
		pr_warn("Is the DMA channel dead?\n");

	/* Free DMA irq */
	free_irq(prtd->params->irq, substream);
	mxs_dma_get_cooked(prtd->dma_ch, &list);
	/* Free DMA channel*/
	for (desc = 0; desc < desc_num; desc++)
		mxs_dma_free_desc(prtd->dma_desc_array[desc]);
	mxs_dma_release(prtd->dma_ch, mxs_pcm_dev);

	/* Free private runtime data */
	kfree(prtd);
	return 0;
}
Beispiel #2
0
/*
 * Enable a DMA channel.
 *
 * If the given channel has any DMA descriptors on its active list, this
 * function causes the DMA hardware to begin processing them.
 *
 * This function marks the DMA channel as "busy," whether or not there are any
 * descriptors to process.
 */
static int mxs_dma_enable(int channel)
{
	struct apbh_dma *apbh = apbh_dma;
	unsigned int sem;
	struct mxs_dma_chan *pchan;
	struct mxs_dma_desc *pdesc;
	int channel_bit, ret;

	ret = mxs_dma_validate_chan(channel);
	if (ret)
		return ret;

	pchan = mxs_dma_channels + channel;

	if (pchan->pending_num == 0) {
		pchan->flags |= MXS_DMA_FLAGS_BUSY;
		return 0;
	}

	pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node);
	if (pdesc == NULL)
		return -EFAULT;

	if (pchan->flags & MXS_DMA_FLAGS_BUSY) {
		if (!(pdesc->cmd.data & MXS_DMA_DESC_CHAIN))
			return 0;

		sem = mxs_dma_read_semaphore(channel);
		if (sem == 0)
			return 0;

		if (sem == 1) {
			pdesc = list_entry(pdesc->node.next,
					   struct mxs_dma_desc, node);
			if (apbh_dma_is_imx23(apbh))
				writel(mxs_dma_cmd_address(pdesc),
					apbh->regs + HW_APBHX_CHn_NXTCMDAR_MX23(channel));
			else
				writel(mxs_dma_cmd_address(pdesc),
					apbh->regs + HW_APBHX_CHn_NXTCMDAR_MX28(channel));
		}

		if (apbh_dma_is_imx23(apbh))
			writel(pchan->pending_num,
					apbh->regs + HW_APBHX_CHn_SEMA_MX23(channel));
		else
			writel(pchan->pending_num,
					apbh->regs + HW_APBHX_CHn_SEMA_MX28(channel));

		pchan->active_num += pchan->pending_num;
		pchan->pending_num = 0;
	} else {
Beispiel #3
0
/*
 * Enable a DMA channel.
 *
 * If the given channel has any DMA descriptors on its active list, this
 * function causes the DMA hardware to begin processing them.
 *
 * This function marks the DMA channel as "busy," whether or not there are any
 * descriptors to process.
 */
static int mxs_dma_enable(int channel)
{
	struct mxs_apbh_regs *apbh_regs =
		(struct mxs_apbh_regs *)MXS_APBH_BASE;
	unsigned int sem;
	struct mxs_dma_chan *pchan;
	struct mxs_dma_desc *pdesc;
	int ret;

	ret = mxs_dma_validate_chan(channel);
	if (ret)
		return ret;

	pchan = mxs_dma_channels + channel;

	if (pchan->pending_num == 0) {
		pchan->flags |= MXS_DMA_FLAGS_BUSY;
		return 0;
	}

	pdesc = list_first_entry(&pchan->active, struct mxs_dma_desc, node);
	if (pdesc == NULL)
		return -EFAULT;

	if (pchan->flags & MXS_DMA_FLAGS_BUSY) {
		if (!(pdesc->cmd.data & MXS_DMA_DESC_CHAIN))
			return 0;

		sem = mxs_dma_read_semaphore(channel);
		if (sem == 0)
			return 0;

		if (sem == 1) {
			pdesc = list_entry(pdesc->node.next,
					   struct mxs_dma_desc, node);
			writel(mxs_dma_cmd_address(pdesc),
				&apbh_regs->ch[channel].hw_apbh_ch_nxtcmdar);
		}
		writel(pchan->pending_num,
			&apbh_regs->ch[channel].hw_apbh_ch_sema);
		pchan->active_num += pchan->pending_num;
		pchan->pending_num = 0;
	} else {