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

📄 mx27-wm8782-pcm.c.bak

📁 根据芯片WM8782在LINUX环境下实现的音频驱动
💻 BAK
📖 第 1 页 / 共 2 页
字号:
	s->periods++;
	s->periods %= runtime->periods;

	/*
	 * Give back to the CPU the access to the non cached memory
	 */
	dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
			 DMA_TO_DEVICE);

	/*
	 * If we are getting a callback for an active stream then we inform
	 * the PCM middle layer we've finished a period
	 */
	if (s->active)
		snd_pcm_period_elapsed(s->substream);

	spin_lock(&s->dma_lock);

	/*
	 * Trig next DMA transfer
	 */
	audio_playback_dma(s);

	spin_unlock(&s->dma_lock);

}
/*!
  * This is a callback which will be called when a RX transfer finishes. 
  * The call occurs in interrupt context.
  * @param	substream	pointer to the structure of the current stream.
  */
static void audio_capture_dma_callback(void *data, int error,
				       unsigned int count)
{
	
	audio_stream_t *s;
	snd_pcm_substream_t *substream;
	snd_pcm_runtime_t *runtime;
	unsigned int dma_size;
	unsigned int previous_period;
	unsigned int offset;

	s = data;
	substream = s->substream;
	runtime = substream->runtime;
	previous_period = s->periods;
	dma_size = frames_to_bytes(runtime, runtime->period_size);
	offset = dma_size * previous_period;
	//ENTRY(0);
//printk("zd audio capture dma callback entry!\n");
	s->tx_spin = 0;
	s->periods++;
	s->periods %= runtime->periods;
//	printk("zd:audio capture dma callback s->periods=%d\n",s->periods);
	/*
	 * Give back to the CPU the access to the non cached memory
	 */
	dma_unmap_single(NULL, runtime->dma_addr + offset, dma_size,
			 DMA_FROM_DEVICE);

	/*
	 * If we are getting a callback for an active stream then we inform
	 * the PCM middle layer we've finished a period
	 */
	if (s->active)
		snd_pcm_period_elapsed(s->substream);

	spin_lock(&s->dma_lock);

	/*
	 * Trig next DMA transfer
	 */
	audio_capture_dma(s);

	spin_unlock(&s->dma_lock);

}


static int wm8782_pcm_prepare(struct snd_pcm_substream *substream)
{
	//mx27_codec_t* codec = snd_pcm_substream_chip (substream);
	//struct wm8782_platform_data * pdata = codec->pdata;
	struct snd_pcm_runtime * runtime = substream->runtime;
	int rate = runtime->rate;
//	int sample_bits = runtime->sample_bits;
	u16 srate = 0;//iface = 0;
	int i = get_coeff(12000000,rate);
	

	printk(KERN_INFO "%s\n",__FUNCTION__);
	printk("zd:rate=%d\n", rate);
	/*set inactive*/
//	pdata->write(WM8782_ACTIVE, 0x0000);
	
	/*set codec sampling rate*/
      	srate = (coeff_div[i].sr << 2) |
		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
		
//	pdata->write(WM8782_SRATE, srate);


#if 0
       	iface = pdata->read(WM8782_IFACE);
	
	iface &= ~(3<<2); 
	/* bit size */
	switch (sample_bits) {
	case 16:
		iface |= 0x0000;
		break;
	case 20:
		iface |= 0x0004;
		break;
	case 24:
		iface |= 0x0008;
		break;
	case 32:
		iface |= 0x000c;
		break;
	}

	/* clock inversion */
	//bclk don't inversion

	/* set iface */
	pdata->write(WM8782_IFACE, iface);
#endif
	/* set active */
//	pdata->write(WM8731_ACTIVE, 0x0001);
	
	/*set output power on*/
	//reg = pdata->read(WM8782_PWR);
	//reg &= ~(1<<4); 
	//pdata->write(WM8782_PWR,reg);
	return 0;
}



