cs4231.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,248 行 · 第 1/5 页

C
2,248
字号
	printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value);#endif}static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg){	int timeout;	unsigned char ret;	for (timeout = 250;	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);	     timeout--)	     	udelay(100);#ifdef CONFIG_SND_DEBUG	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)		snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);#endif	__cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL));	mb();	ret = __cs4231_readb(chip, CS4231P(chip, REG));#if 0	printk("codec in - reg 0x%x = 0x%x\n", chip->mce_bit | reg, ret);#endif	return ret;}#ifdef CONFIG_SND_DEBUGvoid snd_cs4231_debug(cs4231_t *chip){	printk("CS4231 REGS:      INDEX = 0x%02x  ",	       __cs4231_readb(chip, CS4231P(chip, REGSEL)));	printk("                 STATUS = 0x%02x\n",	       __cs4231_readb(chip, CS4231P(chip, STATUS)));	printk("  0x00: left input      = 0x%02x  ", snd_cs4231_in(chip, 0x00));	printk("  0x10: alt 1 (CFIG 2)  = 0x%02x\n", snd_cs4231_in(chip, 0x10));	printk("  0x01: right input     = 0x%02x  ", snd_cs4231_in(chip, 0x01));	printk("  0x11: alt 2 (CFIG 3)  = 0x%02x\n", snd_cs4231_in(chip, 0x11));	printk("  0x02: GF1 left input  = 0x%02x  ", snd_cs4231_in(chip, 0x02));	printk("  0x12: left line in    = 0x%02x\n", snd_cs4231_in(chip, 0x12));	printk("  0x03: GF1 right input = 0x%02x  ", snd_cs4231_in(chip, 0x03));	printk("  0x13: right line in   = 0x%02x\n", snd_cs4231_in(chip, 0x13));	printk("  0x04: CD left input   = 0x%02x  ", snd_cs4231_in(chip, 0x04));	printk("  0x14: timer low       = 0x%02x\n", snd_cs4231_in(chip, 0x14));	printk("  0x05: CD right input  = 0x%02x  ", snd_cs4231_in(chip, 0x05));	printk("  0x15: timer high      = 0x%02x\n", snd_cs4231_in(chip, 0x15));	printk("  0x06: left output     = 0x%02x  ", snd_cs4231_in(chip, 0x06));	printk("  0x16: left MIC (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x16));	printk("  0x07: right output    = 0x%02x  ", snd_cs4231_in(chip, 0x07));	printk("  0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17));	printk("  0x08: playback format = 0x%02x  ", snd_cs4231_in(chip, 0x08));	printk("  0x18: IRQ status      = 0x%02x\n", snd_cs4231_in(chip, 0x18));	printk("  0x09: iface (CFIG 1)  = 0x%02x  ", snd_cs4231_in(chip, 0x09));	printk("  0x19: left line out   = 0x%02x\n", snd_cs4231_in(chip, 0x19));	printk("  0x0a: pin control     = 0x%02x  ", snd_cs4231_in(chip, 0x0a));	printk("  0x1a: mono control    = 0x%02x\n", snd_cs4231_in(chip, 0x1a));	printk("  0x0b: init & status   = 0x%02x  ", snd_cs4231_in(chip, 0x0b));	printk("  0x1b: right line out  = 0x%02x\n", snd_cs4231_in(chip, 0x1b));	printk("  0x0c: revision & mode = 0x%02x  ", snd_cs4231_in(chip, 0x0c));	printk("  0x1c: record format   = 0x%02x\n", snd_cs4231_in(chip, 0x1c));	printk("  0x0d: loopback        = 0x%02x  ", snd_cs4231_in(chip, 0x0d));	printk("  0x1d: var freq (PnP)  = 0x%02x\n", snd_cs4231_in(chip, 0x1d));	printk("  0x0e: ply upr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0e));	printk("  0x1e: rec upr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1e));	printk("  0x0f: ply lwr count   = 0x%02x  ", snd_cs4231_in(chip, 0x0f));	printk("  0x1f: rec lwr count   = 0x%02x\n", snd_cs4231_in(chip, 0x1f));}#endif/* *  CS4231 detection / MCE routines */static void snd_cs4231_busy_wait(cs4231_t *chip){	int timeout;	/* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */	for (timeout = 5; timeout > 0; timeout--)		__cs4231_readb(chip, CS4231P(chip, REGSEL));	/* end of cleanup sequence */	for (timeout = 250;	     timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT);	     timeout--)	     	udelay(100);}static void snd_cs4231_mce_up(cs4231_t *chip){	unsigned long flags;	int timeout;	spin_lock_irqsave(&chip->lock, flags);	for (timeout = 250; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--)		udelay(100);#ifdef CONFIG_SND_DEBUG	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)		snd_printk("mce_up - auto calibration time out (0)\n");#endif	chip->mce_bit |= CS4231_MCE;	timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));	if (timeout == 0x80)		snd_printk("mce_up [%p]: serious init problem - codec still busy\n", chip->port);	if (!(timeout & CS4231_MCE))		__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));	spin_unlock_irqrestore(&chip->lock, flags);}static void snd_cs4231_mce_down(cs4231_t *chip){	unsigned long flags;	int timeout;	signed long time;	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_busy_wait(chip);#if 0	printk("(1) timeout = %i\n", timeout);#endif#ifdef CONFIG_SND_DEBUG	if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)		snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));#endif	chip->mce_bit &= ~CS4231_MCE;	timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL));	__cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));	if (timeout == 0x80)		snd_printk("mce_down [%p]: serious init problem - codec still busy\n", chip->port);	if ((timeout & CS4231_MCE) == 0) {		spin_unlock_irqrestore(&chip->lock, flags);		return;	}	snd_cs4231_busy_wait(chip);	/* calibration process */	for (timeout = 500; timeout > 0 && (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0; timeout--)		udelay(100);	if ((snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) == 0) {		snd_printd("cs4231_mce_down - auto calibration time out (1)\n");		spin_unlock_irqrestore(&chip->lock, flags);		return;	}#if 0	printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies);#endif	time = HZ / 4;	while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) {		spin_unlock_irqrestore(&chip->lock, flags);		if (time <= 0) {			snd_printk("mce_down - auto calibration time out (2)\n");			return;		}		set_current_state(TASK_INTERRUPTIBLE);		time = schedule_timeout(time);		spin_lock_irqsave(&chip->lock, flags);	}#if 0	printk("(3) jiffies = %li\n", jiffies);#endif	time = HZ / 10;	while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) {		spin_unlock_irqrestore(&chip->lock, flags);		if (time <= 0) {			snd_printk("mce_down - auto calibration time out (3)\n");			return;		}		set_current_state(TASK_INTERRUPTIBLE);				time = schedule_timeout(time);		spin_lock_irqsave(&chip->lock, flags);	}	spin_unlock_irqrestore(&chip->lock, flags);#if 0	printk("(4) jiffies = %li\n", jiffies);	snd_printk("mce_down - exit = 0x%x\n", __cs4231_readb(chip, CS4231P(chip, REGSEL)));#endif}#if 0 /* Unused for now... */static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size){	switch (format & 0xe0) {	case CS4231_LINEAR_16:	case CS4231_LINEAR_16_BIG:		size >>= 1;		break;	case CS4231_ADPCM_16:		return size >> 2;	}	if (format & CS4231_STEREO)		size >>= 1;	return size;}#endif#ifdef EBUS_SUPPORTstatic void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent){	snd_pcm_runtime_t *runtime = substream->runtime;	while (1) {		unsigned int dma_size = snd_pcm_lib_period_bytes(substream);		unsigned int offset = dma_size * (*periods_sent);		if (dma_size >= (1 << 24))			BUG();		if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size))			return;#if 0		printk("ebus_advance: Sent period %u (size[%x] offset[%x])\n",		       (*periods_sent), dma_size, offset);#endif		(*periods_sent) = ((*periods_sent) + 1) % runtime->periods;	}}#endifstatic void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on){#ifdef EBUS_SUPPORT	if (chip->flags & CS4231_FLAG_EBUS) {		if (what & CS4231_PLAYBACK_ENABLE) {			if (on) {				ebus_dma_prepare(&chip->eb2p, 0);				ebus_dma_enable(&chip->eb2p, 1);				snd_cs4231_ebus_advance_dma(&chip->eb2p,					chip->playback_substream,					&chip->p_periods_sent);			} else {				ebus_dma_enable(&chip->eb2p, 0);			}		}		if (what & CS4231_RECORD_ENABLE) {			if (on) {				ebus_dma_prepare(&chip->eb2c, 1);				ebus_dma_enable(&chip->eb2c, 1);				snd_cs4231_ebus_advance_dma(&chip->eb2c,					chip->capture_substream,					&chip->c_periods_sent);			} else {				ebus_dma_enable(&chip->eb2c, 0);			}		}	} else {#endif#ifdef SBUS_SUPPORT#endif#ifdef EBUS_SUPPORT	}#endif}static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd){	cs4231_t *chip = snd_pcm_substream_chip(substream);	int result = 0;	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:	case SNDRV_PCM_TRIGGER_STOP:	{		unsigned int what = 0;		snd_pcm_substream_t *s;		struct list_head *pos;		unsigned long flags;		snd_pcm_group_for_each(pos, substream) {			s = snd_pcm_group_substream_entry(pos);			if (s == chip->playback_substream) {				what |= CS4231_PLAYBACK_ENABLE;				snd_pcm_trigger_done(s, substream);			} else if (s == chip->capture_substream) {				what |= CS4231_RECORD_ENABLE;				snd_pcm_trigger_done(s, substream);			}		}#if 0		printk("TRIGGER: what[%x] on(%d)\n",		       what, (cmd == SNDRV_PCM_TRIGGER_START));#endif		spin_lock_irqsave(&chip->lock, flags);		if (cmd == SNDRV_PCM_TRIGGER_START) {			cs4231_dma_trigger(chip, what, 1);			chip->image[CS4231_IFACE_CTRL] |= what;			if (what & CS4231_PLAYBACK_ENABLE) {				snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, 0xff);				snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, 0xff);			}			if (what & CS4231_RECORD_ENABLE) {				snd_cs4231_out(chip, CS4231_REC_LWR_CNT, 0xff);				snd_cs4231_out(chip, CS4231_REC_UPR_CNT, 0xff);			}		} else {			cs4231_dma_trigger(chip, what, 0);			chip->image[CS4231_IFACE_CTRL] &= ~what;		}		snd_cs4231_out(chip, CS4231_IFACE_CTRL,			       chip->image[CS4231_IFACE_CTRL]);		spin_unlock_irqrestore(&chip->lock, flags);		break;	}	default:		result = -EINVAL;		break;	}#if 0	snd_cs4231_debug(chip);#endif	return result;}/* *  CODEC I/O */static unsigned char snd_cs4231_get_rate(unsigned int rate){	int i;	for (i = 0; i < 14; i++)		if (rate == rates[i])			return freq_bits[i];	// snd_BUG();	return freq_bits[13];}static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int channels){	unsigned char rformat;	rformat = CS4231_LINEAR_8;	switch (format) {	case SNDRV_PCM_FORMAT_MU_LAW:	rformat = CS4231_ULAW_8; break;	case SNDRV_PCM_FORMAT_A_LAW:	rformat = CS4231_ALAW_8; break;	case SNDRV_PCM_FORMAT_S16_LE:	rformat = CS4231_LINEAR_16; break;	case SNDRV_PCM_FORMAT_S16_BE:	rformat = CS4231_LINEAR_16_BIG; break;	case SNDRV_PCM_FORMAT_IMA_ADPCM:	rformat = CS4231_ADPCM_16; break;	}	if (channels > 1)		rformat |= CS4231_STEREO;#if 0	snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode);#endif	return rformat;}static void snd_cs4231_calibrate_mute(cs4231_t *chip, int mute){	unsigned long flags;	mute = mute ? 1 : 0;	spin_lock_irqsave(&chip->lock, flags);	if (chip->calibrate_mute == mute) {		spin_unlock_irqrestore(&chip->lock, flags);		return;	}	if (!mute) {		snd_cs4231_dout(chip, CS4231_LEFT_INPUT,				chip->image[CS4231_LEFT_INPUT]);		snd_cs4231_dout(chip, CS4231_RIGHT_INPUT,				chip->image[CS4231_RIGHT_INPUT]);		snd_cs4231_dout(chip, CS4231_LOOPBACK,				chip->image[CS4231_LOOPBACK]);	}	snd_cs4231_dout(chip, CS4231_AUX1_LEFT_INPUT,			mute ? 0x80 : chip->image[CS4231_AUX1_LEFT_INPUT]);	snd_cs4231_dout(chip, CS4231_AUX1_RIGHT_INPUT,			mute ? 0x80 : chip->image[CS4231_AUX1_RIGHT_INPUT]);	snd_cs4231_dout(chip, CS4231_AUX2_LEFT_INPUT,			mute ? 0x80 : chip->image[CS4231_AUX2_LEFT_INPUT]);	snd_cs4231_dout(chip, CS4231_AUX2_RIGHT_INPUT,			mute ? 0x80 : chip->image[CS4231_AUX2_RIGHT_INPUT]);	snd_cs4231_dout(chip, CS4231_LEFT_OUTPUT,			mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]);	snd_cs4231_dout(chip, CS4231_RIGHT_OUTPUT,			mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]);	snd_cs4231_dout(chip, CS4231_LEFT_LINE_IN,			mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]);	snd_cs4231_dout(chip, CS4231_RIGHT_LINE_IN,			mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]);	snd_cs4231_dout(chip, CS4231_MONO_CTRL,			mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]);	chip->calibrate_mute = mute;	spin_unlock_irqrestore(&chip->lock, flags);}static void snd_cs4231_playback_format(cs4231_t *chip, snd_pcm_hw_params_t *params,				       unsigned char pdfr){	unsigned long flags;	down(&chip->mce_mutex);	snd_cs4231_calibrate_mute(chip, 1);	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,		       (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) ?		       (pdfr & 0xf0) | (chip->image[CS4231_REC_FORMAT] & 0x0f) :		       pdfr);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_down(chip);	snd_cs4231_calibrate_mute(chip, 0);	up(&chip->mce_mutex);}static void snd_cs4231_capture_format(cs4231_t *chip, snd_pcm_hw_params_t *params,                                      unsigned char cdfr){	unsigned long flags;	down(&chip->mce_mutex);	snd_cs4231_calibrate_mute(chip, 1);	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->lock, flags);	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) {		snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT,			       ((chip->image[CS4231_PLAYBK_FORMAT]) & 0xf0) |			       (cdfr & 0x0f));		spin_unlock_irqrestore(&chip->lock, flags);		snd_cs4231_mce_down(chip);		snd_cs4231_mce_up(chip);		spin_lock_irqsave(&chip->lock, flags);	}	snd_cs4231_out(chip, CS4231_REC_FORMAT, cdfr);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_down(chip);	snd_cs4231_calibrate_mute(chip, 0);	up(&chip->mce_mutex);}/* *  Timer interface */static unsigned long snd_cs4231_timer_resolution(snd_timer_t *timer){	cs4231_t *chip = snd_timer_chip(timer);

⌨️ 快捷键说明

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