📄 cs4334.c
字号:
/* * Cypress CS4334 Audio Device Driver for S3C44B0X uClinux * * Copyright (C) 2005 QHKJ * * Author : Vencent (zlg@qhkj.com) * */#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/interrupt.h>#include <linux/errno.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/pm.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/dma.h>#include <asm/arch/irqs.h>#include <asm/arch/s3c44b0x.h>//#include "wav.h"#undef DEBUG//#define DEBUG#ifdef DEBUG#define DPRINTK( x... ) printk( ##x )#else#define DPRINTK( x... )#endif#define DEVICE_NAME "audio"//#define IRQ_AUDIO S3C44B0X_INTERRUPT_BDMA0static int audio_rd_refcount;static int audio_wr_refcount;#define audio_active (audio_rd_refcount | audio_wr_refcount)static int audio_dev_dsp;#define BUF_LEN 300*1024 // 300K Bytestatic unsigned short buf[BUF_LEN/2];static unsigned short *data;int audio_major = 80; /* Select 0 for Dynamic adressing */#define AUDIO_NAME "CS4334"//#define MAX_WAVSIZE 0xfffff#define IIS_FIFOREADY !(((inl(S3C44B0X_IISCON))>>7)&1)static unsigned long pllvalue; //add vencent static unsigned int ubdiv;static ssize_t s3c44b0_audio_read(struct file *file, char *buffer, size_t count, loff_t *offp)//static ssize_t s3c44b0_audio_read(struct file *file, char *buffer, size_t count, char offp){ int i; //char *dev = file->private_data + offp; char *dev = file->private_data; #if 0 for(i = 0; i < count; i++) { printk("file_private_data: "); printk(" 0x%x", dev[i]); if(!(i % 10)) { printk("\n"); } }#endif copy_to_user(buffer, &dev, count); return count;}static ssize_t s3c44b0_audio_write(struct file *file, const char *buffer, size_t count, loff_t *offp){ unsigned short xx; unsigned int i; init_s3c44b0_iis_bus(); copy_from_user(buf, buffer, count); outl(inl(S3C44B0X_IISCON)|(0x01), S3C44B0X_IISCON); // IIS enable data = &buf[0]; while(1) { if(IIS_FIFOREADY) { for(i = 0; i < 8; i++) { xx = (unsigned short)(*data++);// printk(" xx = 0x%x\n", xx); outl(xx, S3C44B0X_IISFIF); } if((data - buf) > count) { data = &buf[0]; printk("##### Finish #####\n"); goto out; } } } out: outl(inl(S3C44B0X_IISCON)&(0xfe), S3C44B0X_IISCON); // IIS disable return 0;}static int audio_set_dsp_speed(long val){ printk(" Val = %ld\n", val); switch(val) { case 44100: outl(0x69081, S3C44B0X_PLLCON); //MCLK=45.1584M <--11.2896M*4 outl(24, S3C44B0X_UBRDIV0); outl(24, S3C44B0X_UBRDIV1); outl(0x11, S3C44B0X_IISPSR); // Prescaler_A/B enable, value=4 break; case 22050: outl(0x69081, S3C44B0X_PLLCON); // MCLK=45.1584M <--5.6448M*8 outl(24, S3C44B0X_UBRDIV0); outl(24, S3C44B0X_UBRDIV1); outl(0x33, S3C44B0X_IISPSR); // Prescaler_A/B enable, value=8 break; case 11025: outl(0x69081, S3C44B0X_PLLCON); // MCLK=45.1584M <--5.6448M*16 outl(24, S3C44B0X_UBRDIV0); outl(24, S3C44B0X_UBRDIV1); outl(0x77, S3C44B0X_IISPSR); // Prescaler_A/B enable, value=16 break; case 8000: outl(0x21061, S3C44B0X_PLLCON); // MCLK=20.48M<--2.048M*10 outl(10, S3C44B0X_UBRDIV0); outl(10, S3C44B0X_UBRDIV1); outl(0x44, S3C44B0X_IISPSR); // Prescaler_A/B enable, value=10 break; default: return -1; } return 0;}static int audio_set_dsp_channels(long val){ return 0;}static int audio_set_dsp_samplesize(long val){ return 0;}static int s3c44b0_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg){ long val; int ret; switch(cmd) { case SNDCTL_DSP_CHANNELS: case SNDCTL_DSP_STEREO: get_user(val, (long *) arg); ret = audio_set_dsp_channels(val); if (ret < 0) return -EINVAL; break; case SNDCTL_DSP_SPEED: get_user(val, (long *) arg); ret = audio_set_dsp_speed(val); if (ret < 0) return -EINVAL; break; case SNDCTL_DSP_SAMPLESIZE: get_user(val, (long *) arg); ret = audio_set_dsp_samplesize(val); if (ret < 0) return -EINVAL; break; default: return -EINVAL; } return 1;}/*static void s3c44b0_isr_audio(int irq, void *dev_id, struct pt_regs *reg){ outl((0x01)<<17, S3C44B0X_I_ISPC);}*/static int s3c44b0_audio_open(struct inode *inode, struct file *file){ //printk("Audio open!\n"); MOD_INC_USE_COUNT; return 0;}static int s3c44b0_audio_release(struct inode *inode, struct file *file){ //printk("Audio release!\n"); outl(pllvalue, S3C44B0X_PLLCON); outl(ubdiv, S3C44B0X_UBRDIV0); outl(ubdiv, S3C44B0X_UBRDIV1); MOD_DEC_USE_COUNT; return 0;}static struct file_operations s3c44b0_audio_fops = { read: s3c44b0_audio_read, write: s3c44b0_audio_write,// poll: s3c44b0_audio_poll, ioctl: s3c44b0_audio_ioctl, open: s3c44b0_audio_open, release: s3c44b0_audio_release,};static void init_s3c44b0_iis_io(void){ outl(inl(S3C44B0X_PCONC)|(0xcf), S3C44B0X_PCONC); // IISCLK IISDO IISLRCK initialize outl(inl(S3C44B0X_PCONE)|(0x20000), S3C44B0X_PCONE); // CODECLK/PE8 initialize}static void cs4334_init(void){// NULL}static void init_s3c44b0_iis_bus(void){ outl(inl(S3C44B0X_IISCON)&(~(0x1ff)), S3C44B0X_IISCON); outl(inl(S3C44B0X_IISCON)|(0x02), S3C44B0X_IISCON); // Tx DMA disable, Rx idle, Prescaler enable outl(inl(S3C44B0X_IISMOD)&(~(0x1ff)), S3C44B0X_IISMOD); outl(inl(S3C44B0X_IISMOD)|(0x89), S3C44B0X_IISMOD); // Master, Tx, L-ch=0, iis, 16bit, 256fs, 32fs// outl(inl(S3C44B0X_IISPSR)&(~(0xff)), S3C44B0X_IISPSR); // outl(inl(S3C44B0X_IISPSR)|(0x22), S3C44B0X_IISPSR); // Prescaler_A/B enable, value=6 outl(inl(S3C44B0X_IISFIFCON)&(~(0xfff)), S3C44B0X_IISFIFCON); outl(inl(S3C44B0X_IISFIFCON)|(0x200), S3C44B0X_IISFIFCON); // Tx normal, Tx FIFO // outl(inl(S3C44B0X_IISCON)|(0x01), S3C44B0X_IISCON); // IIS enable }/*static void init_s3c44b0_bdma(void){ outl(inl(S3C44B0X_BDISRC0)&(~(0xffffffff)), S3C44B0X_BDISRC0); outl(inl(S3C44B0X_BDISRC0)|((1<<30)+(1<<28)+(buf)), S3C44B0X_BDISRC0); outl(inl(S3C44B0X_BDIDES0)&(~(0xffffffff)), S3C44B0X_BDIDES0); outl(inl(S3C44B0X_BDIDES0)|((1<<30)+(3<<28)+(S3C44B0X_IISFIF)), S3C44B0X_BDIDES0); outl(inl(S3C44B0X_BDICNT0)&(~(0xffffffff)), S3C44B0X_BDICNT0); outl(inl(S3C44B0X_BDICNT0)|((1<<30)+(1<<26)+(3<<22)+(0<<21)+(1<<20)+(sizeof(buf)&(~(0x3)))), S3C44B0X_BDICNT0); outl(inl(S3C44B0X_BDICNT0)|(1<<20), S3C44B0X_BDICNT0); // enable DMA outl(inl(S3C44B0X_BDCON0)&(~(0xff)), S3C44B0X_BDCON0); // BDMA0 enable }static void cleanup_s3c44b0_bdma(void){ outl(inl(S3C44B0X_BDCON0)|(1<<2), S3C44B0X_BDCON0); // BDMA0 disable }*/int s3c44b0_audio_init(void){ unsigned long flags;// int ret; int cold = !audio_active; local_irq_save(flags); init_s3c44b0_iis_io(); local_irq_restore(flags); pllvalue = inl(S3C44B0X_PLLCON); printk("PLL VALUE : 0x%lx\n", pllvalue); ubdiv = inl(S3C44B0X_UBRDIV0); printk("UBDIV : %d\n", ubdiv); cs4334_init(); // init_s3c44b0_iis_bus(); // init_s3c44b0_bdma(); audio_dev_dsp = register_chrdev(audio_major, DEVICE_NAME, &s3c44b0_audio_fops); if(audio_dev_dsp < 0) { printk("Audio play initialized failed!\n"); return -ENODEV; } printk("Audio play initialized OK!\n"); /* ret = request_irq(IRQ_AUDIO, s3c44b0_isr_audio, 0, DEVICE_NAME, NULL); if(ret < 0) { printk("Audio Driver: Error while installing IRQ_AUDIO handler.\n"); //return -ENODEV; } else { printk("The Audio is registered successfully!\n"); //printk("ret = %d \n", ret); }*/ if(cold) { } return 0;}static void s3c44b0_audio_exit(void){ unregister_chrdev(audio_major,DEVICE_NAME);// cleanup_s3c44b0_bdma();// free_irq(IRQ_AUDIO, NULL); // outl(pllvalue, S3C44B0X_PLLCON);// outl(ubdiv, S3C44B0X_UBRDIV0);// outl(ubdiv, S3C44B0X_UBRDIV1); printk("Audio play unloaded!\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -