您的位置:首页 > 运维架构 > Linux

Sound Card(UDA1341) Driver for Linux2.6.xx+ARM9

2013-01-30 14:53 423 查看
/*

  *  UDA1341TS by chaozang(cz) <zangchao.cn@gmail.com>

  *  From 2013-01-26  To 2013-01-30

  */

----------------------------------------------------------driver---------------------------------------------------------------

#include <linux/module.h>

#include <linux/device.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 <linux/clk.h>

#include <linux/platform_device.h>

#include <asm/uaccess.h>

#include <asm/io.h>

#include <asm/hardware.h>

#include <asm/semaphore.h>

#include <asm/dma.h>

#include <asm/arch/dma.h>

#include <asm/arch/regs-gpio.h>

#include <asm/arch/regs-iis.h>

#include <asm/arch/regs-clock.h>

#include <linux/dma-mapping.h>

#include <asm/dma-mapping.h>

#include <asm/arch/hardware.h>

#include <asm/arch/map.h>

static volatile int waitq_condition = 0;

static DECLARE_WAIT_QUEUE_HEAD(waitq);

#define I2SSDI_DMA1 (010<<24) 

#define I2SSDO_DMA2 (000<<24)

#define DMAON (1<<1)

#define S3C2410_DCON_HANDSHAKE (1<<31)

#define S3C2410_DCON_SYNC_PCLK (0<<30)

#define S3C2410_DCON_INTREQ (1<<29)

#define S3C2410_DCON_TSZUNIT (0<<28)

#define S3C2410_DCON_SSERVE (0<<27)

#define S3C2410_DCON_HWTRIG (1<<23)

#define HALFWORD (1<<20)

#define IISFIFO 0x55000010

#define SRCONAHB (0<<1)

#define SRCONAPB (1<<1)

#define ADDRINC (0<<0)

#define ADDRFIX (1<<0)

#define DMASTOP (1<<2)

#define DMAON (1<<1)

#define DMAOFF (0<<1)

#define DMASW_TRIG (1<<0)

#define AUDIO_RATE_DEFAULT 44100

/* UDA1341 Register bits */

#define UDA1341_ADDR 0x14

#define UDA1341_REG_DATA0 (UDA1341_ADDR + 0)

#define UDA1341_REG_STATUS (UDA1341_ADDR + 2)

/* status control */

#define STAT0 (0x00)

#define STAT0_RST (1 << 6)

#define STAT0_SC_MASK (3 << 4)

#define STAT0_SC_512FS (0 << 4)

#define STAT0_SC_384FS (1 << 4)

#define STAT0_SC_256FS (2 << 4)

#define STAT0_IF_MASK (7 << 1)

#define STAT0_IF_I2S (0 << 1)

#define STAT0_IF_LSB16 (1 << 1)

#define STAT0_IF_LSB18 (2 << 1)

#define STAT0_IF_LSB20 (3 << 1)

#define STAT0_IF_MSB (4 << 1)

#define STAT0_IF_LSB16MSB (5 << 1)

#define STAT0_IF_LSB18MSB (6 << 1)

#define STAT0_IF_LSB20MSB (7 << 1)

#define STAT0_DC_FILTER (1 << 0)

#define STAT0_DC_NO_FILTER (0 << 0)

#define STAT1 (0x80)

#define STAT1_DAC_GAIN (1 << 6) /* gain of DAC */

#define STAT1_ADC_GAIN (1 << 5) /* gain of ADC */

#define STAT1_ADC_POL (1 << 4) /* polarity of ADC */

#define STAT1_DAC_POL (1 << 3) /* polarity of DAC */

#define STAT1_DBL_SPD (1 << 2) /* double speed playback */

#define STAT1_ADC_ON (1 << 1) /* ADC powered */

#define STAT1_DAC_ON (1 << 0) /* DAC powered */

/* data0 direct control */

#define DATA0 (0x00)

#define DATA0_VOLUME_MASK (0x3f)

#define DATA0_VOLUME(x) (x)

#define DATA1 (0x40)

#define DATA1_BASS(x) ((x) << 2)

#define DATA1_BASS_MASK (15 << 2)

#define DATA1_TREBLE(x) ((x))

#define DATA1_TREBLE_MASK (3)

#define DATA2 (0x80)

