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

📄 cs4334.c

📁 经过一番努力
💻 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");


⌨️ 快捷键说明

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