s3c2410上iis接口的uda341驱动的学习
时间:11-11
来源:互联网
点击:
首先看uda1341的datasheet,将其中的关键点记录下来:
接口: i2s, 还有一个L3接口,应该是控制其中的dsp(可以在playback模式提供soft mute等功能)
格式: MSB-justified and LSB-justified format compatible,Three combinational data formats with MSB data output and LSB 16, 18 or 20 bits data input. (从时序图上看, MSB和LSB表示大小端, justified可能是指ws信号变化后的第一个位时钟的上升沿采集第一位,原始的i2s格式是第2个位时钟上升沿开始采样的.
速率: 1fs input and output format data rate
引脚: 除去电压,余下的引脚主要就是i2s接口和L3接口的引脚了
uda1341还有个L3接口,由3根线构成:时钟,数据,模式.soc可以通过它来控制uda1341的音频处理功能,还可以获取一些状态信息. 从协议上看很简单,首先mode引脚拉低,送一个8bit的地址,地址的最后两位是一个选择分量,然后拉高mode,发送8bit数据,根据之前的选择分量又表示3种寄存器.这8位数据的高位本身又是个选择分量,datasheet里面定义了各种选择分量时对应值的表格,到时候根据它写个状态机就可以了.
接口: i2s, 还有一个L3接口,应该是控制其中的dsp(可以在playback模式提供soft mute等功能)
格式: MSB-justified and LSB-justified format compatible,Three combinational data formats with MSB data output and LSB 16, 18 or 20 bits data input. (从时序图上看, MSB和LSB表示大小端, justified可能是指ws信号变化后的第一个位时钟的上升沿采集第一位,原始的i2s格式是第2个位时钟上升沿开始采样的.
速率: 1fs input and output format data rate
引脚: 除去电压,余下的引脚主要就是i2s接口和L3接口的引脚了
uda1341还有个L3接口,由3根线构成:时钟,数据,模式.soc可以通过它来控制uda1341的音频处理功能,还可以获取一些状态信息. 从协议上看很简单,首先mode引脚拉低,送一个8bit的地址,地址的最后两位是一个选择分量,然后拉高mode,发送8bit数据,根据之前的选择分量又表示3种寄存器.这8位数据的高位本身又是个选择分量,datasheet里面定义了各种选择分量时对应值的表格,到时候根据它写个状态机就可以了.
uda1341需要了解的东西就这么多了,接下来就可以看实际的驱动了.网上找了个lfc修改过的uda1341驱动,不过仿佛是基于OSS的,先对它进行分析,了解下驱动本身的东西,后文贴的源码我以注释的形式增加了自己的一些理解.
模块初始化:
static int __init s3c2410_uda1341_init(void) {//初始化输入和输出的缓冲区(xxx_stream),这两个struct封装了dma会用到的一些信息.//这个结构后文用到的时候再分析memzero(&input_stream, sizeof(audio_stream_t)); memzero(&output_stream, sizeof(audio_stream_t));//内核提供的驱动注册函数return driver_register(&s3c2410iis_driver);}static struct device_driver s3c2410iis_driver = {.name = "s3c2410-iis",.bus = &platform_bus_type,.probe = s3c2410iis_probe,.remove = s3c2410iis_remove,};
driver_register是sysfs提供的注册驱动的函数,这里表示该驱动是为platform总线上的设备服务的.当总线上有新设备的时候就会调用s3c2410iis_probe来判断该设备是否存在且能使用.
static int s3c2410iis_probe(struct device *dev) {//转换为platform_device,因为该驱动是在platform总线上的,所以device结构肯定是嵌入在platform_device内struct platform_device *pdev = to_platform_device(dev);struct resource *res;unsigned long flags;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL) {printk(KERN_INFO PFX "failed to get memory region resouce\n");return -ENOENT;}//2410iis的虚拟地址,不知道什么时候ioremap过来的iis_base = (void *)S3C24XX_VA_IIS ;if (iis_base == 0) {printk(KERN_INFO PFX "failed to ioremap() region\n");return -EINVAL;}//clk相关的操作,见后文的分析iis_clock = clk_get(dev, "iis");if (iis_clock == NULL) {printk(KERN_INFO PFX "failed to find clock source\n");return -ENOENT;}/**************************modify by lfc*****************************///2.6.11内核有此函数,意思是增加一个引用计数,最新的内核已经没有了clk_use(iis_clock);//使能iis的时钟,因为2410启动时disable了该时钟的//对此处修改有疑问,因为后面的init_s3c2410_iis_bus中又disable了iis的时钟clk_enable(iis_clock);/*****************************end add********************************/local_irq_save(flags);//配置L3接口,i2s接口占用的GPIO引脚/* GPB 4: L3CLOCK, OUTPUT */s3c2410_gpio_cfgpin(S3C2410_GPB4, S3C2410_GPB4_OUTP);s3c2410_gpio_pullup(S3C2410_GPB4,1);... ...local_irq_restore(flags);//初始化2410的iis控制器init_s3c2410_iis_bus();//初始化uda1341init_uda1341();//初始化缓冲用的stream//输出用dma的channel2output_stream.dma_ch = DMA_CH2;if (audio_init_dma(&output_stream, "UDA1341 out")) {audio_clear_dma(&output_stream,&s3c2410iis_dma_out);printk( KERN_WARNING AUDIO_NAME_VERBOSE": unable to get DMA channels\n" );return -EBUSY;}//输入用dma的channel1input_stream.dma_ch = DMA_CH1;if (audio_init_dma(&input_stream, "UDA1341 in")) {audio_clear_dma(&input_stream,&s3c2410iis_dma_in);printk( KERN_
s3c2410iis接口uda341驱 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)