cs4231.c

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

C
2,248
字号
	return chip->image[CS4231_PLAYBK_FORMAT] & 1 ? 9969 : 9920;}static int snd_cs4231_timer_start(snd_timer_t *timer){	unsigned long flags;	unsigned int ticks;	cs4231_t *chip = snd_timer_chip(timer);	spin_lock_irqsave(&chip->lock, flags);	ticks = timer->sticks;	if ((chip->image[CS4231_ALT_FEATURE_1] & CS4231_TIMER_ENABLE) == 0 ||	    (unsigned char)(ticks >> 8) != chip->image[CS4231_TIMER_HIGH] ||	    (unsigned char)ticks != chip->image[CS4231_TIMER_LOW]) {		snd_cs4231_out(chip, CS4231_TIMER_HIGH,			       chip->image[CS4231_TIMER_HIGH] =			       (unsigned char) (ticks >> 8));		snd_cs4231_out(chip, CS4231_TIMER_LOW,			       chip->image[CS4231_TIMER_LOW] =			       (unsigned char) ticks);		snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,			       chip->image[CS4231_ALT_FEATURE_1] | CS4231_TIMER_ENABLE);	}	spin_unlock_irqrestore(&chip->lock, flags);	return 0;}static int snd_cs4231_timer_stop(snd_timer_t *timer){	unsigned long flags;	cs4231_t *chip = snd_timer_chip(timer);	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1,		       chip->image[CS4231_ALT_FEATURE_1] &= ~CS4231_TIMER_ENABLE);	spin_unlock_irqrestore(&chip->lock, flags);	return 0;}static void snd_cs4231_init(cs4231_t *chip){	unsigned long flags;	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (1)\n");#endif	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->lock, flags);	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |					    CS4231_RECORD_ENABLE | CS4231_RECORD_PIO |					    CS4231_CALIB_MODE);	chip->image[CS4231_IFACE_CTRL] |= CS4231_AUTOCALIB;	snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (2)\n");#endif	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_ALT_FEATURE_1, chip->image[CS4231_ALT_FEATURE_1]);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]);#endif	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_ALT_FEATURE_2, chip->image[CS4231_ALT_FEATURE_2]);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, chip->image[CS4231_PLAYBK_FORMAT]);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (4)\n");#endif	snd_cs4231_mce_up(chip);	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]);	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_mce_down(chip);#ifdef SNDRV_DEBUG_MCE	snd_printk("init: (5)\n");#endif}static int snd_cs4231_open(cs4231_t *chip, unsigned int mode){	unsigned long flags;	down(&chip->open_mutex);	if ((chip->mode & mode)) {		up(&chip->open_mutex);		return -EAGAIN;	}	if (chip->mode & CS4231_MODE_OPEN) {		chip->mode |= mode;		up(&chip->open_mutex);		return 0;	}	/* ok. now enable and ack CODEC IRQ */	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |		       CS4231_RECORD_IRQ |		       CS4231_TIMER_IRQ);	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |		       CS4231_RECORD_IRQ |		       CS4231_TIMER_IRQ);	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);	spin_unlock_irqrestore(&chip->lock, flags);	chip->mode = mode;	up(&chip->open_mutex);	return 0;}static void snd_cs4231_close(cs4231_t *chip, unsigned int mode){	unsigned long flags;	down(&chip->open_mutex);	chip->mode &= ~mode;	if (chip->mode & CS4231_MODE_OPEN) {		up(&chip->open_mutex);		return;	}	snd_cs4231_calibrate_mute(chip, 1);	/* disable IRQ */	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */	/* now disable record & playback */	if (chip->image[CS4231_IFACE_CTRL] &	    (CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |	     CS4231_RECORD_ENABLE | CS4231_RECORD_PIO)) {		spin_unlock_irqrestore(&chip->lock, flags);		snd_cs4231_mce_up(chip);		spin_lock_irqsave(&chip->lock, flags);		chip->image[CS4231_IFACE_CTRL] &=			~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO |			  CS4231_RECORD_ENABLE | CS4231_RECORD_PIO);		snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);		spin_unlock_irqrestore(&chip->lock, flags);		snd_cs4231_mce_down(chip);		spin_lock_irqsave(&chip->lock, flags);	}	/* clear IRQ again */	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */	__cs4231_writeb(chip, 0, CS4231P(chip, STATUS));	/* clear IRQ */	spin_unlock_irqrestore(&chip->lock, flags);	snd_cs4231_calibrate_mute(chip, 0);	chip->mode = 0;	up(&chip->open_mutex);}/* *  timer open/close */static int snd_cs4231_timer_open(snd_timer_t *timer){	cs4231_t *chip = snd_timer_chip(timer);	snd_cs4231_open(chip, CS4231_MODE_TIMER);	return 0;}static int snd_cs4231_timer_close(snd_timer_t * timer){	cs4231_t *chip = snd_timer_chip(timer);	snd_cs4231_close(chip, CS4231_MODE_TIMER);	return 0;}static struct _snd_timer_hardware snd_cs4231_timer_table ={	.flags		=	SNDRV_TIMER_HW_AUTO,	.resolution	=	9945,	.ticks		=	65535,	.open		=	snd_cs4231_timer_open,	.close		=	snd_cs4231_timer_close,	.c_resolution	=	snd_cs4231_timer_resolution,	.start		=	snd_cs4231_timer_start,	.stop		=	snd_cs4231_timer_stop,};/* *  ok.. exported functions.. */static int snd_cs4231_playback_hw_params(snd_pcm_substream_t *substream,					 snd_pcm_hw_params_t *hw_params){	cs4231_t *chip = snd_pcm_substream_chip(substream);	unsigned char new_pdfr;	int err;	if ((err = snd_pcm_lib_malloc_pages(substream,					    params_buffer_bytes(hw_params))) < 0)		return err;	new_pdfr = snd_cs4231_get_format(chip, params_format(hw_params),					 params_channels(hw_params)) |		snd_cs4231_get_rate(params_rate(hw_params));	snd_cs4231_playback_format(chip, hw_params, new_pdfr);	return 0;}static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream){	return snd_pcm_lib_free_pages(substream);}static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	unsigned long flags;	spin_lock_irqsave(&chip->lock, flags);	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE |					    CS4231_PLAYBACK_PIO);	spin_unlock_irqrestore(&chip->lock, flags);	return 0;}static int snd_cs4231_capture_hw_params(snd_pcm_substream_t *substream,					snd_pcm_hw_params_t *hw_params){	cs4231_t *chip = snd_pcm_substream_chip(substream);	unsigned char new_cdfr;	int err;	if ((err = snd_pcm_lib_malloc_pages(substream,					    params_buffer_bytes(hw_params))) < 0)		return err;	new_cdfr = snd_cs4231_get_format(chip, params_format(hw_params),					 params_channels(hw_params)) |		snd_cs4231_get_rate(params_rate(hw_params));	snd_cs4231_capture_format(chip, hw_params, new_cdfr);	return 0;}static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream){	return snd_pcm_lib_free_pages(substream);}static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	unsigned long flags;	spin_lock_irqsave(&chip->lock, flags);	chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |					    CS4231_RECORD_PIO);	spin_unlock_irqrestore(&chip->lock, flags);	return 0;}static void snd_cs4231_overrange(cs4231_t *chip){	unsigned long flags;	unsigned char res;	spin_lock_irqsave(&chip->lock, flags);	res = snd_cs4231_in(chip, CS4231_TEST_INIT);	spin_unlock_irqrestore(&chip->lock, flags);	if (res & (0x08 | 0x02))	/* detect overrange only above 0dB; may be user selectable? */		chip->capture_substream->runtime->overrange++;}static void snd_cs4231_generic_interrupt(cs4231_t *chip){	unsigned long flags;	unsigned char status;	status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);	if (!status)		return;	if (status & CS4231_TIMER_IRQ) {		if (chip->timer)			snd_timer_interrupt(chip->timer, chip->timer->sticks);	}			if (status & CS4231_PLAYBACK_IRQ)		snd_pcm_period_elapsed(chip->playback_substream);	if (status & CS4231_RECORD_IRQ) {		snd_cs4231_overrange(chip);		snd_pcm_period_elapsed(chip->capture_substream);	}	/* ACK the CS4231 interrupt. */	spin_lock_irqsave(&chip->lock, flags);	snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0);	spin_unlock_irqrestore(&chip->lock, flags);}#ifdef SBUS_SUPPORTstatic irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs){	cs4231_t *chip = dev_id;	u32 csr;	csr = sbus_readl(chip->port + APCCSR);	if (!(csr & (APC_INT_PENDING |		     APC_PLAY_INT |		     APC_CAPT_INT |		     APC_GENL_INT |		     APC_XINT_PEMP |		     APC_XINT_CEMP)))		return IRQ_NONE;	/* ACK the APC interrupt. */	sbus_writel(csr, chip->port + APCCSR);	snd_cs4231_generic_interrupt(chip);	return IRQ_HANDLED;}#endif#ifdef EBUS_SUPPORTstatic void snd_cs4231_ebus_play_callback(struct ebus_dma_info *p, int event, void *cookie){	cs4231_t *chip = cookie;	if (chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) {		snd_pcm_period_elapsed(chip->playback_substream);		snd_cs4231_ebus_advance_dma(p, chip->playback_substream,					    &chip->p_periods_sent);	}}static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, void *cookie){	cs4231_t *chip = cookie;	if (chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) {		snd_pcm_period_elapsed(chip->capture_substream);		snd_cs4231_ebus_advance_dma(p, chip->capture_substream,					    &chip->c_periods_sent);	}}#endifstatic snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	size_t ptr, residue, period_bytes;	if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))		return 0;	period_bytes = snd_pcm_lib_period_bytes(substream);	ptr = period_bytes * chip->p_periods_sent;#ifdef EBUS_SUPPORT	if (chip->flags & CS4231_FLAG_EBUS) {		residue = ebus_dma_residue(&chip->eb2p);	} else {#endif#ifdef SBUS_SUPPORT		residue = sbus_readl(chip->port + APCPC);#endif#ifdef EBUS_SUPPORT	}#endif	ptr += (period_bytes - residue);	return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream){	cs4231_t *chip = snd_pcm_substream_chip(substream);	size_t ptr, residue, period_bytes;		if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))		return 0;	period_bytes = snd_pcm_lib_period_bytes(substream);	ptr = period_bytes * chip->c_periods_sent;#ifdef EBUS_SUPPORT	if (chip->flags & CS4231_FLAG_EBUS) {		residue = ebus_dma_residue(&chip->eb2c);	} else {#endif#ifdef SBUS_SUPPORT		residue = sbus_readl(chip->port + APCCC);#endif#ifdef EBUS_SUPPORT	}#endif	ptr += (period_bytes - residue);	return bytes_to_frames(substream->runtime, ptr);}/* */static int snd_cs4231_probe(cs4231_t *chip){	unsigned long flags;	int i, id, vers;	unsigned char *ptr;#if 0	snd_cs4231_debug(chip);#endif	id = vers = 0;	for (i = 0; i < 50; i++) {		mb();		if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT)			udelay(2000);		else {			spin_lock_irqsave(&chip->lock, flags);			snd_cs4231_out(chip, CS4231_MISC_INFO, CS4231_MODE2);			id = snd_cs4231_in(chip, CS4231_MISC_INFO) & 0x0f;			vers = snd_cs4231_in(chip, CS4231_VERSION);			spin_unlock_irqrestore(&chip->lock, flags);			if (id == 0x0a)				break;	/* this is valid value */		}	}

⌨️ 快捷键说明

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