static int mx27_codec_open(snd_pcm_substream_t * substream)
{
	mx27_codec_t* codec = snd_pcm_substream_chip (substream);
	snd_pcm_runtime_t* runtime = substream->runtime;
	int stream_id = substream->pstr->stream;
	int result;
	int err;

	ENTRY (0); 
 //	printk("%s\n",__FUNCTION__);

	codec->s[stream_id].substream = substream;

	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK){
		runtime->hw = mx27_codec_playback_hw;
	   	if ((err =
		configure_write_channel(&codec->s[SNDRV_PCM_STREAM_PLAYBACK],
				     audio_playback_dma_callback)) < 0)
		return err;

	}

	else if(stream_id == SNDRV_PCM_STREAM_CAPTURE){
	//	printk("zd:mx27_codec_open!\n");
		runtime->hw = mx27_codec_capture_hw;
		if ((err =
		configure_read_channel(&codec->s[SNDRV_PCM_STREAM_CAPTURE],
				     audio_capture_dma_callback)) < 0){
			//printk("zd:configure read channel fail!\n");		     
			return err;
			}
	}	   
	else{
		//printk("zd:stream_id fail!\n");
	  	return -ENODEV;
		}
	result = snd_pcm_hw_constraint_integer(runtime,SNDRV_PCM_HW_PARAM_PERIODS);
	if (result < 0)
		return result;
//	printk("zd:result before!\n");
	result = snd_pcm_hw_constraint_list(runtime, 0, 
					     SNDRV_PCM_HW_PARAM_RATE,
					     &hw_constraints_rates);
	//printk("Zd:%d\n", result);
	return result < 0 ? result : 0;
}

static int mx27_codec_close (snd_pcm_substream_t * substream)
{
	mx27_codec_t* codec = snd_pcm_substream_chip (substream);
	//struct wm8782_platform_data * pdata = codec->pdata;
	int stream_id = substream->pstr->stream;
	int channel=-1;
	int result ;

	ENTRY(1);
    //  printk("%s\n",__FUNCTION__);
	codec->s[substream->pstr->stream].substream = NULL;
	channel=codec->s[substream->pstr->stream].dma_channel;

	result=mxc_dma_free(channel);

	if (stream_id == SNDRV_PCM_STREAM_PLAYBACK){
		ssi_interrupt_disable(SSI_CODEC, ssi_tx_dma_interrupt_enable);
		ssi_interrupt_disable(SSI_CODEC, ssi_tx_fifo_0_empty);
		ssi_transmit_enable(SSI_CODEC, 0);
		ssi_tx_flush_fifo(SSI_CODEC);		
		}
	if (stream_id == SNDRV_PCM_STREAM_CAPTURE){
		//ssi_dump();
		ssi_interrupt_disable(SSI_CODEC, ssi_rx_dma_interrupt_enable);
		ssi_interrupt_disable(SSI_CODEC, ssi_rx_fifo_0_full);
		ssi_receive_enable(SSI_CODEC,0);
		ssi_rx_flush_fifo(SSI_CODEC);
		
		}

	//pdata->write(WM8782_ACTIVE,0x0000);
	
	//ssi_dump();
	return result < 0 ?result:0;
}

static int mx27_codec_hw_params (snd_pcm_substream_t* substream,
				     snd_pcm_hw_params_t* hw_params)
{
	snd_pcm_runtime_t *runtime;
	int result;

	ENTRY (0);

	runtime=substream->runtime;
	
	//printk("%s\n",__FUNCTION__);

	printk("dma_addr=%x\n",substream->runtime->dma_addr);
	   
	result = snd_pcm_lib_malloc_pages (substream, 
					   params_buffer_bytes (hw_params));
	if(result<0)
		return result;
	
	runtime->dma_addr = virt_to_phys(runtime->dma_area);
	
	DBG(1,"%s: dma_area=%x ",__FUNCTION__, (int)substream->runtime->dma_area);
	DBG(1,"dma_addr=%x,dma_bytes=%d\n",
		substream->runtime->dma_addr,substream->runtime->dma_bytes);
		
	return result;
}

static int mx27_codec_hw_free (snd_pcm_substream_t* substream)
{
	ENTRY (0);
	return snd_pcm_lib_free_pages (substream);
}

//start the codec.
static int mx27_codec_trigger(snd_pcm_substream_t* substream, int cmd)
{
	mx27_codec_t* codec = snd_pcm_substream_chip (substream);
	 int stream_id = substream->pstr->stream;
	audio_stream_t* s= &codec->s[stream_id];

	int result = 0;
       ENTRY (0);

#if 0
	printk("%s\n",__FUNCTION__);
        printk("rate=%d \n",substream->runtime->rate);
        printk("channel=%d \n",substream->runtime->channels);
        printk("frame_bits=%d \n",substream->runtime->frame_bits);
        printk("sample_bits=%d \n",substream->runtime->sample_bits);
        printk("periods=%d \n",substream->runtime->periods);
        printk("period_size=%ld \n",substream->runtime->period_size);



	printk("zd:s->period=%d\n",s->period);
	printk("zd:s->periods=%d\n",s->periods);
	printk("zd:s->active=%d\n",s->active);
	printk("zd:s->dma_channel=%d\n",s->dma_channel);
	printk("zd:s->tx_spin=%d\n",s->tx_spin);
	printk("zd:s->active=%d\n",s->active);
#endif

	DBG(0, "%s: trigger id %d cmd %d\n", __FUNCTION__, stream_id, cmd);

	if(stream_id==0)
		switch (cmd) {

		case SNDRV_PCM_TRIGGER_START:
			DBG (1, "trigger start stream %d\n", stream_id);

			s->tx_spin = 0;
			s->active = 1;

			audio_playback_dma(s);
			break;
		case SNDRV_PCM_TRIGGER_STOP:
			DBG (1, "trigger stop entry\n");
			s->tx_spin=0;
			s->active=0;
			audio_playback_stop_dma(s);
			break;
		case SNDRV_PCM_TRIGGER_SUSPEND:
			break;
		case SNDRV_PCM_TRIGGER_RESUME:
			break;
		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
			break;
		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
			break;
		default:
			result = -EINVAL;
			break;
	}

	if(stream_id==1)
		switch (cmd) {
		case SNDRV_PCM_TRIGGER_START:
		
			DBG (1, "trigger start stream %d\n", stream_id);
	  		s->tx_spin = 0;
			s->active = 1;
			audio_capture_dma(s);
		//	sleep(10);
			//ssi_dump();
	  		break;		
		case SNDRV_PCM_TRIGGER_STOP:
			DBG (1, "trigger stop\n");
			s->tx_spin=0;
			s->active=0;
			audio_capture_stop_dma(s);
		//	ssi_dump();
			break;
		case SNDRV_PCM_TRIGGER_SUSPEND:
			break;
		case SNDRV_PCM_TRIGGER_RESUME:
			break;
		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
			break;
		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
			break;
		default:
			result = -EINVAL;
			break;
	}
	return result;
}

static int mx27_codec_prepare (snd_pcm_substream_t* substream)
{
	mx27_codec_t* codec = snd_pcm_substream_chip (substream);
	//snd_pcm_runtime_t* runtime = substream->runtime;
	audio_stream_t* s = &codec->s[substream->pstr->stream];
	int id = substream->pstr->stream;
	int channel = substream->runtime->channels;
	
	ENTRY (0);
//	printk("%s\n",__FUNCTION__);
	
	s->period = 0;
	s->periods = 0;	
	//ssi_receive_enable(SSI_CODEC, 0);

	wm8782_pcm_prepare(substream);


//	printk("zd:sub->runtime->channel=%d\n", channel);
//	printk("zd:sample_bits=%d\n", runtime->sample_bits);

	if(id==0){
        printk("zd:it's playback!\n");
        }
	if(id==1){
#if 0

		ssi_receive_enable(SSI_CODEC, 0);
        		
		if(runtime->sample_bits == 16)
		{
			ssi_tx_word_length(SSI_CODEC, ssi_16_bits);
			ssi_rx_word_length(SSI_CODEC, ssi_16_bits);
		}
		if(runtime->sample_bits == 8)
		{
			ssi_tx_word_length(SSI_CODEC, ssi_8_bits);
			ssi_rx_word_length(SSI_CODEC, ssi_8_bits);
		}
#endif	
		ssi_receive_enable(SSI_CODEC, 0);
         //   printk("zd:codec prepare channel= %d\n", channel);
#if 0
		if(channel == 1)
			{
			//	ssi_rx_frame_rate(SSI_CODEC, 1);
				mx27_i2s_normal_mode_config();
			}
		else
		{
			//	ssi_rx_frame_rate(SSI_CODEC, 2);
				mx27_i2s_slave_mode_config();
		}
#endif	
		mx27_i2s_slave_mode_config();

		ssi_interrupt_enable(SSI_CODEC, ssi_rx_dma_interrupt_enable);
		ssi_interrupt_enable(SSI_CODEC, ssi_rx_fifo_0_full);
		//ssi_interrupt_enable(SSI_CODEC, ssi_tx_dma_interrupt_enable);  //add by zd
		//ssi_interrupt_enable(SSI_CODEC, ssi_tx_fifo_0_empty); //add by zd
		ssi_receive_enable(SSI_CODEC,1);
	}		
	return 0;
}

static snd_pcm_uframes_t mx27_codec_pointer (snd_pcm_substream_t* substream)
{
	mx27_codec_t* codec = snd_pcm_substream_chip (substream);
	audio_stream_t* s = (audio_stream_t *)(&(codec->s[substream->pstr->stream]));
	int stream_id=substream->pstr->stream;
	unsigned int c=0;
	
	ENTRY (3);
	//printk("sisr=0x%x\n",__raw_readl(IO_ADDRESS(SSI1_BASE_ADDR)+MXC_SSISISR));
	//printk("satag=0x%x\n",__raw_readl(IO_ADDRESS(SSI1_BASE_ADDR)+MXC_SSISATAG));
	if(stream_id==0){
		c = audio_get_playback_dma_pos(s);
		DBG (3,"ID0 pos c=0x%x\n", c);		
      	}

	if(stream_id==1){
		c = audio_get_capture_dma_pos(s);
		DBG(3,"ID1 pos c=%x\n", c);
	}	
	
	return c;
}

static snd_pcm_ops_t mx27_codec_playback_ops = {
	.open		= mx27_codec_open,
	.close		= mx27_codec_close,
	.ioctl			= snd_pcm_lib_ioctl,
	.hw_params	= mx27_codec_hw_params,
	.hw_free		= mx27_codec_hw_free,
	.prepare		= mx27_codec_prepare,
	.trigger		= mx27_codec_trigger,
	.pointer		= mx27_codec_pointer,
};
static snd_pcm_ops_t mx27_codec_capture_ops = {
	.open		= mx27_codec_open,
	.close		= mx27_codec_close,
	.ioctl			= snd_pcm_lib_ioctl,
	.hw_params	= mx27_codec_hw_params,
	.hw_free		= mx27_codec_hw_free,
	.prepare		= mx27_codec_prepare,
	.trigger		= mx27_codec_trigger,
	.pointer		= mx27_codec_pointer,
};

/* mx27_codec_pcm_init
   performs the hardware initialization for the PCM device.
*/
 int  mx27_codec_pcm_init (mx27_codec_t* codec, int device)
{
	snd_pcm_t* pcm;
	int result = 0;

	ENTRY (0);

	result = snd_pcm_new (codec->card, 
			      "mx27 PCM", device, 1, 1, &pcm);
	if (result)
		goto done;

	snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_PLAYBACK, 
			 &mx27_codec_playback_ops);
	snd_pcm_set_ops (pcm, SNDRV_PCM_STREAM_CAPTURE, 
			 &mx27_codec_capture_ops);

	snd_pcm_lib_preallocate_pages_for_all (pcm, 
				SNDRV_DMA_TYPE_CONTINUOUS,
				//((struct device *)(unsigned long)(GFP_KERNEL)),
				snd_dma_continuous_data(GFP_KERNEL),
				MAX_BUFFER_SIZE * 2 , MAX_BUFFER_SIZE * 2 );

	pcm->private_data = codec;
	pcm->info_flags = 0;
	strcpy (pcm->name, "mx27 PCM");

	mx27_codec_init (codec);
// audio_stream  init
	codec->pcm = pcm;

 done:
	return result;
}

EXPORT_SYMBOL_GPL(mx27_codec_pcm_init);

static int __init mx27_codec_driver_init (void)
{
	printk(KERN_INFO "MXC-WM8782 PCM module loaded successfully\n");
//	mx27_codec = kcalloc (1, sizeof (mx27_codec_t), GFP_KERNEL);
//	if (mx27_codec == NULL)
//		return -ENOMEM;
	return 0;
	
}

static void __exit mx27_codec_driver_exit (void)
{
	printk(KERN_INFO "MXC-WM8782 PCM module unloaded successfully\n");
//	kfree(mx27_codec);
}


module_init(mx27_codec_driver_init);
module_exit(mx27_codec_driver_exit);

MODULE_AUTHOR("Sitek Hengke, Ltd");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("xtp-d501 driver for ALSA");

⌨️ 快捷键说明

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