?? cs4334.c
字號:
#include <linux/module.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/compiler.h>
#include <linux/interrupt.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/pm.h>
#include <linux/errno.h>
#include <asm/dma.h>
#include <asm/hardware.h>
#include <asm/arch/irqs.h>
#define SOUND_NAME "audio"
#define SOUND_IRQ S3C44B0X_INTERRUPT_BDMA0
#ifndef AUDIO_CODEC_CLOCK
#define AUDIO_CODEC_CLOCK 256
#endif
#ifndef SOUND_MAJOR
#define SOUND_MAJOR 14
#endif
static const char sound_driver_version[] = "S3C44B0 Sound driver";
#define bmda1_id "BDMA1_audio"
static volatile unsigned int DMA_Done = 1;
static unsigned char audio_used=0;
static int sound_cpu_init(void)
{
(*(volatile unsigned *)S3C44B0X_PCONE)&=0x0ffff;
(*(volatile unsigned *)S3C44B0X_PCONE)|=0x20000;
(*(volatile unsigned *)S3C44B0X_PCONF)&=0x0703ff;
(*(volatile unsigned *)S3C44B0X_PCONF)|=0x209000;
return 0;
}
static int irq_sound(int irq, void *dev_id, struct pt_regs *regs)
{
DMA_Done = 1;
return 1;
}
static int sound_open(struct inode *inode, struct file *filp)
{
int retII=0;
if (audio_used) return -1;
audio_used=1;
MOD_INC_USE_COUNT;
DMA_Done = 1; // set start status.
retII=request_irq(SOUND_IRQ, irq_sound, SA_INTERRUPT,SOUND_NAME,NULL);
if (retII!=0)
{
printk(KERN_WARNING "s3c44b0_sound: failed to get IRQ\n");
return -1;
}
(*(volatile unsigned *)S3C44B0X_INTMSK)&=~(0x01<<S3C44B0X_INTERRUPT_BDMA0);
return 0;
}
static ssize_t sound_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
unsigned int dma_addr;
while ( DMA_Done == 0 ) {}
/* Aligment to half word*/
count &= 0xfffffffe;
dma_addr = (unsigned int) buf;
dma_addr = (dma_addr + 1) & 0x0ffffffe;
/****** IIS Initialize ******/
(*(volatile unsigned *)S3C44B0X_IISCON)=0x22;
#if (AUDIO_CODEC_CLOCK == 256)
(*(volatile unsigned *)S3C44B0X_IISMOD)=0x89; //Master,Tx,L-ch=low,iis,16bit ch.,codeclk=256fs,lrck=32fs
#else
(*(volatile unsigned *)S3C44B0X_IISMOD)=0x8D; //Master,Tx,L-ch=low,iis,16bit ch.,codeclk=384fs,lrck=32fs
#endif
(*(volatile unsigned *)S3C44B0X_IISFIFCON)=0xa00;
/****** DMA Initialize ******/
(*(volatile unsigned *)S3C44B0X_BDISRC0)=(1<<30)+(1<<28)+ dma_addr; //Half word,inc,Buf
(*(volatile unsigned *)S3C44B0X_BDIDES0)=(1<<30)+(3<<28)+(unsigned int)(S3C44B0X_IISFIF);
(*(volatile unsigned *)S3C44B0X_BDICNT0)=(1<<30)+(1<<26)+(3<<22)+(0<<21)+(0<<20)+count;
(*(volatile unsigned *)S3C44B0X_BDICNT0)|=0x01<<20;
(*(volatile unsigned *)S3C44B0X_BDCON0)=0x0<<2; // Enable DMA
DMA_Done = 0;
(*(volatile unsigned *)S3C44B0X_IISCON)|=0x01;
return count;
}
static int sound_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
/*cancel the DMA*/
(*(volatile unsigned *)S3C44B0X_BDCON0)=0x07;
/*Disable IIS*/
(*(volatile unsigned *)S3C44B0X_IISCON)=0x0c;
DMA_Done = 0;
audio_used=0;
free_irq(SOUND_IRQ,NULL);
return 0;
}
static int sound_ioctl(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg)
{
long val = 0;
int ret = 0;
switch (cmd) {
case SNDCTL_DSP_STEREO:
ret = get_user(val, (int *) arg);
if (ret)
return ret;
ret = (val == 0) ? -EINVAL : 1;
return put_user(ret, (int *) arg);
case SNDCTL_DSP_CHANNELS:
case SOUND_PCM_READ_CHANNELS:
/* the CS4334 is stereo only */
return put_user(2, (long *) arg);
case SNDCTL_DSP_SPEED:
ret = get_user(val, (long *) arg);
if (ret) break;
if (val < 8000) val = 8000;
if (val > 44100) val = 44100;
switch(val) {
case 8000:
#if (AUDIO_CODEC_CLOCK == 256)
(*(volatile unsigned *)S3C44B0X_IISPSR)=(6<<4)+6; /*System clock too high,*/
#else
(*(volatile unsigned *)S3C44B0X_IISPSR=(6<<4)+6; /*System clock too high*/
#endif
break;
case 11025:
#if (AUDIO_CODEC_CLOCK == 256)
(*(volatile unsigned *)S3C44B0X_IISPSR)=(6<<4)+6; /*System clock too high*/
#else
(*(volatile unsigned *)S3C44B0X_IISPSR)=(6<<4)+6; /*Should be 14*/
#endif
break;
case 22050:
#if (AUDIO_CODEC_CLOCK == 256)
(*(volatile unsigned *)S3C44B0X_IISPSR)=(4<<4)+4; /*Should be 10.6 */
#else
(*(volatile unsigned *)S3C44B0X_IISPSR)=(0xe<<4)+0xe; /*Should be 7*/
#endif
break;
case 44100:
#if (AUDIO_CODEC_CLOCK == 256)
(*(volatile unsigned *)S3C44B0X_IISPSR)=(0xc<<4)+0xc; /*Should be 5.31*/
#else
(*(volatile unsigned *)S3C44B0X_IISPSR=(1<<4)+1; /*Should be 3.5*/
#endif
break;
default:
#if (AUDIO_CODEC_CLOCK == 256)
(*(volatile unsigned *)S3C44B0X_IISPSR)=(4<<4)+4;
#else
(*(volatile unsigned *)S3C44B0X_IISPSR)=(6<<4)+6;
#endif
break;
}
case SOUND_PCM_READ_RATE: /* I am n't sure what it is */
return put_user(val , (long *) arg);
case SNDCTL_DSP_SETFMT:
case SNDCTL_DSP_GETFMTS:
return put_user(AFMT_S16_LE, (long *) arg);
default:
return ret;
}
return ret;
}
static struct file_operations sound_fops = {
.write=(void(*))sound_write,
.ioctl=(void(*))sound_ioctl,
.open=(void(*))sound_open,
.release=(void(*))sound_release,
};
int __init sound_init_module(void)
{
int ret;
(*(volatile unsigned *)S3C44B0X_INTMSK)|=(0x01<<S3C44B0X_INTERRUPT_BDMA0);
sound_cpu_init();
#if (AUDIO_CODEC_CLOCK == 256)
(*(volatile unsigned *)S3C44B0X_IISPSR)=(4<<4)+4; /*Should be 10.6 , the register is 4 */
#else
(*(volatile unsigned *)S3C44B0X_IISPSR)=(0xe<<4)+0xe; /*Should be 7 */
#endif
ret=register_chrdev(SOUND_MAJOR,SOUND_NAME,&sound_fops);
if (ret<0)
{
printk(": can't get major number\n");
return -1;
}
printk("%s\n",sound_driver_version);
return 0;
}
void __exit sound_cleanup_module(void)
{
printk(": S3C44B0 Sound Exit.\n");
unregister_chrdev(SOUND_MAJOR,SOUND_NAME);
}
module_init(sound_init_module);
module_exit(sound_cleanup_module);
MODULE_DESCRIPTION("S3C44B0 Sound(CS4334) driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("decker_0422@163.com");
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -