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

📄 s3c24xx-iis.c

📁 基于linux kernel 2.6.20的UDA1341声音芯片的声卡驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* sound/arm/s3c24xx-iis.c * * (c) 2004-2005 Simtec Electronics *	http://armlinux.simtec.co.uk/ *	Ben Dooks <ben@simtec.co.uk> * * S3C24XX ALSA IIS audio driver core * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation.*//* Notes: *   The I2S pins that are needed (SCLK,LRCLK,SDO,SDI) are always *   configured when the I2S system is active. SDO and SDI are *   always configured even if the system is not open for both *   capture and playback. This ensures that if the DAC is *   not muted, then the output line is held in place, reducing *   the chance of any random data being picked up. CDCLK is *   only selected when the system is in master mode. * *   When the I2S unit is not being used, all pins are set to *   input, so either the internal resistors need to be configured *   or the lines need to have external pull-up or pull-downs.*///#define DEBUG 1#include "debug.h"#include <linux/autoconf.h>#include <sound/driver.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/ioctl.h>#include <linux/delay.h>#include <linux/device.h>#include <linux/pm.h>#include <linux/dma-mapping.h>#include <linux/clk.h>#include <asm/hardware.h>#include <asm/dma.h>#include <asm/io.h>#include <sound/driver.h>#include <sound/core.h>#include <sound/pcm.h>#include <sound/initval.h>#include <asm/arch/regs-iis.h>#include <asm/arch/regs-gpio.h>#include <asm/arch/audio.h>#include "s3c24xx-iis.h"/* debugging macros */#ifdef DEBUG#undef pr_debug#define pr_debug(fmt,arg...) printk(fmt,##arg)#endif#ifndef DEBUG #define DBG(x...)#else#define DBG(x...) do { printk(x); } while(0)#endif#ifndef DEBUG#define DBG_DMA(x...)#else#define DBG_DMA(x...) do { printk(x); } while(0)#endifstatic s3c24xx_card_t *our_card;/* s3c24xx_snd_capture_hw * * the default initialiser for the capture hardware stream, * not to be altered*/static struct snd_pcm_hardware s3c24xx_snd_hw = {	.info			= ( SNDRV_PCM_INFO_INTERLEAVED |				    SNDRV_PCM_INFO_MMAP | 				    SNDRV_PCM_INFO_MMAP_VALID |				    SNDRV_PCM_INFO_PAUSE |				    SNDRV_PCM_INFO_RESUME ),#if 1	/* only this is supported by our codec */	.formats                = SNDRV_PCM_FMTBIT_S16_LE,#else	.formats		= ( SNDRV_PCM_FMTBIT_S16_LE |				    SNDRV_PCM_FMTBIT_U16_LE |				    SNDRV_PCM_FMTBIT_U8 |				    SNDRV_PCM_FMTBIT_S8 ),#endif	.rates			= SNDRV_PCM_RATE_8000_44100, // | SNDRV_PCM_RATE_KNOT,	.rate_min		= 8000,	.rate_max		= 48000,	.channels_min		= 2,	.channels_max		= 2,	.buffer_bytes_max	= 64*1024,	.period_bytes_min	= 4,	.period_bytes_max	= PAGE_SIZE,	.periods_min		= 2,	.periods_max		= 128,	.fifo_size		= 32,};static struct s3c2410_dma_client s3c24xx_snd_playback_client = {	.name		= "S3C24XX Audio Playback",};static struct s3c2410_dma_client s3c24xx_snd_capture_client = {	.name		= "S3C24XX Audio Capture",};/* debug helpers */static void s3c24xx_snd_showregs(s3c24xx_card_t *card){	pr_debug("--- %s\n", __FUNCTION__);#ifdef DEBUG	printk(KERN_DEBUG "IIS: CON=%08x, MOD=%08x, PSR=%08x, FCON=%08x\n",	       readl(card->regs + S3C2410_IISCON),	       readl(card->regs + S3C2410_IISMOD),	       readl(card->regs + S3C2410_IISPSR),	       readl(card->regs + S3C2410_IISFCON));#endif}static void s3c24xx_snd_showdma(s3c24xx_runtime_t *or){	dma_addr_t src, dst;	pr_debug("--- %s\n", __FUNCTION__);	s3c2410_dma_getposition(or->dma_ch, &src, &dst);	DBG("dma position: src=0x%lx, dst=0x%lx\n", (long)src, (long)dst);}/* conversion */static struct s3c24xx_platdata_iis *to_platdata(s3c24xx_card_t *card){	pr_debug("--- %s\n", __FUNCTION__);	return (card->device == NULL) ? NULL : card->device->platform_data;}/* helpers */static inline int s3c24xx_snd_is_clkmaster(s3c24xx_card_t *chip){	pr_debug("--- %s\n", __FUNCTION__);	return (readl(chip->regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;}/* audio hardware control */static void s3c24xx_snd_txctrl(s3c24xx_card_t *card, int on){	unsigned long iisfcon;	unsigned long iiscon;	unsigned long iismod;	pr_debug("--- %s\n", __FUNCTION__);	iisfcon = readl(card->regs + S3C2410_IISFCON);	iiscon  = readl(card->regs + S3C2410_IISCON);	iismod  = readl(card->regs + S3C2410_IISMOD);	if (on) {		iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;		iiscon  |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN;		  		iiscon  &= ~S3C2410_IISCON_TXIDLE;		iismod  |= S3C2410_IISMOD_TXMODE;		iismod  |= S3C2410_IISMOD_RXMODE;		if (s3c24xx_snd_is_clkmaster(card))		  iiscon |= S3C2410_IISCON_PSCEN;		else 		  iiscon &= ~S3C2410_IISCON_PSCEN;		writel(iismod,  card->regs + S3C2410_IISMOD);		writel(iisfcon, card->regs + S3C2410_IISFCON);		writel(iiscon,  card->regs + S3C2410_IISCON);	} else {		/* note, we have to disable the FIFOs otherwise bad things		 * seem to happen when the DMA stops. According to the 		 * Samsung supplied kernel, this should allow the DMA 		 * engine and FIFOs to reset. If this isn't allowed, the		 * DMA engine will simply freeze randomly.                 */		iisfcon &= ~S3C2410_IISFCON_TXENABLE;		iisfcon &= ~S3C2410_IISFCON_TXDMA;		iiscon  |=  S3C2410_IISCON_TXIDLE;		iiscon  &= ~S3C2410_IISCON_TXDMAEN;		//iismod  &= ~S3C2410_IISMOD_TXMODE;		if (s3c24xx_snd_is_clkmaster(card))		  iiscon |= S3C2410_IISCON_PSCEN;		else 		  iiscon &= ~S3C2410_IISCON_PSCEN;		writel(iiscon,  card->regs + S3C2410_IISCON);		writel(iisfcon, card->regs + S3C2410_IISFCON);		//writel(iismod,  card->regs + S3C2410_IISMOD);	}	DBG("%s: iismod=0x%08lx, iisfcon=0x%08lx, iiscon=0x%08lx\n",	    __FUNCTION__, iismod, iisfcon, iiscon);}static void s3c24xx_snd_rxctrl(s3c24xx_card_t *card, int on){	unsigned long iisfcon;	unsigned long iiscon;	unsigned long iismod;	pr_debug("--- %s\n", __FUNCTION__);	iisfcon = readl(card->regs + S3C2410_IISFCON);	iiscon  = readl(card->regs + S3C2410_IISCON);	iismod  = readl(card->regs + S3C2410_IISMOD);	if (on) {		iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;		iiscon  |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN|		  (s3c24xx_snd_is_clkmaster(card)?S3C2410_IISCON_PSCEN:0);		iiscon  &= (~S3C2410_IISCON_RXIDLE);		iismod  |= S3C2410_IISMOD_RXMODE;		iismod  |= S3C2410_IISMOD_TXMODE;		writel(iismod,  card->regs + S3C2410_IISMOD);		writel(iisfcon, card->regs + S3C2410_IISFCON);		writel(iiscon,  card->regs + S3C2410_IISCON);	} else {                /* note, we have to disable the FIFOs otherwise bad things                 * seem to happen when the DMA stops. According to the                  * Samsung supplied kernel, this should allow the DMA                  * engine and FIFOs to reset. If this isn't allowed, the                 * DMA engine will simply freeze randomly.                 */                iisfcon &= ~S3C2410_IISFCON_RXENABLE;                iisfcon &= ~S3C2410_IISFCON_RXDMA;                iiscon  |= S3C2410_IISCON_RXIDLE;                iiscon  &= ~S3C2410_IISCON_RXDMAEN;		//iismod  &= ~S3C2410_IISMOD_RXMODE;		writel(iisfcon, card->regs + S3C2410_IISFCON);		writel(iiscon,  card->regs + S3C2410_IISCON);		//writel(iismod,  card->regs + S3C2410_IISMOD);	}	DBG("%s: iismod=0x%08lx, iisfcon=0x%08lx, iiscon=0x%08lx\n",	    __FUNCTION__, iismod, iisfcon, iiscon);}int s3c24xx_iis_cfgclksrc(s3c24xx_card_t *card, const char *name){	struct s3c24xx_platdata_iis *pdata = to_platdata(card);	unsigned long iismod;		pr_debug("--- %s\n", __FUNCTION__);	if (name == NULL && pdata != NULL)		name = pdata->codec_clk;	if (name == NULL)		return -EINVAL;	DBG("%s: clock source %s\n", __FUNCTION__, name);	/* alter clock source (master/slave) appropriately */	iismod = readl(card->regs + S3C2410_IISMOD);	if (strcmp(name, "pclk") == 0 || strcmp(name, "cdclk") == 0) {		iismod &= ~S3C2410_IISMOD_SLAVE;			} else {		iismod |= S3C2410_IISMOD_SLAVE;	}	writel(iismod, card->regs + S3C2410_IISMOD);	return 0;}EXPORT_SYMBOL(s3c24xx_iis_cfgclksrc);/* s3c24xx_pcm_enqueue * * place a dma buffer onto the queue for the dma system * to handle.*/static void s3c24xx_pcm_enqueue(s3c24xx_runtime_t *or){	dma_addr_t pos = or->dma_pos;	int ret;	pr_debug("--- %s\n", __FUNCTION__);	DBG_DMA("%s: pos=%lx, period=%x, end=%lx, loaded=%d\n", __FUNCTION__,		(long)or->dma_start, or->dma_period,		(long)or->dma_end, or->dma_loaded);	do {		DBG_DMA("%s: load buffer %lx\n", __FUNCTION__, (long)pos);		ret = s3c2410_dma_enqueue(or->dma_ch, or, pos, or->dma_period);		if (ret == 0) {			or->dma_loaded++;			pos += or->dma_period;			if (pos >= or->dma_end)				pos = or->dma_start;		}	} while (ret == 0 && or->dma_loaded < or->dma_limit);	or->dma_pos = pos;}static void s3c24xx_snd_playback_buffdone(struct s3c2410_dma_chan *ch,					  void *bufid, int size,					  enum s3c2410_dma_buffresult result){	s3c24xx_runtime_t *or = bufid;	pr_debug("--- %s\n", __FUNCTION__);	DBG_DMA("%s: %p,%p, or %p, sz %d, res %d\n", 		__FUNCTION__, ch, bufid, or, size, result);	if (or->stream)		snd_pcm_period_elapsed(or->stream);	spin_lock(&or->lock);	if (or->state & ST_RUNNING) {		or->dma_loaded--;		s3c24xx_pcm_enqueue(or);	}	spin_unlock(&or->lock);}static void s3c24xx_snd_capture_buffdone(struct s3c2410_dma_chan *ch,					 void *bufid, int size,					 enum s3c2410_dma_buffresult result){	s3c24xx_runtime_t *or = bufid;	pr_debug("--- %s\n", __FUNCTION__);	DBG_DMA("%s: %p,%p, or %p, sz %d, res %d\n", 		__FUNCTION__, ch, bufid, or, size, result);	if (or->stream)		snd_pcm_period_elapsed(or->stream);	spin_lock(&or->lock);	if (or->state & ST_RUNNING) {		or->dma_loaded--;		s3c24xx_pcm_enqueue(or);	}	spin_unlock(&or->lock);}static int call_startup(struct s3c24xx_iis_ops *ops){	pr_debug("--- %s\n", __FUNCTION__);	if (ops && ops->startup)		return (ops->startup)(ops);	return 0;}static int call_open(struct s3c24xx_iis_ops *ops,		     struct snd_pcm_substream *substream){	pr_debug("--- %s\n", __FUNCTION__);	if (ops && ops->open)		return (ops->open)(ops, substream);	return 0;}static int s3c24xx_snd_open(struct snd_pcm_substream *substream){	s3c24xx_card_t *chip = snd_pcm_substream_chip(substream);	s3c24xx_runtime_t *or;	struct snd_pcm_runtime *runtime = substream->runtime;	int ret = 0;	pr_debug("--- %s\n", __FUNCTION__);	DBG("%s: substream=%p, chip=%p\n", __FUNCTION__, substream, chip);	runtime->private_data = &chip->playback;	runtime->hw	      = s3c24xx_snd_hw;	down(&chip->sem);	/* todo - request dma channel nicely */	DBG("%s: state: playback 0x%x, capture 0x%x\n",	    __FUNCTION__, chip->playback.state, chip->capture.state);	if (chip->playback.state == 0 && chip->capture.state == 0) {		/* ensure we hold all the modules we need */		if (chip->base_ops) {			if (try_module_get(chip->base_ops->owner))				chip->base_ops_claimed = 1;			else {				dev_err(chip->device, "cannot claim module\n");				ret = -EINVAL;				goto exit_err;			}		}		if (chip->chip_ops) {			if (try_module_get(chip->chip_ops->owner))				chip->chip_ops_claimed = 1;			else {				dev_err(chip->device, "cannot claim module\n");				ret = -EINVAL;				goto exit_err;			}		}		/* ensure the chip is started */		ret = call_startup(chip->base_ops);		if (ret)			goto exit_err;		ret = call_startup(chip->chip_ops);

⌨️ 快捷键说明

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