#define DATA2_PEAKAFTER (0x1 << 5)

#define DATA2_DEEMP_NONE (0x0 << 3)

#define DATA2_DEEMP_32KHz (0x1 << 3)

#define DATA2_DEEMP_44KHz (0x2 << 3)

#define DATA2_DEEMP_48KHz (0x3 << 3)

#define DATA2_MUTE (0x1 << 2)

#define DATA2_FILTER_FLAT (0x0 << 0)

#define DATA2_FILTER_MIN (0x1 << 0)

#define DATA2_FILTER_MAX (0x3 << 0)

/* data0 extend control */

#define EXTADDR(n) (0xc0 | (n))

#define EXTDATA(d) (0xe0 | (d))

#define EXT0 0

#define EXT0_CH1_GAIN(x) (x)

#define EXT1 1

#define EXT1_CH2_GAIN(x) (x)

#define EXT2 2

#define EXT2_MIC_GAIN_MASK (7 << 2)

#define EXT2_MIC_GAIN(x) ((x) << 2)

#define EXT2_MIXMODE_DOUBLEDIFF (0)

#define EXT2_MIXMODE_CH1 (1)

#define EXT2_MIXMODE_CH2 (2)

#define EXT2_MIXMODE_MIX (3)

#define EXT4 4

#define EXT4_AGC_ENABLE (1 << 4)

#define EXT4_INPUT_GAIN_MASK (3)

#define EXT4_INPUT_GAIN(x) ((x) & 3)

#define EXT5 5

#define EXT5_INPUT_GAIN(x) ((x) >> 2)

#define EXT6 6

#define EXT6_AGC_CONSTANT_MASK (7 << 2)

#define EXT6_AGC_CONSTANT(x) ((x) << 2)

#define EXT6_AGC_LEVEL_MASK (3)

#define EXT6_AGC_LEVEL(x) (x)

#define AUDIO_NAME "UDA1341"

#define AUDIO_NAME_VERBOSE "UDA1341 audio driver"

#define AUDIO_FMT_MASK (AFMT_S16_LE)

#define AUDIO_FMT_DEFAULT (AFMT_S16_LE)

#define AUDIO_CHANNELS_DEFAULT 2

#define AUDIO_RATE_DEFAULT 44100

#define AUDIO_NBFRAGS_DEFAULT 8

#define AUDIO_FRAGSIZE_DEFAULT 8192

#define S_CLOCK_FREQ 384

#define PCM_ABS(a) (a < 0 ? -a : a)

static u_int audio_rate;

struct iis_regs {

 unsigned long iiscon;

 unsigned long iismod;

 unsigned long iispsr;

 unsigned long iisfcon;

 unsigned long iisfifo;

};

static struct iis_regs *piis_regs_base;

struct dma_regs {

 unsigned long disrc;

 unsigned long disrcc;

 unsigned long didst;

 unsigned long didstc;

 unsigned long dcon;

 unsigned long dstat;

 unsigned long dcsrc;

 unsigned long dcdst;

 unsigned long dmasktrig;

};

static struct dma_regs *pdma_regs_in_base;

static struct dma_regs *pdma_regs_out_base;

static struct clk *iis_clock;

static int audio_dev_dsp;

static int audio_dev_mixer;

static int iispsr_value(int s_bit_clock, int sample_rate)

{

 int i, prescaler = 0;

 unsigned long tmpval;

 unsigned long tmpval384;

 unsigned long tmpval384min = 0xffff;

 tmpval384 = clk_get_rate(iis_clock) / s_bit_clock;

// tmpval384 = s3c2410_get_bus_clk(GET_PCLK) / s_bit_clock;

 for (i = 0; i < 32; i++) {

  tmpval = tmpval384/(i+1);

  if (PCM_ABS((sample_rate - tmpval)) < tmpval384min) {

   tmpval384min = PCM_ABS((sample_rate - tmpval));

   prescaler = i;

  }

 }

 printk("prescaler = %d\n", prescaler);

 return prescaler;

}

static long audio_set_dsp_speed(long val)

{

 unsigned int prescaler;

 prescaler=(IISPSR_A(iispsr_value(S_CLOCK_FREQ, val))

   | IISPSR_B(iispsr_value(S_CLOCK_FREQ, val)));

 __raw_writel(prescaler, piis_regs_base + S3C2410_IISPSR);

 printk("audio_set_dsp_speed:%ld prescaler:%i\n",val,prescaler);

 return (audio_rate = val);

}

