⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c24xx-iis_c.txt

📁 2410uda1341的测试代码
💻 TXT
📖 第 1 页 / 共 3 页
字号:
		else
			s3c24xx_snd_txctrl(chip, 0);
		
		s3c2410_dma_ctrl(or->dma_ch, S3C2410_DMAOP_STOP);
		s3c24xx_snd_showdma(or);	
		s3c24xx_snd_showregs(chip);

		ret = 0;
		break;

	default:
		ret = -EINVAL;
	}

 exit_err:
	spin_unlock_irqrestore(&or->lock, flags);
	return ret;
}


/* pointer callback */
static snd_pcm_uframes_t s3c24xx_snd_pcm_pointer(struct snd_pcm_substream *substream)
{
	s3c24xx_runtime_t *or = substream->runtime->private_data;
	unsigned long flags;
	unsigned long res;
	dma_addr_t src, dst;

	pr_debug("--- %s\n", __FUNCTION__);
	spin_lock_irqsave(&or->lock, flags);
	s3c2410_dma_getposition(or->dma_ch, &src, &dst);

	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
		res = dst - or->dma_start;
	else
		res = src - or->dma_start;

	spin_unlock_irqrestore(&or->lock, flags);

	/* we seem to be getting the odd error from the pcm library due
	 * to out-of-bounds pointers. this is maybe due to the dma engine
	 * not having loaded the new values for the channel before being
	 * callled... (todo - fix )
	 */

	if (res > (or->dma_end - or->dma_start))
		DBG("%s: %lx,%lx (%lx) from %lx,%lx\n", __FUNCTION__,
		    (long)src, (long)dst, res,
		    (long)or->dma_start, (long)or->dma_end);

	if (res >= snd_pcm_lib_buffer_bytes(substream)) {
		if (res > snd_pcm_lib_buffer_bytes(substream))
			DBG("%s: res %lx >= %lx\n", __FUNCTION__,
			    res, (long)snd_pcm_lib_buffer_bytes(substream));
		
		if (res == snd_pcm_lib_buffer_bytes(substream))
			res = 0;
	}

	return bytes_to_frames(substream->runtime, res);
}

static int s3c24xx_snd_pcm_mmap(struct snd_pcm_substream *substream,
				struct vm_area_struct *vma)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	int ret;

	pr_debug("-*- %s\n", __FUNCTION__);

	ret = dma_mmap_writecombine(substream->pcm->card->dev, vma,
				    runtime->dma_area,
				    runtime->dma_addr,
				    runtime->dma_bytes);
	pr_debug("-*- %s: %d\n", __FUNCTION__, ret);
	return ret;
}

static int sc24xx_snd_dma_prealloc(struct snd_pcm *pcm, int stream)
{
	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
	struct snd_dma_buffer *buf = &substream->dma_buffer;
	size_t size = s3c24xx_snd_hw.buffer_bytes_max;

	pr_debug("--- %s\n", __FUNCTION__);
	buf->dev.type = SNDRV_DMA_TYPE_DEV;
	buf->dev.dev = pcm->card->dev;
	buf->private_data = NULL;

	buf->bytes = size;
	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
					   &buf->addr, GFP_KERNEL);

	if (buf->area == NULL) {
		dev_err(pcm->card->dev, "failed to allocate dma buff\n");
		return -ENOMEM;
	}

	DBG("%s: stream %d: dma area %p, 0x%lx\n", __FUNCTION__,
	    stream, buf->area, (long)buf->addr);

	return 0;
}

static void sc24xx_snd_dma_free(struct snd_pcm *pcm, int stream)
{
	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
	struct snd_dma_buffer *buf = &substream->dma_buffer;
	size_t size = s3c24xx_snd_hw.buffer_bytes_max;

	pr_debug("--- %s\n", __FUNCTION__);
	dma_free_writecombine(pcm->card->dev, size, buf->area, buf->addr);

	buf->area = NULL;
	buf->addr = (dma_addr_t)NULL;
}

/* operators */
static struct snd_pcm_ops s3c24xx_snd_pcm_ops = {
	.open		= s3c24xx_snd_open,
	.close		= s3c24xx_snd_close,
	.ioctl		= snd_pcm_lib_ioctl,
	.hw_params	= s3c24xx_snd_pcm_hw_params,
	.hw_free	= s3c24xx_snd_pcm_hw_free,
	.prepare	= s3c24xx_snd_pcm_prepare,
	.trigger	= s3c24xx_snd_pcm_trigger,
	.pointer	= s3c24xx_snd_pcm_pointer,
	.mmap		= s3c24xx_snd_pcm_mmap,
};

