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

📄 s3c24xx-iis_c.txt

📁 2410uda1341的测试代码
💻 TXT
📖 第 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 + -