static void czuda1341_l3_address(u8 data)

{

 printk("driver: czuda1341_l3_address in ok\n");

 int i;

 unsigned long flags;

 local_irq_save(flags);

 s3c2410_gpio_setpin(S3C2410_GPB2,0); //GPB 2: L3MODE

 s3c2410_gpio_setpin(S3C2410_GPB4,1);// GPB 4: L3CLOCK

 udelay(1);

 for (i = 0; i < 8; i++) {

  if (data & 0x1) {

   s3c2410_gpio_setpin(S3C2410_GPB4,0);

   s3c2410_gpio_setpin(S3C2410_GPB3,1);//set GPB 3: L3DATA 1

   udelay(1);

   s3c2410_gpio_setpin(S3C2410_GPB4,1);

  } else {

   s3c2410_gpio_setpin(S3C2410_GPB4,0);

   s3c2410_gpio_setpin(S3C2410_GPB3,0);//set GPB 3: L3DATA 0

   udelay(1);

   s3c2410_gpio_setpin(S3C2410_GPB4,1);

  }

  data >>= 1;

 }

 s3c2410_gpio_setpin(S3C2410_GPB2,1);//GPB 2: L3MODE

 s3c2410_gpio_setpin(S3C2410_GPB4,1);// GPB 4: L3CLOCK

 local_irq_restore(flags);

 printk("driver: czuda1341_l3_address out ok\n");

}

static void czuda1341_l3_data(u8 data)

{

 printk("driver: czuda1341_l3_data in ok\n");

 int i;

 unsigned long flags;

 local_irq_save(flags);

 udelay(1);

 for (i = 0; i < 8; i++) {

  if (data & 0x1) {

   s3c2410_gpio_setpin(S3C2410_GPB4,0);

   s3c2410_gpio_setpin(S3C2410_GPB3,1);

   udelay(1);

   s3c2410_gpio_setpin(S3C2410_GPB4,1);

  } else {

   s3c2410_gpio_setpin(S3C2410_GPB4,0);

   s3c2410_gpio_setpin(S3C2410_GPB3,0);

   udelay(1);

   s3c2410_gpio_setpin(S3C2410_GPB4,1);

  }

  data >>= 1;

 }

 local_irq_restore(flags);

 printk("driver: czuda1341_l3_data out ok\n");

}

static irqreturn_t cz_dma_irqhandler(int irq, void *dev_id)



 printk("driver: cz_dma_irqhandler in ok\n");

 waitq_condition = 1;

 wake_up_interruptible(&waitq);

 

 printk("driver: cz_dma_irqhandler out ok\n");

 return IRQ_HANDLED;

}

#if 0

static const struct file_operations czuda1341_fops = {

 .owner  = THIS_MODULE,

 .read  = czdma_read,

 .write  = czdma_write,

 //.open  = czdma_open,

 //.release = czdma_release,

 //.ioctl      = czdma_ioctl,

};

static  int major;

static struct class *pczuda1341_cls;

static struct class_device *pczuda1341_cls_dev;

#endif

static int cz_dmainit(int in,unsigned long addr,unsigned int size)