static int snd_card_s3c24xx_pcm(s3c24xx_card_t *card)
{
	struct snd_pcm *pcm;
	int err;

	pr_debug("--- %s\n", __FUNCTION__);
	DBG("snd_card_s3c24xx_pcm: card=%p\n", card);

	err = snd_pcm_new(card->card, "S3C24XX-IIS", 0, 1, 1, &pcm);
	if (err < 0) {
		printk(KERN_ERR "cannot register new pcm");
		return err;
	}

	DBG("snd_card_s3c24xx_pcm: new pcm %p\n", pcm);

	card->pcm	  = pcm;
	pcm->private_data = card;

	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &s3c24xx_snd_pcm_ops);
	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &s3c24xx_snd_pcm_ops);

	/* allocate dma resources */

	err = sc24xx_snd_dma_prealloc(pcm, SNDRV_PCM_STREAM_PLAYBACK);
	if (err)
		goto exit_err;

	err = sc24xx_snd_dma_prealloc(pcm, SNDRV_PCM_STREAM_CAPTURE);
	if (err)
		goto exit_err;

	strcpy(pcm->name, "s3c24xx");

	DBG("snd_card_s3c24xx_pcm: ok\n");

	return 0;

 exit_err:
	return err;
}

static int s3c24xx_iis_free(s3c24xx_card_t *card)
{
	pr_debug("--- %s\n", __FUNCTION__);
	sc24xx_snd_dma_free(card->pcm, SNDRV_PCM_STREAM_PLAYBACK);
	sc24xx_snd_dma_free(card->pcm, SNDRV_PCM_STREAM_CAPTURE);
}

static int s3c24xx_iis_dma_init(s3c24xx_card_t *card)
{
	int err = 0;

	pr_debug("--- %s\n", __FUNCTION__);
	our_card->playback.dma_ch = DMACH_I2S_OUT;
	our_card->capture.dma_ch = DMACH_I2S_IN;

	err = s3c2410_dma_request(our_card->playback.dma_ch,
				  &s3c24xx_snd_playback_client, NULL);
	if (err) {
		printk(KERN_ERR "failed to get dma channel\n");
		return err;
	}

	s3c2410_dma_devconfig(our_card->playback.dma_ch,
			      S3C2410_DMASRC_MEM, 0x03,
			      S3C2410_PA_IIS + S3C2410_IISFIFO);

	s3c2410_dma_config(our_card->playback.dma_ch,
			   2, S3C2410_DCON_CH2_I2SSDO|S3C2410_DCON_SYNC_PCLK|S3C2410_DCON_HANDSHAKE);

	s3c2410_dma_set_buffdone_fn(our_card->playback.dma_ch,
				    s3c24xx_snd_playback_buffdone);

	/* attach capture channel */

	err = s3c2410_dma_request(our_card->capture.dma_ch,
				  &s3c24xx_snd_capture_client, NULL);
	if (err) {
		printk(KERN_ERR "failed to get dma channel\n");
		return err;
	}

	s3c2410_dma_config(our_card->capture.dma_ch,
			   2, S3C2410_DCON_HANDSHAKE |
			   S3C2410_DCON_SYNC_PCLK |
			   (2 << S3C2410_DCON_SRCSHIFT));

	s3c2410_dma_devconfig(our_card->capture.dma_ch,
			      S3C2410_DMASRC_HW, 0x3,
			      S3C2410_PA_IIS + S3C2410_IISFIFO);

	s3c2410_dma_set_buffdone_fn(our_card->capture.dma_ch,
				    s3c24xx_snd_capture_buffdone);

	return 0;
}

static int s3c24xx_iis_dma_free(s3c24xx_card_t *card)
{
	pr_debug("--- %s\n", __FUNCTION__);
	s3c2410_dma_free(card->capture.dma_ch, &s3c24xx_snd_capture_client);
	s3c2410_dma_free(card->playback.dma_ch, &s3c24xx_snd_playback_client);
}

int s3c24xx_iis_remove(struct device *dev)
{
	s3c24xx_card_t *card = dev_get_drvdata(dev);

	pr_debug("--- %s\n", __FUNCTION__);
	card = dev_get_drvdata(dev);
	if (card == NULL)
		return 0;

	s3c24xx_iis_dma_free(card);
	s3c24xx_iis_free(card);

	kfree(card);
	dev_set_drvdata(dev, NULL);

	return 0;
}

EXPORT_SYMBOL(s3c24xx_iis_remove);

#if 1

static ssize_t s3c24xx_iis_show_regs(struct device *dev, struct device_attribute *attr, char *buf)
{
	s3c24xx_card_t *our_card = dev_get_drvdata(dev);

	pr_debug("--- %s\n", __FUNCTION__);
	return snprintf(buf, PAGE_SIZE,
			"IISMOD = %08x\n"
			"IISCON = %08x\n"
			"IISPSR = %08x\n"
			"IISFCON= %08x\n",
			readl(our_card->regs + S3C2410_IISCON),
			readl(our_card->regs + S3C2410_IISMOD),
			readl(our_card->regs + S3C2410_IISPSR),
			readl(our_card->regs + S3C2410_IISFCON));
}

