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

📄 sound.c

📁 基于AT91RM9200 板卡的LM4390音频驱动程序LM4390连接于9200的SSC0接口
💻 C
字号:
/*  * sound GPIO interface for Linux on Atmel AT91RM9200 * Copyright (c) 2006 Ligang Wang * wangzitan@163.com *//* include some file */ #include <linux/module.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/string.h>#include <linux/poll.h>#include <linux/init.h>#include <asm/io.h>#include <asm/system.h>#include <asm/arch/hardware.h>#include <asm/segment.h>#include "sound.h"/* define some macro for this module*/static AT91PS_SYS AT91_SYS1 = (AT91PS_SYS) AT91C_VA_BASE_SYS;static AT91PS_TWI pTWI = (AT91PS_TWI) AT91C_VA_BASE_TWI;static AT91PS_SSC pSSC0 = (AT91PS_SSC) AT91C_VA_BASE_SSC0; int AT91F_TWI_Write(int address, char *data2send, int size)
{
	unsigned int status;
	// Set the TWI Master Mode Register
	pTWI->TWI_MMR = ((address <<16) | AT91C_TWI_IADRSZ_NO ) & ~AT91C_TWI_MREAD;	
	// Set TWI Internal Address Register
	status = pTWI->TWI_SR;
	pTWI->TWI_THR = *(data2send++);
	pTWI->TWI_CR = AT91C_TWI_START;
	while (size-- >1)	{
		// Wait THR Holding register to be empty
		while (!(pTWI->TWI_SR & AT91C_TWI_TXRDY));
		// Send first byte
		pTWI->TWI_THR = *(data2send++);
	}

	pTWI->TWI_CR = AT91C_TWI_STOP;		
	status = pTWI->TWI_SR;
	// Wait transfer is finished
    while (!(pTWI->TWI_SR & AT91C_TWI_TXCOMP));
	return 0;
}
//*=========================================================
//*		READ
//*=========================================================
//*----------------------------------------------------------------------------
//* \fn    AT91F_TWI_Read
//* \brief Read n bytes from a slave device
//*----------------------------------------------------------------------------
int AT91F_TWI_Read(int address, char *data, int size)
{
	unsigned int status;
	char temp;
	
	// Set the TWI Master Mode Register
	pTWI->TWI_MMR = address | AT91C_TWI_IADRSZ_NO | AT91C_TWI_MREAD;	
	// Set TWI Internal Address Register
	//pTWI->TWI_IADR = address;
	// Start transfer
	pTWI->TWI_CR = AT91C_TWI_START;
	status = pTWI->TWI_SR;
	temp	=	pTWI->TWI_RHR;	
	while (size-- >1)	{
		// Wait RHR Holding register is full
		while (!(pTWI->TWI_SR & AT91C_TWI_RXRDY))
		{
			//print(pTWI->TWI_SR);
		};
		// Read byte
		*(data++) = pTWI->TWI_RHR;
	}
	pTWI->TWI_CR = AT91C_TWI_STOP;
	status = pTWI->TWI_SR;
	// Wait transfer is finished
    while (!(pTWI->TWI_SR & AT91C_TWI_TXCOMP));
	// Read last byte
	*data = pTWI->TWI_RHR;	
	return 0;
}/* * Read funcation for vfs */ssize_t at91_sound_read(struct file * file, char *buf, size_t count, loff_t * ppos){	//int retval;	return 0;}/* * Write funcation for vfs */
static char * data;ssize_t at91_sound_write(struct file * file, const char * buf, size_t count, loff_t * ppos){
	int loop;	int retval = 0;
	unsigned short * pdata;
	int data_size;
	if(count > 1024 * sizeof(int))
	{
		retval = copy_from_user((char *)data,buf,1024 * sizeof(int));
		data_size = 1024 * sizeof(int);	}
	else
	{
		retval = copy_from_user((char *)data,buf,count);
		data_size = count;
	}	if (retval)		return retval;	
	pdata = (unsigned short *)data;
	
	for(loop = 0; loop < data_size/(sizeof(unsigned short)); loop++)
	{
		pSSC0->SSC_THR = *pdata;   /* Write the TD data */
		while((pSSC0->SSC_SR & AT91C_SSC_TXRDY)==0){ } /* Wait ready */	
		pdata++;  
	}
	return data_size;
}		/* open a device */static int at91_sound_open(struct inode* inode,struct file* file){	MOD_INC_USE_COUNT;
	return 0;	}/* * Handle commands from user-space. */static int at91_sound_ioctl(struct inode *inode, struct file *file,		unsigned int cmd, unsigned long arg){		unsigned arg_data = 0;		switch(cmd) 		{			//handle select dev and port command			case 48000:
				pSSC0->SSC_CMR = 20;				break;			case 44100:				pSSC0->SSC_CMR = 21;
				break;
			case 22050:
				pSSC0->SSC_CMR = 43;
				break;
			case 16000:
				pSSC0->SSC_CMR = 59;
				break;
			case 8000:
				pSSC0->SSC_CMR = 117;
				break;
			default:
				return;		}	return 0;
}void set_twi_clock()
{
	int sclock;

	/* Here, CKDIV = 1 and CHDIV=CLDIV  ==> CLDIV = CHDIV = 1/4*((Fmclk/FTWI) -6)*/

	sclock = (10*AT91C_MASTER_CLOCK /AT91C_TWI_CLOCK);
	if (sclock % 10 >= 5)
		sclock = (sclock /10) - 5;
	else
		sclock = (sclock /10)- 6;
	sclock = (sclock + (4 - sclock %4)) >> 2;	// div 4

    pTWI->TWI_CWGR	=(AT91C_TWI_CLDIV|AT91C_TWI_CHDIV|(0x02 <<16));// 0x00010000 | sclock | (sclock << 8);
}
void TWI_Configure ()
{
    //* Disable interrupts
	pTWI->TWI_IDR = (unsigned int) -1;
    //* Reset peripheral
	pTWI->TWI_CR = AT91C_TWI_SWRST;
	//* Set Master mode
	pTWI->TWI_CR = AT91C_TWI_MSEN;
}/* * setup sound hardware */static void at91_sound_setup(void){	// Configure TWI PIOs	char write[2];	int loop;	unsigned short * tmp;
	//AT91_CfgPIO_TWI();	AT91_SYS1->PIOA_PDR = AT91C_PA25_TWD|AT91C_PA26_TWCK;	AT91_SYS1->PIOA_ASR = AT91C_PA25_TWD|AT91C_PA26_TWCK;	AT91_SYS1->PIOA_MDDR = ~AT91C_PA25_TWD;	AT91_SYS1->PIOA_MDER = AT91C_PA25_TWD;		// Configure PMC by enabling TWI clock	AT91_SYS1->PMC_PCER = (unsigned int) (1 << AT91C_ID_TWI);		// Configure TWI in master mode	TWI_Configure();		// Set TWI Clock Waveform Generator Register	set_twi_clock();		//I2S setup;	// Configure I2S PIOs	AT91_SYS1->PIOB_PDR = ((unsigned int) AT91C_PB1_TK0     ) |
			 ((unsigned int) AT91C_PB2_TD0     ) |
			 ((unsigned int) AT91C_PB0_TF0     );	//* Configure PMC by enabling SSC1 clock  	AT91_SYS1->PMC_PCER = (unsigned int) (1 << AT91C_ID_SSC0);		//* Reset All the Peripheral 	pSSC0->SSC_CR = AT91C_SSC_SWRST ;	pSSC0->SSC_CMR = 21;		pSSC0->SSC_TCMR =  ((((BITS_BY_SLOT*SLOT_BY_FRAME)/2) -1) <<24) |
   		   ((1<<16) & AT91C_SSC_STTDLY) |
		   AT91C_SSC_START_FALL_RF | 
		   AT91C_SSC_CKO_CONTINOUS | 	// continuous transmit clock
		   AT91C_SSC_CKS_DIV; 		// Divided clock     //set AT91C_SSC_STTOUT in TCMT +\  with out no work FOR VERSION BEFORE Rev F
     pSSC0->SSC_TFMR =  
     		AT91C_SSC_FSOS_LOW 	|
		(((BITS_BY_SLOT-1)<<16) & AT91C_SSC_FSLEN)  |   // Fslen => 16 Clock
		(((SLOT_BY_FRAME-1)<<8) & AT91C_SSC_DATNB) |   // 2 Data by frame
		 AT91C_SSC_MSBF	    		|	// MSB in first
		 (BITS_BY_SLOT-1) ;		// 16 bits
		//* Enable TX
	pSSC0->SSC_CR = AT91C_SSC_TXEN;    /* Enable Tx */		//configure lm4930	write[0] = 0x0;
	write[1] = 0x10;
	AT91F_TWI_Write(BASIC_CONFIG, write, 2);
	for (loop=0; loop<1000; loop++);
	
	write[0] = 0x00;
	write[1] = 0x06;
	AT91F_TWI_Write(BASIC_CONFIG, write, 2);
	for (loop=0; loop<1000; loop++);
	
	write[0] = 0x0;
	write[1] = 0x16;
	AT91F_TWI_Write(VOICETEST, write, 2);
	for (loop=0; loop<1000; loop++);
	
	write[0] = 0xff;
	write[1] = 0xff;
	AT91F_TWI_Write(GAINCONFIG, write, 2);
	for (loop=0; loop<1000; loop++);
	printk("Init complate\n");	return;}static int at91_sound_release(struct inode* inode,struct file* file){	MOD_DEC_USE_COUNT;	return 0;}struct file_operations at91_sound_fops = {	owner:       THIS_MODULE,
	write:		at91_sound_write,
	read:			at91_sound_read,	open:     at91_sound_open,	ioctl:		at91_sound_ioctl,	release:  at91_sound_release,};/* * Initialize and install sound driver */static int __init at91_sound_init(void){	at91_sound_setup();	if(register_chrdev(DEV_MAJOR,"sound",&at91_sound_fops))
	{		printk("sound: Can not register led driver \n");
		return -1;
	}	data = kmalloc(1024*sizeof(int),GFP_KERNEL);	if(!data)
	{
		printk("Kmalloc mem error\n");		return -1;
	}
	printk("soundboard: the sound is working now\n");	return 0;}/* * Disable and remove the sound driver */static void __exit at91_sound_exit(void){	printk("sound: at91_sound_exit has been called\n");	unregister_chrdev(DEV_MAJOR,"sound");
	kfree(data);	return;}module_init(at91_sound_init);module_exit(at91_sound_exit);MODULE_AUTHOR("Ligang Wang");MODULE_DESCRIPTION("AT91 rm9200 8255a driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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