{

 printk("driver: cz_dmainit in ok\n");

 unsigned long flags;

 if(in)

  {

   //init dma_in, from uda1341 to mem, recorded

   local_irq_restore(flags); 

   request_irq(IRQ_DMA1, cz_dma_irqhandler, IRQF_DISABLED, "IRQ_DMA1", "dma1");

   local_irq_save(flags);

   printk("driver: cz_dmainit if request_irq ok\n");

   pdma_regs_in_base->disrc = addr;//from;

   pdma_regs_in_base->didst = IISFIFO;

   pdma_regs_in_base->disrcc = SRCONAPB|ADDRINC;//src(uda1341) is on ph bus

   pdma_regs_in_base->didstc = (0<<2)|SRCONAHB|ADDRINC;//dst(mem) is on sys bus

   pdma_regs_in_base->dcon = S3C2410_DCON_HANDSHAKE|S3C2410_DCON_SYNC_PCLK|S3C2410_DCON_INTREQ|S3C2410_DCON_TSZUNIT|S3C2410_DCON_SSERVE|I2SSDI_DMA1|\

                        S3C2410_DCON_HWTRIG|(1<<22)|HALFWORD|(size<<0);

   pdma_regs_in_base->dmasktrig = DMAON;//turn on DMA1

   printk("driver: cz_dmainit if DMAON ok\n");

  }

 else

  {

   //init dma_out, from mem to uda1341, play

   local_irq_restore(flags); 

   request_irq(IRQ_DMA2, cz_dma_irqhandler, IRQF_DISABLED, "IRQ_DMA2", "dma2");

   local_irq_save(flags);

   printk("driver: cz_dmainit else request_irq ok\n");

   

   pdma_regs_out_base->disrc = IISFIFO;

   pdma_regs_out_base->didst = addr;//to;

   pdma_regs_out_base->disrcc = SRCONAHB|ADDRINC;//src(mem) is on on sys bus

   pdma_regs_out_base->didstc = (0<<2)|SRCONAPB|ADDRINC;//dst(uda1341) is on  ph bus

   pdma_regs_out_base->dcon = S3C2410_DCON_HANDSHAKE|S3C2410_DCON_SYNC_PCLK|S3C2410_DCON_INTREQ|\

                 S3C2410_DCON_TSZUNIT|S3C2410_DCON_SSERVE|I2SSDO_DMA2|\

                        S3C2410_DCON_HWTRIG|(1<<22)|HALFWORD|(size<<0);

   pdma_regs_out_base->dmasktrig = DMAON;//turn on DMA2

   printk("driver: cz_dmainit else DMAON ok\n");

  }

  

 return 0;

}

static void init_s3c2410_iis_bus_rx(void){

 printk("driver: init_s3c2410_iis_bus_rx in ok\n");

 unsigned int iiscon = 0, iismod= 0, iisfcon= 0;

 iiscon |= (1<<1);//S3C2410_IISCON_PSCEN; // Enable prescaler

 iiscon |= (1<<0);//S3C2410_IISCON_IISEN; // Enable interface

 // iismod |= S3C2410_IISMOD_MASTER; // Set interface to Master Mode

 iismod |= (0<<5);//S3C2410_IISMOD_LR_LLOW; // Low for left channel

 iismod |= (1<<4);//S3C2410_IISMOD_MSB; // IIS format

 iismod |= (1<<3);//S3C2410_IISMOD_16BIT; // Serial data bit/channel is 16 bit

 iismod |= (1<<2);//S3C2410_IISMOD_384FS; // Master clock freq = 384 fs

 iismod |= (1<<0);//S3C2410_IISMOD_32FS; // 32 fs

 iisfcon |= (1<<14);//S3C2410_IISFCON_RXDMA; //Set RX FIFO acces mode to DMA

 iisfcon |= (1<<15);//S3C2410_IISFCON_TXDMA; //Set RX FIFO acces mode to DMA

 iiscon |= (1<<4);//S3C2410_IISCON_RXDMAEN; //Enable RX DMA service request

 iiscon |= (1<<3);//S3C2410_IISCON_TXIDLE; //Set TX channel idle

 iismod |= (1<<6);//S3C2410_IISMOD_RXMODE; //Set RX Mode

 iisfcon|= (1<<12);//S3C2410_IISFCON_RXENABLE; //Enable RX Fifo

 //setup the prescaler

 printk("driver: init_s3c2410_iis_bus_rx audio_rate ok\n");

 

 audio_set_dsp_speed(audio_rate);

 

 printk("driver: init_s3c2410_iis_bus_rx audio_set_dsp_speed ok\n");

 //iiscon has to be set last - it enables the interface

 __raw_writel(iismod, piis_regs_base + S3C2410_IISMOD);

 __raw_writel(iisfcon, piis_regs_base + S3C2410_IISFCON);

 __raw_writel(iiscon, piis_regs_base + S3C2410_IISCON);

 printk("driver: init_s3c2410_iis_bus_rx out ok\n");

}

static int cz_audio_read(struct file *file, char *buffer,

       size_t count, loff_t * ppos)

{

// uda1341 to iis to mem

 printk("driver: cz_audio_read in ok\n");

 cz_dmainit(1, (unsigned long)buffer, count);

 printk("driver: cz_audio_read cz_dmainit ok\n");

 waitq_condition = 0;

 wait_event_interruptible(waitq, waitq_condition);

 printk("driver: cz_audio_read wait_event_interruptible ok\n");

 return 0;

}

