📄 sound.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 + -