Пример #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;
}
Пример #2
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);
}
Пример #3
0
static int __devexit mxs_hsadc_remove(struct platform_device *pdev)
{
	struct mxs_hsadc_data *pd = platform_get_drvdata(pdev);
	u32 ctrl = 0;

	hsadc_cleanup_cdev(pd); // clean cdev interface

	if (pd->buf_phy)
		dma_free_coherent(NULL, DMA_BUF_SIZE, pd->buf, pd->buf_phy);

	if (pd->desc)
		mxs_dma_free_desc(pd->desc);
	
	mxs_dma_enable_irq(pd->dma_ch, 0);
	ctrl = readl(pd->hsadc_base + HSADC_CTRL1);
	ctrl &= ~(1<<31 | 1<<30 | 1<<29); // disable irq
	writel(ctrl, pd->hsadc_base + HSADC_CTRL1);
	mxs_dma_disable(pd->dma_ch);
	
	mxs_dma_release(pd->dma_ch, pd->dev);
	free_irq(pd->dev_irq, pd);
	free_irq(pd->dma_irq, pd);

	clk_disable(pd->hsadc_clk);
	clk_disable(pd->pwm_clk);
	clk_disable(pd->ref_hsadc_clk);

	clk_put(pd->hsadc_clk);
	clk_put(pd->pwm_clk);
	clk_put(pd->ref_hsadc_clk);

	iounmap(pd->pwm_base);
	iounmap(pd->hsadc_base);
	
	platform_set_drvdata(pdev, NULL);
	kfree(pd);

#if HSADC_DEBUG
	printk(KERN_INFO "%s> driver removed.\n", HSADC_DEVICE_NAME);
#endif

	return 0;
}
Пример #4
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;

	static LIST_HEAD(list);
	mxs_dma_disable(prtd->dma_ch);
	/* 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;
}
Пример #5
0
static int __devinit mxs_hsadc_probe(struct platform_device *pdev)
{
	struct mxs_hsadc_data *pd;
	struct resource *res;
	int rlevel = 0;

	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
	if (pd)
		rlevel++;
	else
		goto quit;

	pd->dev = &pdev->dev;
	platform_set_drvdata(pdev, pd);
	pd->pdev = pdev;
	rlevel++;
	
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL)
		goto quit;
	pd->hsadc_base = ioremap(res->start, res->end - res->start);
	if (pd->hsadc_base)
		rlevel++;
	else
		goto quit;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (res == NULL)
		goto quit;
	pd->pwm_base = ioremap(res->start, res->end - res->start);
	if (pd->pwm_base)
		rlevel++;
	else
		goto quit;

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (res)
		pd->dev_irq = res->start;
	else
		goto quit;

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
	if (res)
		pd->dma_irq = res->start;
	else
		goto quit;

	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
	if (res)
		pd->dma_ch = res->start;
	else
		goto quit;

	pd->ref_hsadc_clk = clk_get(NULL, "ref_hsadc");
	if (pd->ref_hsadc_clk)
		rlevel++;
	else
		goto quit;

	pd->hsadc_clk = clk_get(NULL, "hsadc");
	if (pd->hsadc_clk)
		rlevel++;
	else
		goto quit;

	pd->pwm_clk = clk_get(NULL, "pwm");
	if (pd->pwm_clk)
		rlevel++;
	else
		goto quit;

	clk_enable(pd->ref_hsadc_clk);
	clk_enable(pd->hsadc_clk);
	clk_enable(pd->pwm_clk);
	rlevel++;

	clk_set_rate(pd->ref_hsadc_clk, REF_HSADC_FREQ);
	clk_set_rate(pd->hsadc_clk, HSADC_FREQ);

    if (request_irq(pd->dma_irq, hsadc_dma_isr, 0, "hsadc dma", pd))
		goto quit;
	else
		rlevel++;

	if (request_irq(pd->dev_irq, hsadc_isr, 0, "hsadc irq", pd))
		goto quit;
	else
		rlevel++;

	if (mxs_dma_request(pd->dma_ch, pd->dev, "hsadc"))
		goto quit;
	else
		rlevel++;

	mxs_dma_disable(pd->dma_ch);

	pd->desc = mxs_dma_alloc_desc();
	if (pd->desc==NULL)
		goto quit;
	
	memset(&pd->desc->cmd, 0, sizeof(pd->desc->cmd));
	rlevel++;

	pd->buf = dma_alloc_coherent(NULL, DMA_BUF_SIZE, &pd->buf_phy, GFP_KERNEL);
	if(!pd->buf)
		goto quit;
	
	rlevel++;

	if(hsadc_init_cdev(pd))
		goto quit;

#if HSADC_DEBUG
	printk(KERN_INFO "%s> probe successed.\n", HSADC_DEVICE_NAME);
#endif

	return 0;

quit:
	pr_err("%s quit at rlevel %d\n", __func__, rlevel);
	switch (rlevel) {
	case 14:
		hsadc_cleanup_cdev(pd);
	case 13:
		if (pd->buf_phy)
			dma_free_coherent(NULL, DMA_BUF_SIZE, pd->buf, pd->buf_phy);
	case 12:
		if (pd->desc)
			mxs_dma_free_desc(pd->desc);
	case 11:
		mxs_dma_release(pd->dma_ch, pd->dev);
	case 10:
		free_irq(pd->dev_irq, pd);
	case 9:
		free_irq(pd->dma_irq, pd);
	case 8:
		clk_disable(pd->pwm_clk);
		clk_disable(pd->hsadc_clk);
		clk_disable(pd->ref_hsadc_clk);
	case 7:
		clk_put(pd->pwm_clk);
	case 6:
		clk_put(pd->hsadc_clk);
	case 5:
		clk_put(pd->ref_hsadc_clk);
	case 4:
		iounmap(pd->pwm_base);
	case 3:
		iounmap(pd->hsadc_base);
	case 2:
		platform_set_drvdata(pdev, NULL);
	case 1:
		kfree(pd);
	case 0:
	default:
		return -ENODEV;
	}
}