微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > s3c2410上iis接口的uda341驱动的学习

s3c2410上iis接口的uda341驱动的学习

时间:11-11 来源:互联网 点击:

uda1341通过L3接口初始化:

static void init_uda1341(void){/* GPB 4: L3CLOCK *//* GPB 3: L3DATA *//* GPB 2: L3MODE */unsigned long flags;uda1341_volume = 62 - ((DEF_VOLUME * 61) / 100);uda1341_boost = 0;//        uda_sampling = DATA2_DEEMP_NONE;//        uda_sampling &= ~(DATA2_MUTE);local_irq_save(flags);s3c2410_gpio_setpin(S3C2410_GPB2,1);//L3MODE=1s3c2410_gpio_setpin(S3C2410_GPB4,1);//L3CLOCK=1local_irq_restore(flags);uda1341_l3_address(UDA1341_REG_STATUS);uda1341_l3_data(0x40 | STAT0_SC_384FS | STAT0_IF_MSB|STAT0_DC_FILTER); // reset uda1341uda1341_l3_data(STAT1 | STAT1_ADC_ON | STAT1_DAC_ON);uda1341_l3_address(UDA1341_REG_DATA0);uda1341_l3_data(DATA0 |DATA0_VOLUME(0x0)); // maximum volumeuda1341_l3_data(DATA1 |DATA1_BASS(uda1341_boost)| DATA1_TREBLE(0));uda1341_l3_data((DATA2 |DATA2_DEEMP_NONE) &~(DATA2_MUTE));uda1341_l3_data(EXTADDR(EXT2));uda1341_l3_data(EXTDATA(EXT2_MIC_GAIN(0x6)) | EXT2_MIXMODE_CH1);//input channel 1 select(input channel 2 off)}

其中的uda1341_l3_address(),uda1341_l3_data()都是操作的data,clk,mode gpio口的电平,配合udelay延时,来模拟的L3接口协议.传输时调用local_irq_save关了中断的.

probe函数的最后部分是对输入和输出流的初始化,主要就是初始化对应的dma通道.从2410的datasheet中dma部分可知,通道1支持 iis的sdi,通道2支持iis的sdi,sdo.所以这里将通道1用于输入流,通道2用于了输出流.下面是对dma部分的初始化:

static int __init audio_init_dma(audio_stream_t * s, char *desc){int ret ;//2.6.10内核定义的enum,就两个值,表示dma的源是hardware还是memorys3c2410_dmasrc_t source;int hwcfg;unsigned long devaddr;dmach_t channel;int dcon;unsigned int flags = 0;if(s->dma_ch == DMA_CH2){channel = 2;//因为是输出,所以源是内存source = S3C2410_DMASRC_MEM;hwcfg = 3;//2410的iis接口中fifo数据寄存器的物理地址,16bit宽devaddr = 0x55000010;//DCON寄存器的初始值,这里的取值表示://handshake mode,传输完成产生中断,DREQ and DACK are synchronized to PCLK (APB clock)//读写各一字节后释放总线,single service mode,auto reload,dma的请求源是iis sdodcon = 0xa0800000;//?flags = S3C2410_DMAF_AUTOSTART;//配置dma传输中,iis控制器一端的寄存器值//hwcfg=3,表示设备是在APB总线上,且传输过程中地址不递增//看2410datasheet的框图,可以看到iis控制器是在APB总线上//读iis数据fifo的时候是一直读同一个地址s3c2410_dma_devconfig(channel, source, hwcfg, devaddr);//源地址位宽为2个字节,硬件源触发,完成一次传输要产生中断s3c2410_dma_config(channel, 2, dcon);//安装一个回调函数s3c2410_dma_set_buffdone_fn(channel, audio_dmaout_done_callback);//保存一个标志s3c2410_dma_setflags(channel, flags);//请求对应的dma通道,详细内容见后文ret = s3c2410_dma_request(s->dma_ch, &s3c2410iis_dma_out, NULL);s->dma_ok = 1;return ret;}else if(s->dma_ch == DMA_CH1){channel =1;source =S3C2410_DMASRC_HW;hwcfg =3;devaddr = 0x55000010;//表示dma的请求源是i2s sdi,其他类似dcon = 0xa2900000;flags = S3C2410_DMAF_AUTOSTART;s3c2410_dma_devconfig(channel, source, hwcfg, devaddr);s3c2410_dma_config(channel, 2, dcon);s3c2410_dma_set_buffdone_fn(channel, audio_dmain_done_callback);s3c2410_dma_setflags(channel, flags);ret = s3c2410_dma_request(s->dma_ch, &s3c2410iis_dma_in, NULL);s->dma_ok =1;return ret ;}elsereturn 1;}
int s3c2410_dma_devconfig(int channel,s3c2410_dmasrc_t source,int hwcfg,unsigned long devaddr){//系统定义了4个s3c2410_dma_chan_t结构,记录了这4个dma通道的所有信息//此处根据输入参数选择将要配置的通道s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];check_channel(channel);pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",__FUNCTION__, (int)source, hwcfg, devaddr);chan->source = source;//保存源的目的地址,比如0x55000010,表示源就是2410的iis接口的fifo数据寄存器chan->dev_addr = devaddr;switch (source) {case S3C2410_DMASRC_HW:/* source is hardware */pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",__FUNCTION__, devaddr, hwcfg);//源是iis控制器,所以地址固定,在APB总线上dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3);dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr);//目的地址在AHB总线上,地址递增,因为是内存缓冲区dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<1) | (0<0));//add_reg指向dma的目的地址寄存器DIDSTchan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);return 0;case S3C2410_DMASRC_MEM:/* source is memory */pr_debug( "%s: mem source, devaddr=%08lx, hwcfg=%d\n",__FUNCTION__, devaddr, hwcfg);dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<1) | (0<0));dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr);dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3);chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC);return 0;}printk(KERN_ERR "dma%d: invalid source type (%d)\n", channel, source);return -EINVAL;}
int s3c2410_dma_config(dmach_t channel,int xferunit,int dcon){s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];check_channel(channel);switch (xferunit) {case 1://配置源地址的位宽dcon |= S3C2410_DCON_BYTE;break;case 2:dcon |= S3C2410_DCON_HALFWORD;break;case 4:dcon |= S3C2410_DCON_WORD;break;default:pr_debug("%s: bad transfer size %d\n", __FUNCTION__, xferunit);return -EINVAL;}//设置dma请求源是硬件,如iis sdi等dcon |= S3C2410_DCON_HWTRIG;//设置一次dma传输结束后触发中断dcon |= S3C2410_DCON_INTREQ;chan->dcon = dcon;chan->xfer_unit = xferunit;return 0;}
int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,void *dev){s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];unsigned long flags;int err;check_channel(channel);local_irq_save(flags);dbg_showchan(chan);//是否已经有人申请过该通道if (chan->in_use) {if (client != chan->client) {printk(KERN_ERR "dma%d: already in use\n", channel);local_irq_restore(flags);return -EBUSY;} else {printk(KERN_ERR "dma%d: client already has channel\n", channel);}}chan->client = client;chan->in_use = 1;if (!chan->irq_claimed) {//安装对应dma通道的中断,可以看出每个dma通道共用了同一个中断服务程序s3c2410_dma_irqerr = request_irq(chan->irq, s3c2410_dma_irq, SA_INTERRUPT,client->name, (void *)chan);if (err) {chan->in_use = 0;local_irq_restore(flags);printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",client->name, chan->irq, chan->number);return err;}chan->irq_claimed = 1;chan->irq_enabled = 1;}local_irq_restore(flags);return 0;}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top