static DEVICE_ATTR(regs, S_IRUGO, s3c24xx_iis_show_regs, NULL);
#endif

s3c24xx_card_t *s3c24xx_iis_probe(struct device *dev)
{
	struct s3c24xx_platdata_iis *pdata = dev->platform_data;
	struct snd_card *card;
	int err;

	pr_debug("--- %s\n", __FUNCTION__);
	dev_info(dev, "probe called\n");

	card = snd_card_new(-1, 0, THIS_MODULE, sizeof(s3c24xx_card_t));

	our_card = (s3c24xx_card_t *)card->private_data;

	if (card == NULL) {
		printk(KERN_ERR "snd_card_new() failed\n");
		err = -EINVAL;
		goto exit_err;
	}
	
	our_card->card     = card;
	our_card->device   = dev;
	our_card->base_ops = (pdata) ? pdata->ops : NULL;

	/* get resources such as clocks and IO */

	our_card->clock = clk_get(dev, "iis");
	DBG("our_card.clock = %p\n", our_card->clock);

	if (IS_ERR(our_card->clock)) {
		err = PTR_ERR(our_card->clock);
		goto exit_err;
	}

	our_card->regs = ioremap(S3C2410_PA_IIS, 0x100);
	if (our_card->regs == NULL) {
		err = -ENXIO;
		goto exit_err;
	}

	DBG("our_card.regs at %p\n", our_card->regs);
	
	clk_enable(our_card->clock);

	init_MUTEX(&our_card->sem);
	spin_lock_init(&our_card->capture.lock);
	spin_lock_init(&our_card->playback.lock);

	/* ensure the channels are both shutdown */

	s3c24xx_snd_txctrl(our_card, 0);
	s3c24xx_snd_rxctrl(our_card, 0);

	/* static dma channel setup for the moment */

	err = s3c24xx_iis_dma_init(our_card);
	if (err)
		goto exit_err;

	/* default names for s3c2410 audio driver */

	strcpy(card->driver,    "S3C24XX");
	strcpy(card->shortname, "S3C24XX");
	strcpy(card->longname,  "Samsung S3C24XX");

	err = snd_card_s3c24xx_pcm(our_card);
	if (err) {
		printk(KERN_ERR "failed to init pcm devices\n");
		goto exit_err;
	}

	dev_info(dev, "soundcard attached ok (%p)\n", our_card);

	dev_set_drvdata(dev, our_card);
	device_create_file(dev, &dev_attr_regs);
	return our_card;

 exit_err:
	dev_err(dev, "error initialised card (%d)\n", err);
	snd_card_free(our_card->card);
	return ERR_PTR(err);
}

EXPORT_SYMBOL(s3c24xx_iis_probe);

#ifdef CONFIG_PM

static int call_suspend(struct s3c24xx_iis_ops *ops)
{
	pr_debug("--- %s\n", __FUNCTION__);
	if (ops && ops->suspend)
		return (ops->suspend)(ops);

	return 0;
}

int s3c24xx_iis_suspend(struct device *dev, u32 state)
{
	s3c24xx_card_t *card = dev_get_drvdata(dev);

	pr_debug("--- %s\n", __FUNCTION__);
	if (card) {
		if (card->card->power_state == SNDRV_CTL_POWER_D3cold)
			goto exit;

		/* inform sound core that we wish to suspend */

		snd_pcm_suspend_all(card->pcm);
		snd_power_change_state(card->card, SNDRV_CTL_POWER_D3cold);

		/* inform any of our clients */

		call_suspend(card->chip_ops);
		call_suspend(card->base_ops);

		clk_disable(card->clock);
	}

 exit:
	return 0;
}

static int call_resume(struct s3c24xx_iis_ops *ops)
{
	pr_debug("--- %s\n", __FUNCTION__);
	if (ops && ops->resume)
		return (ops->resume)(ops);

	return 0;
}

int s3c24xx_iis_resume(struct device *dev)
{
	s3c24xx_card_t *card = dev_get_drvdata(dev);

	pr_debug("--- %s\n", __FUNCTION__);
	if (card) {
		if (card->card->power_state == SNDRV_CTL_POWER_D0)
			goto exit;

		clk_enable(card->clock);

		/* inform any of our clients */

		call_resume(card->base_ops);
		call_resume(card->chip_ops);

		/* inform sound core that we wish to resume */

		snd_power_change_state(card->card, SNDRV_CTL_POWER_D0);
	}

 exit:
	return 0;
}

EXPORT_SYMBOL(s3c24xx_iis_suspend);
EXPORT_SYMBOL(s3c24xx_iis_resume);

#endif /* CONFIG_PM */

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("S3C4XX iis driver");
MODULE_AUTHOR("Ben Dooks");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -