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

📄 at91_audio.c

📁 H9200F(2.6.12)的音频接口驱动。 操作方法: 1、将驱动程序rsound.ko拷贝到系统目录:/lib/modules 2、执行如下命令加载模块: insmod /
💻 C
📖 第 1 页 / 共 2 页
字号:
/*----------------------------------------------------------**	linux/drivers/at91/at91_audio.c**		****	Copyright (C) 2006 Hyesco Technology Co.,Ltd****	Author: casiawu <wujh@hyesco.com>****	History:****	2006.4   casiawu  <wujh@hyesco.com>**               Original version**---------------------------------------------------------*/#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/poll.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/ioport.h>//#include <sound_config.h>//#include <dev_table.h>#include <linux/soundcard.h>#include <linux/sound.h>#include <linux/interrupt.h>#include <asm/arch/AT91RM9200_SSC.h>#include <asm/arch/board.h>#include "at91_audio.h"#include "i2c.h"#define I2S_ASY_MASTER_TX_SETTING(nb_bit_by_slot, nb_slot_by_frame)( +\AT91C_SSC_CKS_DIV   +\AT91C_SSC_CKO_CONTINOUS      +\AT91C_SSC_START_FALL_RF +\((1<<16) & AT91C_SSC_STTDLY) +\((((nb_bit_by_slot*nb_slot_by_frame)/2)-1) <<24))#define I2S_ASY_TX_FRAME_SETTING(nb_bit_by_slot, nb_slot_by_frame)( +\(nb_bit_by_slot-1)  +\AT91C_SSC_MSBF   +\(((nb_slot_by_frame-1)<<8) & AT91C_SSC_DATNB)  +\(((nb_bit_by_slot-1)<<16) & AT91C_SSC_FSLEN) +\AT91C_SSC_FSOS_NEGATIVE)#define NEXT_BUF(_s_,_b_) { \        (_s_)->_b_##_idx++; \        (_s_)->_b_##_idx %= (_s_)->nbfrags; \        (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; }                                                                         #define AUDIO_MODULE_NAME "AT91_AUDIO"     /* global definitions */#define AUDIO_NBFRAGS_DEFAULT	8#define AUDIO_FRAGSIZE_DEFAULT	(8*1024)                                                                                                                                                                                                                                     #define SLOT_BY_FRAME	2#define BITS_BY_SLOT	16static int audio_dev_dsp; static unsigned int a9200_stereo;static unsigned int a9200_bits;AT91PS_SSC ssc_regs;AT91PS_PDC pdc_regs;unsigned char uda1380_rx_init[] = {	0x00, 0x0f, 0x3f,	0x01, 0x00, 0x88,	0x02, 0xaf, 0xff,	0x03, 0x00, 0x00,	0x04, 0x02, 0x02,	0x10, 0x00, 0x00,	0x11, 0xb0, 0xb0,	0x12, 0x00, 0x00,	0x13, 0x00, 0x00,	0x14, 0x00, 0x00,	0x20, 0x00, 0x00,	0x21, 0x08, 0x08,	0x22, 0x16, 0x0C,	0x23, 0x00, 0x00};	/*----------------------------------------------------- * Name :      codec_init() * Function:   Init the code chip  * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/	void codec_init(unsigned char *command){        int ic;        unsigned int msb, lsb, data, reg;                                                                                        DPRINTK("Testing I2C\n");                for (ic = 0; ic < 42; ic += 3) {                reg = command[ic];                lsb = command[ic + 1];                msb = command[ic + 2];                data = msb << 8 | lsb;                I2C_write(reg, data, 2);        }}  /*----------------------------------------------------- * Name :      AT91F_SSC_SetBaudrate() * Function:   Set the baudrate according to the CPU clock * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/__inline void AT91F_SSC_SetBaudrate (        AT91PS_SSC pSSC,        // \arg pointer to a SSC controller        unsigned int mainClock, // \arg peripheral clock        unsigned int speed)     // \arg SSC baudrate{        unsigned int baud_value;        //* Define the baud rate divisor register        if (speed == 0)           baud_value = 0;        else        {           baud_value = (unsigned int) (mainClock * 10)/(2*speed);           if ((baud_value % 10) >= 5)                  baud_value = (baud_value / 10) + 1;           else                  baud_value /= 10;        }        pSSC->SSC_CMR = baud_value;}                                                                              /*----------------------------------------------------- * Name :      SSC_init() * Function:   Init the PIO and SSC REG  * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/	                                                                            void SSC_init(void){     DPRINTK("Init SSC...\n");          //init the global variables     a9200_bits = 16;     a9200_stereo = 1;            ssc_regs = (AT91PS_SSC) AT91C_VA_BASE_SSC1;     pdc_regs = (AT91PS_PDC) AT91C_VA_BASE_PDC_SSC1;        	   // Configure SSC1 PIOs  TF/TK/TD       AT91_SYS->PIOB_PDR = AT91C_PB6_TF1 | AT91C_PB7_TK1 | AT91C_PB8_TD1 | AT91C_PB9_RD1 | AT91C_PB10_RK1;     AT91_SYS->PIOB_ASR = AT91C_PB6_TF1 | AT91C_PB7_TK1 | AT91C_PB8_TD1 | AT91C_PB9_RD1 | AT91C_PB10_RK1;                                                                          AT91_SYS->PMC_PCER = 1 << AT91C_ID_SSC1;/* Peripheral Clock Enable */     /*soft reset */     ssc_regs->SSC_CR = AT91C_SSC_SWRST;                                                                                     AT91F_SSC_SetBaudrate(ssc_regs, at91_master_clock,FILE_SAMPLING_FREQ *(BITS_BY_SLOT * SLOT_BY_FRAME));     ssc_regs->SSC_IDR = 0xCFF;      //disabled all                                                                                     /* SSC Transmit Clock Mode Register */     ssc_regs->SSC_TCMR = I2S_ASY_MASTER_TX_SETTING(BITS_BY_SLOT,SLOT_BY_FRAME);     /* SSC Transmit Frame Mode Register */     ssc_regs->SSC_TFMR = I2S_ASY_TX_FRAME_SETTING(BITS_BY_SLOT,SLOT_BY_FRAME);     /* SSC_RFMR */     ssc_regs->SSC_RFMR = I2S_ASY_TX_FRAME_SETTING(BITS_BY_SLOT,SLOT_BY_FRAME);     /* SSC_RCMR */     ssc_regs->SSC_RCMR = I2S_ASY_MASTER_TX_SETTING(BITS_BY_SLOT,SLOT_BY_FRAME);          ssc_regs->SSC_CR |= (AT91C_SSC_RXDIS | AT91C_SSC_TXEN)  ;		// ssc_regs->SSC_IER |= (AT91C_SSC_ENDTX | AT91C_SSC_TXBUFE | AT91C_SSC_ENDRX | AT91C_SSC_RXBUFF);		 		 pdc_regs->PDC_PTCR |= (AT91C_PDC_RXTDIS | AT91C_PDC_TXTEN );       }/*----------------------------------------------------- * Name :      at91_audio_open() * Function:   Open aduio dev  * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/ int at91_audio_open(struct inode * inode, struct file * filp){	// MOD_INC_USE_COUNT;	 return 0;}/*----------------------------------------------------- * Name :      at91_audio_release() * Function:   Release audio dev  * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/int at91_audio_release(struct inode * inode,struct file * filp){	// MOD_DEC_USE_COUNT;	 return 0;}	/*----------------------------------------------------- * Name :      at91_audio_ioctl() * Function:   Audio IO Control  * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/ int at91_audio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){	  return 0;}                                                                                                                                                         /*----------------------------------------------------- * Name :      at91_audio_clear_buf() * Function:   frees all buffers  * Last rework data: 06-04-14   wujh@hyesco.com *----------------------------------------------------*/static void at91_audio_clear_buf(audio_stream_t * s){	  DPRINTK("aduio_clear_buf\n");	  s->active = 0;	  	  at91rm9200_dma_flush_all(s->dma);	  if (s->buffers) {		  int frag;		  for (frag = 0; frag < s->nbfrags; frag++) {			if (!s->buffers[frag].master)				  continue;			dma_free_coherent(NULL, s->buffers[frag].master, s->buffers[frag].start, s->buffers[frag].dma_addr);					}				kfree(s->buffers);		s->buffers = NULL;	}	  s->buf_idx = 0;	  s->buf = NULL;}/*----------------------------------------------------- * Name :      at91_audio_setup_buf() * Function:   This function allocates the buffer structure array  * and buffer data space according to the current number of  * fragments and fragment size.  * Last rework data: 06-04-14   wujh@hyesco.com *----------------------------------------------------*/static int at91_audio_setup_buf(audio_stream_t * s){	int frag;	int dmasize = 0;	char *dmabuf = NULL;	dma_addr_t dmaphys = 0;	if (s->buffers)		return -EBUSY;	s->buffers = (audio_buf_t *)kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);	if (!s->buffers)		goto err;	memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);	for (frag = 0; frag < s->nbfrags; frag++) {		audio_buf_t *b = &s->buffers[frag];		/*		 * Let's allocate non-cached memory for DMA buffers.		 * We try to allocate all memory at once.		 * If this fails (a common reason is memory fragmentation),		 * then we allocate more smaller buffers.		 */		if (!dmasize) {			dmasize = (s->nbfrags - frag) * s->fragsize;			do {					dmabuf = dma_alloc_coherent(NULL, dmasize, &dmaphys, GFP_KERNEL);				if (!dmabuf)					dmasize -= s->fragsize;			} while (!dmabuf && dmasize);			if (!dmabuf)				goto err;			b->master = dmasize;			memzero(dmabuf, dmasize);		}		b->start = dmabuf;		b->dma_addr = dmaphys;		b->stream = s;		sema_init(&b->sem, 1);		DPRINTK("buf %d: start %p dma %p\n", frag, b->start,			b->dma_addr);		dmabuf += s->fragsize;		dmaphys += s->fragsize;		dmasize -= s->fragsize;	}	s->buf_idx = 0;	s->buf = &s->buffers[0];	return 0;err:	printk(" unable to allocate audio memory\n ");	at91_audio_clear_buf(s);	return -ENOMEM;}/*----------------------------------------------------- * Name :      at91_audio_prime_dma() * Function:   Send data buffer to dma queue  * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/static void at91_audio_prime_dma(audio_stream_t *s){	int i;	s->active = 1;	for (i = 0; i < s->nbfrags; i++) {		audio_buf_t *b = s->buf;		down(&b->sem);		at91rm9200_dma_queue_buffer(s->dma, (void *) b,					b->dma_addr, s->fragsize);		NEXT_BUF(s, buf);	}}/*----------------------------------------------------- * Name :      at91_audio_read() * Function:   Read Data from Audio and Send to user  * Last rework data: 06-04-13   wujh@hyesco.com *----------------------------------------------------*/static ssize_t at91_audio_read(struct file *file, char *buffer,		      size_t count, loff_t * ppos){	 audio_stream_t *s = &input_stream;	 unsigned long bufcnt,chunksize;	 unsigned long ret = 0,i=0,tmpint=0,tmpint2=0;     unsigned short *buflp;   unsigned long *appbuflp;   audio_buf_t *b;      bufcnt = count ;   appbuflp = (unsigned long *)buffer;		 ret = -ERESTARTSYS;	 DPRINTK("audio_read: count=%d\n", count);   if(a9200_stereo == 1)   	  bufcnt >>= 1;   if(a9200_bits == 16)      bufcnt >>= 1;	 if (!s->active) {		     if (!s->buffers && at91_audio_setup_buf(s))			   return -ENOMEM;                           DPRINTK("audio_read: audio_prime_dma(s)\n");						     at91_audio_prime_dma(s);	 }	 wmb();	 b = s->buf;	    ssc_regs->SSC_CR |= AT91C_SSC_RXEN  ;   pdc_regs->PDC_PTCR |= AT91C_PDC_RXTEN;	    wmb();	 	 while (bufcnt) {		  			if (down_interruptible(&b->sem))				break;		  			 /* Grab data from the current buffer */		 chunksize = b->size;		 if (chunksize > 2*bufcnt)		 chunksize = 2*bufcnt;					 DPRINTK("read %d from %d\n", chunksize, s->buf_idx);

⌨️ 快捷键说明

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