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

📄 dbri.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * REN   =  1 - enable receiver	 */	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	*(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN);	*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);	dbri_cmdsend(dbri, cmd, 4);}/**************************************************************************************************** CS4215 audio codec management **************************************************************************************************In the standard SPARC audio configuration, the CS4215 codec is attachedto the DBRI via the CHI interface and few of the DBRI's PIO pins. * Lock must not be held before calling it.*/static __devinit void cs4215_setup_pipes(struct snd_dbri *dbri){	unsigned long flags;	spin_lock_irqsave(&dbri->lock, flags);	/*	 * Data mode:	 * Pipe  4: Send timeslots 1-4 (audio data)	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)	 * Pipe  6: Receive timeslots 1-4 (audio data)	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via	 *          interrupt, and the rest of the data (slot 5 and 8) is	 *          not relevant for us (only for doublechecking).	 *	 * Control mode:	 * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only)	 * Pipe 18: Receive timeslot 1 (clb).	 * Pipe 19: Receive timeslot 7 (version).	 */	setup_pipe(dbri, 4, D_SDP_MEM | D_SDP_TO_SER | D_SDP_MSB);	setup_pipe(dbri, 20, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);	setup_pipe(dbri, 6, D_SDP_MEM | D_SDP_FROM_SER | D_SDP_MSB);	setup_pipe(dbri, 21, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);	setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB);	setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);	setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB);	spin_unlock_irqrestore(&dbri->lock, flags);	dbri_cmdwait(dbri);}static __devinit int cs4215_init_data(struct cs4215 *mm){	/*	 * No action, memory resetting only.	 *	 * Data Time Slot 5-8	 * Speaker,Line and Headphone enable. Gain set to the half.	 * Input is mike.	 */	mm->data[0] = CS4215_LO(0x20) | CS4215_HE | CS4215_LE;	mm->data[1] = CS4215_RO(0x20) | CS4215_SE;	mm->data[2] = CS4215_LG(0x8) | CS4215_IS | CS4215_PIO0 | CS4215_PIO1;	mm->data[3] = CS4215_RG(0x8) | CS4215_MA(0xf);	/*	 * Control Time Slot 1-4	 * 0: Default I/O voltage scale	 * 1: 8 bit ulaw, 8kHz, mono, high pass filter disabled	 * 2: Serial enable, CHI master, 128 bits per frame, clock 1	 * 3: Tests disabled	 */	mm->ctrl[0] = CS4215_RSRVD_1 | CS4215_MLB;	mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;	mm->ctrl[2] = CS4215_XCLK | CS4215_BSEL_128 | CS4215_FREQ[0].xtal;	mm->ctrl[3] = 0;	mm->status = 0;	mm->version = 0xff;	mm->precision = 8;	/* For ULAW */	mm->channels = 1;	return 0;}static void cs4215_setdata(struct snd_dbri *dbri, int muted){	if (muted) {		dbri->mm.data[0] |= 63;		dbri->mm.data[1] |= 63;		dbri->mm.data[2] &= ~15;		dbri->mm.data[3] &= ~15;	} else {		/* Start by setting the playback attenuation. */		struct dbri_streaminfo *info = &dbri->stream_info[DBRI_PLAY];		int left_gain = info->left_gain & 0x3f;		int right_gain = info->right_gain & 0x3f;		dbri->mm.data[0] &= ~0x3f;	/* Reset the volume bits */		dbri->mm.data[1] &= ~0x3f;		dbri->mm.data[0] |= (DBRI_MAX_VOLUME - left_gain);		dbri->mm.data[1] |= (DBRI_MAX_VOLUME - right_gain);		/* Now set the recording gain. */		info = &dbri->stream_info[DBRI_REC];		left_gain = info->left_gain & 0xf;		right_gain = info->right_gain & 0xf;		dbri->mm.data[2] |= CS4215_LG(left_gain);		dbri->mm.data[3] |= CS4215_RG(right_gain);	}	xmit_fixed(dbri, 20, *(int *)dbri->mm.data);}/* * Set the CS4215 to data mode. */static void cs4215_open(struct snd_dbri *dbri){	int data_width;	u32 tmp;	unsigned long flags;	dprintk(D_MM, "cs4215_open: %d channels, %d bits\n",		dbri->mm.channels, dbri->mm.precision);	/* Temporarily mute outputs, and wait 1/8000 sec (125 us)	 * to make sure this takes.  This avoids clicking noises.	 */	cs4215_setdata(dbri, 1);	udelay(125);	/*	 * Data mode:	 * Pipe  4: Send timeslots 1-4 (audio data)	 * Pipe 20: Send timeslots 5-8 (part of ctrl data)	 * Pipe  6: Receive timeslots 1-4 (audio data)	 * Pipe 21: Receive timeslots 6-7. We can only receive 20 bits via	 *          interrupt, and the rest of the data (slot 5 and 8) is	 *          not relevant for us (only for doublechecking).	 *	 * Just like in control mode, the time slots are all offset by eight	 * bits.  The CS4215, it seems, observes TSIN (the delayed signal)	 * even if it's the CHI master.  Don't ask me...	 */	spin_lock_irqsave(&dbri->lock, flags);	tmp = sbus_readl(dbri->regs + REG0);	tmp &= ~(D_C);		/* Disable CHI */	sbus_writel(tmp, dbri->regs + REG0);	/* Switch CS4215 to data mode - set PIO3 to 1 */	sbus_writel(D_ENPIO | D_PIO1 | D_PIO3 |		    (dbri->mm.onboard ? D_PIO0 : D_PIO2), dbri->regs + REG2);	reset_chi(dbri, CHIslave, 128);	/* Note: this next doesn't work for 8-bit stereo, because the two	 * channels would be on timeslots 1 and 3, with 2 and 4 idle.	 * (See CS4215 datasheet Fig 15)	 *	 * DBRI non-contiguous mode would be required to make this work.	 */	data_width = dbri->mm.channels * dbri->mm.precision;	link_time_slot(dbri, 4, 16, 16, data_width, dbri->mm.offset);	link_time_slot(dbri, 20, 4, 16, 32, dbri->mm.offset + 32);	link_time_slot(dbri, 6, 16, 16, data_width, dbri->mm.offset);	link_time_slot(dbri, 21, 6, 16, 16, dbri->mm.offset + 40);	/* FIXME: enable CHI after _setdata? */	tmp = sbus_readl(dbri->regs + REG0);	tmp |= D_C;		/* Enable CHI */	sbus_writel(tmp, dbri->regs + REG0);	spin_unlock_irqrestore(&dbri->lock, flags);	cs4215_setdata(dbri, 0);}/* * Send the control information (i.e. audio format) */static int cs4215_setctrl(struct snd_dbri *dbri){	int i, val;	u32 tmp;	unsigned long flags;	/* FIXME - let the CPU do something useful during these delays */	/* Temporarily mute outputs, and wait 1/8000 sec (125 us)	 * to make sure this takes.  This avoids clicking noises.	 */	cs4215_setdata(dbri, 1);	udelay(125);	/*	 * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait	 * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec	 */	val = D_ENPIO | D_PIO1 | (dbri->mm.onboard ? D_PIO0 : D_PIO2);	sbus_writel(val, dbri->regs + REG2);	dprintk(D_MM, "cs4215_setctrl: reg2=0x%x\n", val);	udelay(34);	/* In Control mode, the CS4215 is a slave device, so the DBRI must	 * operate as CHI master, supplying clocking and frame synchronization.	 *	 * In Data mode, however, the CS4215 must be CHI master to insure	 * that its data stream is synchronous with its codec.	 *	 * The upshot of all this?  We start by putting the DBRI into master	 * mode, program the CS4215 in Control mode, then switch the CS4215	 * into Data mode and put the DBRI into slave mode.  Various timing	 * requirements must be observed along the way.	 *	 * Oh, and one more thing, on a SPARCStation 20 (and maybe	 * others?), the addressing of the CS4215's time slots is	 * offset by eight bits, so we add eight to all the "cycle"	 * values in the Define Time Slot (DTS) commands.  This is	 * done in hardware by a TI 248 that delays the DBRI->4215	 * frame sync signal by eight clock cycles.  Anybody know why?	 */	spin_lock_irqsave(&dbri->lock, flags);	tmp = sbus_readl(dbri->regs + REG0);	tmp &= ~D_C;		/* Disable CHI */	sbus_writel(tmp, dbri->regs + REG0);	reset_chi(dbri, CHImaster, 128);	/*	 * Control mode:	 * Pipe 17: Send timeslots 1-4 (slots 5-8 are read only)	 * Pipe 18: Receive timeslot 1 (clb).	 * Pipe 19: Receive timeslot 7 (version).	 */	link_time_slot(dbri, 17, 16, 16, 32, dbri->mm.offset);	link_time_slot(dbri, 18, 16, 16, 8, dbri->mm.offset);	link_time_slot(dbri, 19, 18, 16, 8, dbri->mm.offset + 48);	spin_unlock_irqrestore(&dbri->lock, flags);	/* Wait for the chip to echo back CLB (Control Latch Bit) as zero */	dbri->mm.ctrl[0] &= ~CS4215_CLB;	xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);	spin_lock_irqsave(&dbri->lock, flags);	tmp = sbus_readl(dbri->regs + REG0);	tmp |= D_C;		/* Enable CHI */	sbus_writel(tmp, dbri->regs + REG0);	spin_unlock_irqrestore(&dbri->lock, flags);	for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i)		msleep_interruptible(1);	if (i == 0) {		dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n",			dbri->mm.status);		return -1;	}	/* Disable changes to our copy of the version number, as we are about	 * to leave control mode.	 */	recv_fixed(dbri, 19, NULL);	/* Terminate CS4215 control mode - data sheet says	 * "Set CLB=1 and send two more frames of valid control info"	 */	dbri->mm.ctrl[0] |= CS4215_CLB;	xmit_fixed(dbri, 17, *(int *)dbri->mm.ctrl);	/* Two frames of control info @ 8kHz frame rate = 250 us delay */	udelay(250);	cs4215_setdata(dbri, 0);	return 0;}/* * Setup the codec with the sampling rate, audio format and number of * channels. * As part of the process we resend the settings for the data * timeslots as well. */static int cs4215_prepare(struct snd_dbri *dbri, unsigned int rate,			  snd_pcm_format_t format, unsigned int channels){	int freq_idx;	int ret = 0;	/* Lookup index for this rate */	for (freq_idx = 0; CS4215_FREQ[freq_idx].freq != 0; freq_idx++) {		if (CS4215_FREQ[freq_idx].freq == rate)			break;	}	if (CS4215_FREQ[freq_idx].freq != rate) {		printk(KERN_WARNING "DBRI: Unsupported rate %d Hz\n", rate);		return -1;	}	switch (format) {	case SNDRV_PCM_FORMAT_MU_LAW:		dbri->mm.ctrl[1] = CS4215_DFR_ULAW;		dbri->mm.precision = 8;		break;	case SNDRV_PCM_FORMAT_A_LAW:		dbri->mm.ctrl[1] = CS4215_DFR_ALAW;		dbri->mm.precision = 8;		break;	case SNDRV_PCM_FORMAT_U8:		dbri->mm.ctrl[1] = CS4215_DFR_LINEAR8;		dbri->mm.precision = 8;		break;	case SNDRV_PCM_FORMAT_S16_BE:		dbri->mm.ctrl[1] = CS4215_DFR_LINEAR16;		dbri->mm.precision = 16;		break;	default:		printk(KERN_WARNING "DBRI: Unsupported format %d\n", format);		return -1;	}	/* Add rate parameters */	dbri->mm.ctrl[1] |= CS4215_FREQ[freq_idx].csval;	dbri->mm.ctrl[2] = CS4215_XCLK |	    CS4215_BSEL_128 | CS4215_FREQ[freq_idx].xtal;	dbri->mm.channels = channels;	if (channels == 2)		dbri->mm.ctrl[1] |= CS4215_DFR_STEREO;	ret = cs4215_setctrl(dbri);	if (ret == 0)		cs4215_open(dbri);	/* set codec to data mode */	return ret;}/* * */static __devinit int cs4215_init(struct snd_dbri *dbri){	u32 reg2 = sbus_readl(dbri->regs + REG2);	dprintk(D_MM, "cs4215_init: reg2=0x%x\n", reg2);	/* Look for the cs4215 chips */	if (reg2 & D_PIO2) {		dprintk(D_MM, "Onboard CS4215 detected\n");		dbri->mm.onboard = 1;	}	if (reg2 & D_PIO0) {		dprintk(D_MM, "Speakerbox detected\n");		dbri->mm.onboard = 0;		if (reg2 & D_PIO2) {			printk(KERN_INFO "DBRI: Using speakerbox / "			       "ignoring onboard mmcodec.\n");			sbus_writel(D_ENPIO2, dbri->regs + REG2);		}	}	if (!(reg2 & (D_PIO0 | D_PIO2))) {		printk(KERN_ERR "DBRI: no mmcodec found.\n");		return -EIO;	}	cs4215_setup_pipes(dbri);	cs4215_init_data(&dbri->mm);	/* Enable capture of the status & version timeslots. */	recv_fixed(dbri, 18, &dbri->mm.status);	recv_fixed(dbri, 19, &dbri->mm.version);	dbri->mm.offset = dbri->mm.onboard ? 0 : 8;	if (cs4215_setctrl(dbri) == -1 || dbri->mm.version == 0xff) {		dprintk(D_MM, "CS4215 failed probe at offset %d\n",			dbri->mm.offset);		return -EIO;	}	dprintk(D_MM, "Found CS4215 at offset %d\n", dbri->mm.offset);	return 0;}/******************************************************************************************************** DBRI interrupt handler *****************************************************************************************************The DBRI communicates with the CPU mainly via a circular interruptbuffer.  When an interrupt is signaled, the CPU walks through thebuffer and calls dbri_process_one_interrupt() for each interrupt word.Complicated interrupts are handled by dedicated functions (whichappear first in this file).  Any pending interrupts can be serviced bycalling dbri_process_interrupt_buffer(), which works even if the CPU'sinterrupts are disabled.*//* xmit_descs() * * Starts transmitting the current TD's for recording/playing. * For playback, ALSA has filled the DMA memory with new data (we hope). */static void xmit_descs(struct snd_dbri *dbri){	struct dbri_streaminfo *info;	s32 *cmd;	unsigned long flags;	int first_td;	if (dbri == NULL)		return;		/* Disabled */	info = &dbri->stream_info[DBRI_REC];	spin_lock_irqsave(&dbri->lock, flags);	if (info->pipe >= 0) {		first_td = dbri->pipes[info->pipe].first_desc;		dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td);

⌨️ 快捷键说明

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