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

📄 s3c24xx-iis.c

📁 基于linux kernel 2.6.20的UDA1341声音芯片的声卡驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (ret)			goto exit_err;		/* configure the pins for audio (iis) control */		s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK);		s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK);		s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI);		s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO);				if (s3c24xx_snd_is_clkmaster(chip))			s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK);	}	/* initialise the stream */	runtime->hw = s3c24xx_snd_hw;	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)		or = &chip->capture;	else		or = &chip->playback;	/* call all the registered helpers */	ret = call_open(chip->base_ops, substream);	if (ret < 0)		goto exit_err;	ret = call_open(chip->chip_ops, substream);	if (ret < 0)		goto exit_err;	or->state |= ST_OPENED;	runtime->private_data = or;	or->stream = substream;	up(&chip->sem);	return ret; exit_err:	up(&chip->sem);	return ret;}static void call_shutdown(struct s3c24xx_iis_ops *ops){	pr_debug("--- %s\n", __FUNCTION__);	if (ops && ops->shutdown)		(ops->shutdown)(ops);}static int call_close(struct s3c24xx_iis_ops *ops, 		      struct snd_pcm_substream *substream){	pr_debug("--- %s\n", __FUNCTION__);	if (ops && ops->close)		return (ops->close)(ops, substream);		return 0;}/* close callback */static int s3c24xx_snd_close(struct snd_pcm_substream *substream){	s3c24xx_card_t *chip = snd_pcm_substream_chip(substream);	struct snd_pcm_runtime *runtime = substream->runtime;	s3c24xx_runtime_t *or = runtime->private_data;	pr_debug("--- %s\n", __FUNCTION__);	DBG("%s: substream=%p, chip=%p\n", __FUNCTION__, substream, chip);			down(&chip->sem); 	snd_assert(or->state != 0, chip = chip);	/* mark stream as closed */	or->state &= ~ST_OPENED;	/* close all the devices associated with this */	call_close(chip->chip_ops, substream);	call_close(chip->base_ops, substream);	/* are both shut-down? */	if (chip->playback.state == 0 && chip->capture.state == 0) {		/* call shut-down methods for all */						call_shutdown(chip->chip_ops);		call_shutdown(chip->base_ops);		/* de-configure the IIS pins, go to input */		s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_INP);		s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_INP);				if (s3c24xx_snd_is_clkmaster(chip))			s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_INP);				s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_INP);		s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_INP);		/* free any hold we had on the modules */		if (chip->base_ops_claimed) {			chip->base_ops_claimed = 0;			module_put(chip->base_ops->owner);		}		if (chip->chip_ops_claimed) {			chip->chip_ops_claimed = 0;			module_put(chip->chip_ops->owner);		}	}		up(&chip->sem);	return 0;}/* hw_params callback */static int s3c24xx_snd_pcm_hw_params(struct snd_pcm_substream *substream,				     struct snd_pcm_hw_params *hw_params){	pr_debug("--- %s\n", __FUNCTION__);	DBG("%s: sub=%p, hwp=%p\n", __FUNCTION__, substream, hw_params);	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);	return 0;}/* hw_free callback */static int s3c24xx_snd_pcm_hw_free(struct snd_pcm_substream *substream){	pr_debug("--- %s\n", __FUNCTION__);	DBG("%s: substream %p\n", __FUNCTION__, substream);	snd_pcm_set_runtime_buffer(substream, NULL);	return 0;}/* frequency control */#define DIV_ABS(a) ((a) < 0 ? -(a) : (a))#define MANY_FPS 1 static long s3c24xx_snd_getdiv(s3c24xx_card_t *card, unsigned int rate,			       unsigned long *iismod, unsigned long iisdiv, unsigned long *err){	unsigned long clkrate = clk_get_rate(card->clock);	long div;	long diff;	pr_debug("--- %s\n", __FUNCTION__);	DBG("%s: %ld\n", __FUNCTION__, clkrate);	if (iisdiv & S3C2410_IISMOD_384FS)		clkrate /= 384;	else		clkrate /= 256;	div = clkrate / rate;	/* is divisor in range */	if (div < 1)		div =1;	if (div > 32)		div = 32;	if (div < 32) {	  if ( DIV_ABS(rate*div - clkrate) > DIV_ABS(rate*(div+1) - clkrate))	    div = div +1;	}	/* is the rate generated near enough our clock rate? */	diff = (clkrate / div) - rate;		if (err)	  *err = DIV_ABS(diff);#ifndef MANY_FPS	if (DIV_ABS(diff) > 100) {		//return -1L;		printk("Warning, i2s clock is rather out of specs (found %ld, expected %d)!\n", clkrate/div, rate);	}#endif	       	/* update info and return */	*iismod &= ~S3C2410_IISMOD_384FS;	*iismod |= iisdiv;	return (div-1) << S3C2410_IISPSR_INTSHIFT;}/* s3c24xx_snd_setrate * * configure the clock rate for when the s3c24xx is in clock master * mode.*/int s3c24xx_snd_setrate(s3c24xx_card_t *chip, struct snd_pcm_runtime *run){	unsigned long iismod = readl(chip->regs + S3C2410_IISMOD);	unsigned long rate;	unsigned long tmp;	long prescaler;#ifdef MANY_FPS	long prescaler_256, prescaler_384;	unsigned long iismod_256, iismod_384;	unsigned long err_256, err_384, err;#endif	/* if this is set to slave mode, then our clocks are all	 * inputs anyway, so we cannot alter the frequency here */	pr_debug("--- %s\n", __FUNCTION__);	if (iismod & S3C2410_IISMOD_SLAVE) {		printk(KERN_ERR "%s: called with IISMOD as slave\n",		       __FUNCTION__);		return -EINVAL;	}	rate = run->rate;#ifdef MANY_FPS	/* try both */	iismod_256 = iismod_384 = iismod;	prescaler_256 = s3c24xx_snd_getdiv(chip, rate, &iismod_256,					   S3C2410_IISMOD_256FS, &err_256);	prescaler_384 = s3c24xx_snd_getdiv(chip, rate, &iismod_384,					   S3C2410_IISMOD_384FS, &err_384);	if (err_256 < err_384) {	  prescaler = prescaler_256;	  iismod = iismod_256;	  err = err_256;	  chip->is_384 = 0;	}	else {	  prescaler = prescaler_384;	  iismod = iismod_384;	  err = err_384;	  chip->is_384 = 1;	}#if 1 	if (err > 100)	  printk("Imprecise sample rate (err is %ld)\n", err);#endif#else	/* CHRI: here we force to 384fs. We should study a way to tell	   the codec to change this parameter. grep: ONLY384 */	DBG("%s: clock rate %ld\n", __FUNCTION__, rate);	prescaler = s3c24xx_snd_getdiv(chip, rate, &iismod,				       S3C2410_IISMOD_384FS, NULL);	DBG("%s: prescaler is %ld\n", __FUNCTION__, prescaler >> S3C2410_IISPSR_INTSHIFT);	chip->is_384 = 1;#endif	if (prescaler < 0) {		printk(KERN_ERR "cannot get rate %d Hz\n", run->rate);		return -ERANGE;	}	/* update timing registers */	writel(iismod, chip->regs + S3C2410_IISMOD);	tmp = readl(chip->regs + S3C2410_IISPSR) & ~S3C2410_IISPSR_INTMASK;	tmp |= prescaler;	tmp &= ~S3C2410_IISPSR_EXTMASK;	/* no harm in always setting ext prescaler too */	tmp |= prescaler >> S3C2410_IISPSR_INTSHIFT;	writel(tmp, chip->regs + S3C2410_IISPSR);	tmp = readl(chip->regs + S3C2410_IISPSR);	DBG("%s: IISPSR is %08lx\n", __FUNCTION__, tmp);	return 0;}EXPORT_SYMBOL(s3c24xx_snd_setrate);/* s3c24xx_iismod_cfg * * Update the s3c24xx IISMOD register*/void s3c24xx_iismod_cfg(s3c24xx_card_t *chip,			unsigned long set,			unsigned long mask){	unsigned long flags;	unsigned long tmp;	pr_debug("--- %s\n", __FUNCTION__);	local_irq_save(flags);	tmp = readl(chip->regs + S3C2410_IISMOD);	tmp &= ~mask;	tmp |= set;	DBG("%s: new iismod 0x%08lx\n", __FUNCTION__, tmp);	writel(tmp, chip->regs + S3C2410_IISMOD);	local_irq_restore(flags);}EXPORT_SYMBOL(s3c24xx_iismod_cfg);static int call_prepare(struct s3c24xx_iis_ops *ops,			struct snd_pcm_substream *substream, struct snd_pcm_runtime *rt){	pr_debug("--- %s\n", __FUNCTION__);	if (ops && ops->prepare)		return (ops->prepare)(ops, substream, rt);	return 0;}/* prepare callback */static int s3c24xx_snd_pcm_prepare(struct snd_pcm_substream *substream){	s3c24xx_card_t *chip = snd_pcm_substream_chip(substream);	s3c24xx_runtime_t *or = substream->runtime->private_data;	struct snd_pcm_runtime *runtime = substream->runtime;	unsigned long flags;	int ret = 0;	pr_debug("--- %s\n", __FUNCTION__);	DBG("%s: substream=%p, chip=%p\n", __FUNCTION__, substream, chip);	DBG("%s: r->dma_addr=%lx, r->dma_area=%p\n", __FUNCTION__,	    (long)runtime->dma_addr, runtime->dma_area);	/* if we are master set clock rate */	if (s3c24xx_snd_is_clkmaster(chip)) {		s3c24xx_snd_setrate(chip, runtime);	}	/* prepare DMA */	spin_lock_irqsave(&or->lock, flags);	or->dma_loaded	= 0;	or->dma_limit	= runtime->hw.periods_min;	or->dma_period	= snd_pcm_lib_period_bytes(substream);	or->dma_start	= runtime->dma_addr;	or->dma_pos	= or->dma_start;	or->dma_end	= or->dma_start + snd_pcm_lib_buffer_bytes(substream);	spin_unlock_irqrestore(&or->lock, flags);	DBG("%s: dma: period=%d, start=%lx, pos=%lx, end=%lx\n", __FUNCTION__,	    or->dma_period, (long)or->dma_start,	    (long)or->dma_pos, (long)or->dma_end);		/* flush the DMA channel */	s3c2410_dma_ctrl(or->dma_ch, S3C2410_DMAOP_FLUSH);	/* call the register ops for prepare, to allow things like	 * sample rate and format to be set	 */	ret = call_prepare(chip->base_ops, substream, runtime);	if (ret < 0)		goto exit_err;	ret = call_prepare(chip->chip_ops, substream, runtime); exit_err:	return ret;}/* s3c24xx_snd_lrsync * * Wait for the LR signal to allow synchronisation to the L/R clock * from the DAC. May only be needed for slave mode.*/static int s3c24xx_snd_lrsync(s3c24xx_card_t *chip){	unsigned long iiscon;	int timeout = 10000;	pr_debug("--- %s\n", __FUNCTION__);	while (1) {		iiscon = readl(chip->regs + S3C2410_IISCON);		if (iiscon & S3C2410_IISCON_LRINDEX)			break;		if (--timeout < 0)			return -ETIMEDOUT;	}	return 0;}/* trigger callback */static int s3c24xx_snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd){	s3c24xx_runtime_t *or = substream->runtime->private_data;	s3c24xx_card_t *chip = snd_pcm_substream_chip(substream);	unsigned long flags;	int ret = -EINVAL;	pr_debug("--- %s\n", __FUNCTION__);	DBG("%s: substream=%p, cmd=%d\n", __FUNCTION__, substream, cmd);	spin_lock_irqsave(&or->lock, flags);	switch (cmd) {	case SNDRV_PCM_TRIGGER_START:		or->state |= ST_RUNNING;		/* enqueue dma buffers and start the IIS engine */		s3c24xx_pcm_enqueue(or);		s3c24xx_snd_showregs(chip);		s3c2410_dma_ctrl(or->dma_ch, S3C2410_DMAOP_START);		if (!s3c24xx_snd_is_clkmaster(chip)) {						ret = s3c24xx_snd_lrsync(chip);			if (ret)				goto exit_err;		}		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)			s3c24xx_snd_rxctrl(chip, 1);		else			s3c24xx_snd_txctrl(chip, 1);		ret = 0;		break;	case SNDRV_PCM_TRIGGER_STOP:		or->state &= ~ST_RUNNING;		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)			s3c24xx_snd_rxctrl(chip, 0);

⌨️ 快捷键说明

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