static void init_s3c2410_iis_bus_tx(void)

{

 printk("driver: init_s3c2410_iis_bus_tx in ok\n");

 unsigned int iiscon = 0, iismod= 0, iisfcon= 0;

//Kill everything...

 printk("driver: init_s3c2410_iis_bus_tx in");

 iowrite32(0, piis_regs_base + S3C2410_IISPSR);

 printk("driver: init_s3c2410_iis_bus_tx S3C2410_IISPSR");

 iowrite32(0, piis_regs_base + S3C2410_IISCON);

 iowrite32(0, piis_regs_base + S3C2410_IISMOD);

 iowrite32(0, piis_regs_base + S3C2410_IISFCON);

#if 0

 __raw_writel(0, iis_base + S3C2410_IISPSR);

 printk("driver: init_s3c2410_iis_bus_tx S3C2410_IISPSR");

 __raw_writel(0, iis_base + S3C2410_IISCON);

 __raw_writel(0, iis_base + S3C2410_IISMOD);

 __raw_writel(0, iis_base + S3C2410_IISFCON);

#endif

 clk_enable(iis_clock);

 iiscon = iismod = iisfcon = 0;

//Setup basic stuff

 iiscon |= S3C2410_IISCON_PSCEN; // Enable prescaler

 iiscon |= S3C2410_IISCON_IISEN; // Enable interface

// iismod |= S3C2410_IISMOD_MASTER; // Set interface to Master Mode

 iismod |= S3C2410_IISMOD_LR_LLOW; // Low for left channel

 iismod |= S3C2410_IISMOD_MSB; // MSB format

 iismod |= S3C2410_IISMOD_16BIT; // Serial data bit/channel is 16 bit

 iismod |= S3C2410_IISMOD_384FS; // Master clock freq = 384 fs

 iismod |= S3C2410_IISMOD_32FS; // 32 fs

 iisfcon|= S3C2410_IISFCON_RXDMA; //Set RX FIFO acces mode to DMA

 iisfcon|= S3C2410_IISFCON_TXDMA; //Set TX FIFO acces mode to DMA

 iiscon |= S3C2410_IISCON_TXDMAEN; //Enable TX DMA service request

 iiscon |= S3C2410_IISCON_RXIDLE; //Set RX channel idle

 iismod |= S3C2410_IISMOD_TXMODE; //Set TX Mode

 iisfcon|= S3C2410_IISFCON_TXENABLE; //Enable TX Fifo

//setup the prescaler

 audio_set_dsp_speed(audio_rate);

printk("driver: init_s3c2410_iis_bus_tx audio_rate ok\n");

//iiscon has to be set last - it enables the interface

 //printk("driver: init_s3c2410_iis_bus_tx audio_set_dsp_speed");

 iowrite32(iismod, piis_regs_base + S3C2410_IISMOD);

 printk("driver: init_s3c2410_iis_bus_tx S3C2410_IISMOD");

 iowrite32(iisfcon, piis_regs_base + S3C2410_IISFCON);

 iowrite32(iiscon, piis_regs_base + S3C2410_IISCON);

 printk("driver: init_s3c2410_iis_bus_tx out ok\n");

#if 0

 __raw_writel(iismod, iis_base + S3C2410_IISMOD);

 printk("driver: init_s3c2410_iis_bus_tx S3C2410_IISMOD");

 __raw_writel(iisfcon, iis_base + S3C2410_IISFCON);

 __raw_writel(iiscon, iis_base + S3C2410_IISCON);

#endif

}

static ssize_t cz_audio_write(struct file *file, const char *buffer,

        size_t count, loff_t * ppos)

{

// mem to iis to uda1341

 printk("driver: cz_audio_write in ok\n");

 cz_dmainit(0, (unsigned long)buffer, count);

 printk("driver: cz_audio_write cz_dmainit ok\n");

 waitq_condition = 0;

 wait_event_interruptible(waitq, waitq_condition);

 printk("driver: cz_audio_write wait_event_interruptible ok\n");

 return 0;

}

static int cz_audio_open(struct inode *inode, struct file *file)

