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

📄 s3c24xx-iis.c

📁 基于linux kernel 2.6.20的UDA1341声音芯片的声卡驱动
💻 C
📖 第 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 1static 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);#endifs3c24xx_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_PMstatic 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 + -