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

📄 vwsnd.c

📁 iis s3c2410-uda1341语音系统的 开发
💻 C
📖 第 1 页 / 共 5 页
字号:
 * dma_chan_desc is invariant information about a Lithium * DMA channel.  There are two instances, li_comm1 and li_comm2. * * Note that the CCTL register fields are write ptr and read ptr, but what * we care about are which pointer is updated by software and which by * hardware. */typedef struct dma_chan_desc {	int basereg;	int cfgreg;	int ctlreg;	int hwptrreg;	int swptrreg;	int ustreg;	int mscreg;	unsigned long swptrmask;	int ad1843_slot;	int direction;			/* LI_CCTL_DIR_IN/OUT */} dma_chan_desc_t;static const dma_chan_desc_t li_comm1 = {	LI_COMM1_BASE,			/* base register offset */	LI_COMM1_CFG,			/* config register offset */	LI_COMM1_CTL,			/* control register offset */	LI_COMM1_CTL + 0,		/* hw ptr reg offset (write ptr) */	LI_COMM1_CTL + 1,		/* sw ptr reg offset (read ptr) */	LI_AUDIO1_UST,			/* ust reg offset */	LI_AUDIO1_MSC,			/* msc reg offset */	LI_CCTL_RPTR,			/* sw ptr bitmask in ctlval */	2,				/* ad1843 serial slot */	LI_CCFG_DIR_IN			/* direction */};static const dma_chan_desc_t li_comm2 = {	LI_COMM2_BASE,			/* base register offset */	LI_COMM2_CFG,			/* config register offset */	LI_COMM2_CTL,			/* control register offset */	LI_COMM2_CTL + 1,		/* hw ptr reg offset (read ptr) */	LI_COMM2_CTL + 0,		/* sw ptr reg offset (writr ptr) */	LI_AUDIO2_UST,			/* ust reg offset */	LI_AUDIO2_MSC,			/* msc reg offset */	LI_CCTL_WPTR,			/* sw ptr bitmask in ctlval */	2,				/* ad1843 serial slot */	LI_CCFG_DIR_OUT			/* direction */};/* * dma_chan is variable information about a Lithium DMA channel. * * The desc field points to invariant information. * The lith field points to a lithium_t which is passed * to li_read* and li_write* to access the registers. * The *val fields shadow the lithium registers' contents. */typedef struct dma_chan {	const dma_chan_desc_t *desc;	lithium_t      *lith;	unsigned long   baseval;	unsigned long	cfgval;	unsigned long	ctlval;} dma_chan_t;/* * ustmsc is a UST/MSC pair (Unadjusted System Time/Media Stream Counter). * UST is time in microseconds since the system booted, and MSC is a * counter that increments with every audio sample. */typedef struct ustmsc {	unsigned long long ust;	unsigned long msc;} ustmsc_t;/* * li_ad1843_wait waits until lithium says the AD1843 register * exchange is not busy.  Returns 0 on success, -EBUSY on timeout. * * Locking: must be called with lithium_lock held. */static int li_ad1843_wait(lithium_t *lith){	unsigned long later = jiffies + 2;	while (li_readl(lith, LI_CODEC_COMMAND) & LI_CC_BUSY)		if (jiffies >= later)			return -EBUSY;	return 0;}/* * li_read_ad1843_reg returns the current contents of a 16 bit AD1843 register. * * Returns unsigned register value on success, -errno on failure. */static int li_read_ad1843_reg(lithium_t *lith, int reg){	int val;	ASSERT(!in_interrupt());	spin_lock(&lith->lock);	{		val = li_ad1843_wait(lith);		if (val == 0) {			li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_RD | reg);			val = li_ad1843_wait(lith);		}		if (val == 0)			val = li_readl(lith, LI_CODEC_DATA);	}	spin_unlock(&lith->lock);	DBGXV("li_read_ad1843_reg(lith=0x%p, reg=%d) returns 0x%04x\n",	      lith, reg, val);	return val;}/* * li_write_ad1843_reg writes the specified value to a 16 bit AD1843 register. */static void li_write_ad1843_reg(lithium_t *lith, int reg, int newval){	spin_lock(&lith->lock);	{		if (li_ad1843_wait(lith) == 0) {			li_writel(lith, LI_CODEC_DATA, newval);			li_writel(lith, LI_CODEC_COMMAND, LI_CC_DIR_WR | reg);		}	}	spin_unlock(&lith->lock);}/* * li_setup_dma calculates all the register settings for DMA in a particular * mode.  It takes too many arguments. */static void li_setup_dma(dma_chan_t *chan,			 const dma_chan_desc_t *desc,			 lithium_t *lith,			 unsigned long buffer_paddr,			 int bufshift,			 int fragshift,			 int channels,			 int sampsize){	unsigned long mode, format;	unsigned long size, tmask;	DBGEV("(chan=0x%p, desc=0x%p, lith=0x%p, buffer_paddr=0x%lx, "	     "bufshift=%d, fragshift=%d, channels=%d, sampsize=%d)\n",	     chan, desc, lith, buffer_paddr,	     bufshift, fragshift, channels, sampsize);	/* Reset the channel first. */	li_writel(lith, desc->ctlreg, LI_CCTL_RESET);	ASSERT(channels == 1 || channels == 2);	if (channels == 2)		mode = LI_CCFG_MODE_STEREO;	else		mode = LI_CCFG_MODE_MONO;	ASSERT(sampsize == 1 || sampsize == 2);	if (sampsize == 2)		format = LI_CCFG_FMT_16BIT;	else		format = LI_CCFG_FMT_8BIT;	chan->desc = desc;	chan->lith = lith;	/*	 * Lithium DMA address register takes a 40-bit physical	 * address, right-shifted by 8 so it fits in 32 bits.  Bit 37	 * must be set -- it enables cache coherence.	 */	ASSERT(!(buffer_paddr & 0xFF));	chan->baseval = (buffer_paddr >> 8) | 1 << (37 - 8);	chan->cfgval = (!LI_CCFG_LOCK |			SHIFT_FIELD(desc->ad1843_slot, LI_CCFG_SLOT) |			desc->direction |			mode |			format);	size = bufshift - 6;	tmask = 13 - fragshift;		/* See Lithium DMA Notes above. */	ASSERT(size >= 2 && size <= 7);	ASSERT(tmask >= 1 && tmask <= 7);	chan->ctlval = (!LI_CCTL_RESET |			SHIFT_FIELD(size, LI_CCTL_SIZE) |			!LI_CCTL_DMA_ENABLE |			SHIFT_FIELD(tmask, LI_CCTL_TMASK) |			SHIFT_FIELD(0, LI_CCTL_TPTR));	DBGPV("basereg 0x%x = 0x%lx\n", desc->basereg, chan->baseval);	DBGPV("cfgreg 0x%x = 0x%lx\n", desc->cfgreg, chan->cfgval);	DBGPV("ctlreg 0x%x = 0x%lx\n", desc->ctlreg, chan->ctlval);	li_writel(lith, desc->basereg, chan->baseval);	li_writel(lith, desc->cfgreg, chan->cfgval);	li_writel(lith, desc->ctlreg, chan->ctlval);	DBGRV();}static void li_shutdown_dma(dma_chan_t *chan){	lithium_t *lith = chan->lith;	caddr_t lith1 = lith->page1;	DBGEV("(chan=0x%p)\n", chan);		chan->ctlval &= ~LI_CCTL_DMA_ENABLE;	DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);	li_writel(lith, chan->desc->ctlreg, chan->ctlval);	/*	 * Offset 0x500 on Lithium page 1 is an undocumented,	 * unsupported register that holds the zero sample value.	 * Lithium is supposed to output zero samples when DMA is	 * inactive, and repeat the last sample when DMA underflows.	 * But it has a bug, where, after underflow occurs, the zero	 * sample is not reset.	 *	 * I expect this to break in a future rev of Lithium.	 */	if (lith1 && chan->desc->direction == LI_CCFG_DIR_OUT)		* (volatile unsigned long *) (lith1 + 0x500) = 0;}/* * li_activate_dma always starts dma at the beginning of the buffer. * * N.B., these may be called from interrupt. */static __inline__ void li_activate_dma(dma_chan_t *chan){	chan->ctlval |= LI_CCTL_DMA_ENABLE;	DBGPV("ctlval = 0x%lx\n", chan->ctlval);	li_writel(chan->lith, chan->desc->ctlreg, chan->ctlval);}static void li_deactivate_dma(dma_chan_t *chan){	lithium_t *lith = chan->lith;	caddr_t lith2 = lith->page2;	chan->ctlval &= ~(LI_CCTL_DMA_ENABLE | LI_CCTL_RPTR | LI_CCTL_WPTR);	DBGPV("ctlval = 0x%lx\n", chan->ctlval);	DBGPV("ctlreg 0x%x = 0x%lx\n", chan->desc->ctlreg, chan->ctlval);	li_writel(lith, chan->desc->ctlreg, chan->ctlval);	/*	 * Offsets 0x98 and 0x9C on Lithium page 2 are undocumented,	 * unsupported registers that are internal copies of the DMA	 * read and write pointers.  Because of a Lithium bug, these	 * registers aren't zeroed correctly when DMA is shut off.  So	 * we whack them directly.	 *	 * I expect this to break in a future rev of Lithium.	 */	if (lith2 && chan->desc->direction == LI_CCFG_DIR_OUT) {		* (volatile unsigned long *) (lith2 + 0x98) = 0;		* (volatile unsigned long *) (lith2 + 0x9C) = 0;	}}/* * read/write the ring buffer pointers.  These routines' arguments and results * are byte offsets from the beginning of the ring buffer. */static __inline__ int li_read_swptr(dma_chan_t *chan){	const unsigned long mask = chan->desc->swptrmask;	return CHUNKS_TO_BYTES(UNSHIFT_FIELD(chan->ctlval, mask));}static __inline__ int li_read_hwptr(dma_chan_t *chan){	return CHUNKS_TO_BYTES(li_readb(chan->lith, chan->desc->hwptrreg));}static __inline__ void li_write_swptr(dma_chan_t *chan, int val){	const unsigned long mask = chan->desc->swptrmask;	ASSERT(!(val & ~CHUNKS_TO_BYTES(0xFF)));	val = BYTES_TO_CHUNKS(val);	chan->ctlval = (chan->ctlval & ~mask) | SHIFT_FIELD(val, mask);	li_writeb(chan->lith, chan->desc->swptrreg, val);}/* li_read_USTMSC() returns a UST/MSC pair for the given channel. */static void li_read_USTMSC(dma_chan_t *chan, ustmsc_t *ustmsc){	lithium_t *lith = chan->lith;	const dma_chan_desc_t *desc = chan->desc;	unsigned long now_low, now_high0, now_high1, chan_ust;	spin_lock(&lith->lock);	{		/*		 * retry until we do all five reads without the		 * high word changing.  (High word increments		 * every 2^32 microseconds, i.e., not often)		 */		do {			now_high0 = li_readl(lith, LI_UST_HIGH);			now_low = li_readl(lith, LI_UST_LOW);			/*			 * Lithium guarantees these two reads will be			 * atomic -- ust will not increment after msc			 * is read.			 */			ustmsc->msc = li_readl(lith, desc->mscreg);			chan_ust = li_readl(lith, desc->ustreg);			now_high1 = li_readl(lith, LI_UST_HIGH);		} while (now_high0 != now_high1);	}		spin_unlock(&lith->lock);	ustmsc->ust = ((unsigned long long) now_high0 << 32 | chan_ust);}static void li_enable_interrupts(lithium_t *lith, unsigned int mask){	DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);	/* clear any already-pending interrupts. */	li_writel(lith, LI_INTR_STATUS, mask);	/* enable the interrupts. */	mask |= li_readl(lith, LI_INTR_MASK);	li_writel(lith, LI_INTR_MASK, mask);}static void li_disable_interrupts(lithium_t *lith, unsigned int mask){	unsigned int keepmask;	DBGEV("(lith=0x%p, mask=0x%x)\n", lith, mask);	/* disable the interrupts */	keepmask = li_readl(lith, LI_INTR_MASK) & ~mask;	li_writel(lith, LI_INTR_MASK, keepmask);	/* clear any pending interrupts. */	li_writel(lith, LI_INTR_STATUS, mask);}/* Get the interrupt status and clear all pending interrupts. */static unsigned int li_get_clear_intr_status(lithium_t *lith){	unsigned int status;	status = li_readl(lith, LI_INTR_STATUS);	li_writel(lith, LI_INTR_STATUS, ~0);	return status & li_readl(lith, LI_INTR_MASK);}static int li_init(lithium_t *lith){	/* 1. System power supplies stabilize. */	/* 2. Assert the ~RESET signal. */	li_writel(lith, LI_HOST_CONTROLLER, LI_HC_RESET);	udelay(1);	/* 3. Deassert the ~RESET signal and enter a wait period to allow	   the AD1843 internal clocks and the external crystal oscillator	   to stabilize. */	li_writel(lith, LI_HOST_CONTROLLER, LI_HC_LINK_ENABLE);	udelay(1);	return 0;}/*****************************************************************************//* AD1843 access *//* * AD1843 bitfield definitions.  All are named as in the AD1843 data * sheet, with ad1843_ prepended and individual bit numbers removed. * * E.g., bits LSS0 through LSS2 become ad1843_LSS. * * Only the bitfields we need are defined. */typedef struct ad1843_bitfield {	char reg;	char lo_bit;	char nbits;} ad1843_bitfield_t;static const ad1843_bitfield_t	ad1843_PDNO   = {  0, 14,  1 },	/* Converter Power-Down Flag */	ad1843_INIT   = {  0, 15,  1 },	/* Clock Initialization Flag */	ad1843_RIG    = {  2,  0,  4 },	/* Right ADC Input Gain */	ad1843_RMGE   = {  2,  4,  1 },	/* Right ADC Mic Gain Enable */	ad1843_RSS    = {  2,  5,  3 },	/* Right ADC Source Select */	ad1843_LIG    = {  2,  8,  4 },	/* Left ADC Input Gain */	ad1843_LMGE   = {  2, 12,  1 },	/* Left ADC Mic Gain Enable */	ad1843_LSS    = {  2, 13,  3 },	/* Left ADC Source Select */	ad1843_RX1M   = {  4,  0,  5 },	/* Right Aux 1 Mix Gain/Atten */	ad1843_RX1MM  = {  4,  7,  1 },	/* Right Aux 1 Mix Mute */	ad1843_LX1M   = {  4,  8,  5 },	/* Left Aux 1 Mix Gain/Atten */	ad1843_LX1MM  = {  4, 15,  1 },	/* Left Aux 1 Mix Mute */	ad1843_RX2M   = {  5,  0,  5 },	/* Right Aux 2 Mix Gain/Atten */	ad1843_RX2MM  = {  5,  7,  1 },	/* Right Aux 2 Mix Mute */	ad1843_LX2M   = {  5,  8,  5 },	/* Left Aux 2 Mix Gain/Atten */	ad1843_LX2MM  = {  5, 15,  1 },	/* Left Aux 2 Mix Mute */	ad1843_RMCM   = {  7,  0,  5 },	/* Right Mic Mix Gain/Atten */	ad1843_RMCMM  = {  7,  7,  1 },	/* Right Mic Mix Mute */	ad1843_LMCM   = {  7,  8,  5 },	/* Left Mic Mix Gain/Atten */	ad1843_LMCMM  = {  7, 15,  1 },	/* Left Mic Mix Mute */	ad1843_HPOS   = {  8,  4,  1 },	/* Headphone Output Voltage Swing */	ad1843_HPOM   = {  8,  5,  1 },	/* Headphone Output Mute */	ad1843_RDA1G  = {  9,  0,  6 },	/* Right DAC1 Analog/Digital Gain */	ad1843_RDA1GM = {  9,  7,  1 },	/* Right DAC1 Analog Mute */	ad1843_LDA1G  = {  9,  8,  6 },	/* Left DAC1 Analog/Digital Gain */	ad1843_LDA1GM = {  9, 15,  1 },	/* Left DAC1 Analog Mute */	ad1843_RDA1AM = { 11,  7,  1 },	/* Right DAC1 Digital Mute */	ad1843_LDA1AM = { 11, 15,  1 },	/* Left DAC1 Digital Mute */	ad1843_ADLC   = { 15,  0,  2 },	/* ADC Left Sample Rate Source */	ad1843_ADRC   = { 15,  2,  2 },	/* ADC Right Sample Rate Source */	ad1843_DA1C   = { 15,  8,  2 },	/* DAC1 Sample Rate Source */	ad1843_C1C    = { 17,  0, 16 },	/* Clock 1 Sample Rate Select */	ad1843_C2C    = { 20,  0, 16 },	/* Clock 1 Sample Rate Select */	ad1843_DAADL  = { 25,  4,  2 },	/* Digital ADC Left Source Select */

⌨️ 快捷键说明

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