{

 printk("driver: cz_audio_open in ok\n");

 if ((file->f_mode & FMODE_WRITE)){

  printk("driver: cz_audio_open FMODE_WRITE ok\n");

  audio_rate = AUDIO_RATE_DEFAULT;

  init_s3c2410_iis_bus_tx();

  printk("driver: cz_audio_open init_s3c2410_iis_bus_tx ok\n");

  //audio_clear_buf(&output_stream);

 }

 if ((file->f_mode & FMODE_READ)){

  printk("driver: cz_audio_open FMODE_READ ok\n");

  audio_rate = AUDIO_RATE_DEFAULT;

  init_s3c2410_iis_bus_rx();

  printk("driver: cz_audio_open init_s3c2410_iis_bus_rx ok\n");

  //audio_clear_buf(&input_stream);

 }

 return 0;

}

static struct file_operations smdk2410_audio_fops = {

 //llseek: smdk2410_audio_llseek,

 write: cz_audio_write,

 read: cz_audio_read,

 //poll: smdk2410_audio_poll,

 //ioctl: smdk2410_audio_ioctl,

 open: cz_audio_open,

 //release: smdk2410_audio_release

};

static struct file_operations smdk2410_mixer_fops = {

 //ioctl: smdk2410_mixer_ioctl,

 //open: smdk2410_mixer_open,

 //release: smdk2410_mixer_release

};

static int cz_uda1341_init(void) { 

 printk("driver: cz_uda1341_init in ok\n");

 unsigned long flags;

 

 iis_clock = clk_get(NULL, "iis");

 clk_enable(iis_clock);

 piis_regs_base     = ioremap(0x55000000,SZ_1M);

 

 pdma_regs_in_base  = ioremap(0x4B000040,SZ_1M);//DMA1

 pdma_regs_out_base = ioremap(0x4B000080,SZ_1M);//DMA2

 printk("driver: cz_uda1341_init pdma_regs_out_base ok\n");

 //iis & l3 pin set

 local_irq_save(flags);

 s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);  // GPB 4: L3CLOCK, OUTPUT

 s3c2410_gpio_pullup(S3C2410_GPB4,1);

 s3c2410_gpio_cfgpin(S3C2410_GPB3,S3C2410_GPB3_OUTP);   //GPB 3: L3DATA, OUTPUT

 s3c2410_gpio_cfgpin(S3C2410_GPB2,S3C2410_GPB2_OUTP);   //GPB 2: L3MODE, OUTPUT

 s3c2410_gpio_pullup(S3C2410_GPB2,1);

 s3c2410_gpio_cfgpin(S3C2410_GPE3,S3C2410_GPE3_I2SSDI); //GPE 3: I2SSDI

 s3c2410_gpio_pullup(S3C2410_GPE3,0);

 s3c2410_gpio_cfgpin(S3C2410_GPE0,S3C2410_GPE0_I2SLRCK);//GPE 0: I2SLRCK

 s3c2410_gpio_pullup(S3C2410_GPE0,0);

 s3c2410_gpio_cfgpin(S3C2410_GPE1,S3C2410_GPE1_I2SSCLK);//GPE 1: I2SSCLK

 s3c2410_gpio_pullup(S3C2410_GPE1,0);

 s3c2410_gpio_cfgpin(S3C2410_GPE2,S3C2410_GPE2_CDCLK);  //GPE 2: CDCLK

 s3c2410_gpio_pullup(S3C2410_GPE2,0);

 s3c2410_gpio_cfgpin(S3C2410_GPE4,S3C2410_GPE4_I2SSDO); //GPE 4: I2SSDO

 s3c2410_gpio_pullup(S3C2410_GPE4,0);

 local_irq_restore(flags);

 

 printk("driver: cz_uda1341_init local_irq_restore ok\n");

 //init_s3c2410_iis_bus

 __raw_writel(0, piis_regs_base + S3C2410_IISPSR);

 __raw_writel(0, piis_regs_base + S3C2410_IISCON);

 __raw_writel(0, piis_regs_base + S3C2410_IISMOD);

 __raw_writel(0, piis_regs_base + S3C2410_IISFCON);

 printk("driver: cz_uda1341_init __raw_writel ok\n");

 //init_uda1341

 local_irq_save(flags);

 s3c2410_gpio_setpin(S3C2410_GPB2,1);//L3MODE=1

 s3c2410_gpio_setpin(S3C2410_GPB4,1);//L3CLOCK=1

 local_irq_restore(flags);

 //uda1341 chip address is : 000101xx

 //xx = 00 means DATA0 mode;   xx = 01 means DATA1 mode;

 //xx = 10 means STATUS mode; xx = 11 means not used;

 //STATUS mode selected

 czuda1341_l3_address(UDA1341_REG_STATUS);//0x14+2 = 0x16 = 000101 10

 //0x40 = 0100 0000, STATUS control 1/2

 czuda1341_l3_data(0x40 | STAT0_SC_384FS | STAT0_IF_MSB|STAT0_DC_FILTER); // reset; 384fs; MSB-justified; DC-filtering

 //0x80 = 1000 0000, STATUS control 2/2

 czuda1341_l3_data(STAT1 | STAT1_ADC_ON | STAT1_DAC_ON);//adc on; dac on

    //DATA0 mode selected

 czuda1341_l3_address(UDA1341_REG_DATA0);//0x14+0 = 000101 00

 //DATA0-> bit7:bit6=00

 czuda1341_l3_data(DATA0 |DATA0_VOLUME(0x0)); // maximum volume

 //DATA1-> bit7:bit6=01

 czuda1341_l3_data(DATA1 |DATA1_BASS(0)| DATA1_TREBLE(0));//BB = 0; TR = 0

 //DATA2-> bit7:bit6=10

 czuda1341_l3_data((DATA2 |DATA2_DEEMP_NONE) &~(DATA2_MUTE));//DE = 0; MT = 0, no mute

 //EXTADDR:0xc0=11000  000, means extended address(EA) mode selected

 //EXT2:2=0  010, means MS2:MS1:MS0:MM1:MM0 registers  selected

 czuda1341_l3_data(EXTADDR(EXT2));

 //EXTDATA:0xe0=111  00000, means extended data(ED) mode selected

 //EXT2_MIC_GAIN(0x6)=0x6<<2=0110<<2=0  110  00, means MS2:MS1:MS0=110, means MIC AMPLIFIER GAIN = +27dB

 //EXT2_MIXMODE_CH1=01, means MM1:MM0=01, means input channel 1 select(input channel 2 off) 

 czuda1341_l3_data(EXTDATA(EXT2_MIC_GAIN(0x6)) | EXT2_MIXMODE_CH1);

 printk("driver: cz_uda1341_init czuda1341_l3_data ok\n");

 audio_dev_dsp = register_sound_dsp(&smdk2410_audio_fops, -1);

 audio_dev_mixer = register_sound_mixer(&smdk2410_mixer_fops, -1);

 printk("driver: cz_uda1341_init audio_dev_mixer ok\n");

#if 0

 major = register_chrdev(0, "czuda1341", &czuda1341_fops);

 pczuda1341_cls = class_create(THIS_MODULE, "czuda1341_cls");

 pczuda1341_cls_dev = class_device_create(pczuda1341_cls, NULL, MKDEV(major, 0), NULL, "czuda1341_cls_dev");

#endif

 return 0;

}

static void  cz_uda1341_exit(void) {

 printk("driver: cz_uda1341_exit in ok\n");

 

 unregister_sound_dsp(audio_dev_dsp);

 unregister_sound_mixer(audio_dev_mixer);

 //audio_clear_dma(&output_stream,&s3c2410iis_dma_out);

 //audio_clear_dma(&input_stream,&s3c2410iis_dma_in); /* input */

 

 iounmap(pdma_regs_out_base);

 iounmap(pdma_regs_in_base);

 iounmap(piis_regs_base);

 

 clk_disable(iis_clock);

}

module_init(cz_uda1341_init);

module_exit(cz_uda1341_exit);

MODULE_AUTHOR("chaozang(cz)<zangchao.cn@gmail.com>");

MODULE_DESCRIPTION("TQ2440 uda1341 sound driver");

MODULE_LICENSE("GPL");

----------------------------------------------------test commands----------------------------------------------------------

#cat xxx.wav > /dev/dsp

#cat /dev/dsp > sound.bin

#cat sound.bin > /dev/dsp

-----------------------------------------------------------

Contact: zangchao.cn@gmail.com

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: