Linux I2C驱动分析 S3C6410


看Linux I2C驱动也有一段时间了,把自己理解的内容写下来,一是下次用的时候便于快速捡起来,二梳理IIC驱动复杂框架,三欢迎大家给我指正,共同进步。

Linux中I2C体系结构如下图所示(图片来源于网络)。图中用分割线分成了三个层次:用户空间(也就是应用程序),内核(也就是驱动部分)和硬件(也就是实际物理设备,这里就是6410中的i2c控制器和at24xx)。这个够清晰了吧?我们主要研究的是中间那一层。

    

中间一层又分为i2c设备驱动、i2c-core层、i2c控制器驱动三部分。其中i2c-core提供了i2c设备驱动和控制器驱动的注册、注销方法。其上三部分Driver、Client、i2c-dev用来描述i2c设备(如at24xx)及其驱动,下面Algorithm、Adapter、及Adapter specific code 用来描述i2c控制器驱动。

以s3c6410 linux 2.6.26下iic器件 at24xx驱动为例进行分析,主要包含以下文件。

1、i2c-core.c 实现了I2C的核心功能。

2、i2c-dev.c  实现了I2C控制器设备文件的功能。

3、At24.c    实现了at24xx系列IIC接口设备驱动。

4、i2c-s3c2410.c  实现了6410 IIC控制器驱动。

5、Algos     实现了一些IIC控制器的algorithm

6、mach-mini6410.c  定义并注册了I2C平台设备。


我们根据系统加载有关I2C模块的顺序进行分析。

1、运行   MACHINE_START .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。

  1. MACHINE_START(MINI6410, "MINI6410")  
  2. /* Maintainer: Ben Dooks <ben-linux@fluff.org> */  
  3. .boot_params    = S3C64XX_PA_SDRAM + 0x100,  
  4.   
  5. .init_irq   = s3c6410_init_irq,  
  6. .map_io  = mini6410_map_io,  
  7. .init_machine   = mini6410_machine_init,  
  8. .timer   = &s3c24xx_timer,  
  9. MACHINE_END  
 
  1. 再看看 mini6410_machine_init(void) 中和 i2c 有关的部分。   
 
  1. static void __init mini6410_machine_init(void)   
 
  1. {  
  2.     u32 cs1;  
  3.   
  4.     s3c_i2c0_set_platdata(NULL);  
  5. #ifdef CONFIG_S3C_DEV_I2C1   
  6.     s3c_i2c1_set_platdata(NULL);  
  7. #endif   
  8.          ...   
 
  1. ...   
 
  1. if (ARRAY_SIZE(i2c_devs0)) {  
  2.     i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));  
  3. }  
  4. if (ARRAY_SIZE(i2c_devs1)) {  
  5.     i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));  
  6. }  
  7.   
  8.        ...  
 
  1.         ...  
  2.   
  3.     platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));  
  4.   
  5. #ifdef CONFIG_VIDEO_SAMSUNG   
  6.     create_proc_read_entry("videomem", 0, NULL, s3c_media_read_proc, NULL);  
  7. #endif   
  1. platform_add_devices  添加了平台设备  
 
  1. static struct platform_device *mini6410_devices[] __initdata = {  
  2. #ifdef CONFIG_MINI6410_SD_CH0   
  3. <span style="white-space:pre">    </span>&s3c_device_hsmmc0,  
  4. #endif   
  5. #ifdef CONFIG_MINI6410_SD_CH1   
  6. <span style="white-space:pre">    </span>&s3c_device_hsmmc1,  
  7. #endif   
  8. <span style="white-space:pre">    </span>&s3c_device_i2c0,  
  9. #ifdef CONFIG_S3C_DEV_I2C1   
  10. <span style="white-space:pre">    </span>&s3c_device_i2c1,  
  11. #endif

其中   

  1. struct platform_device s3c_device_i2c0 = {  
  2. <span style="white-space:pre">    </span>.name<span style="white-space:pre">      </span>  = "s3c2410-i2c",  //注意这里设备名称  s3c2410-i2c   
  3. #ifdef CONFIG_S3C_DEV_I2C1   
  4. <span style="white-space:pre">    </span>.id<span style="white-space:pre">        </span>  = 0,  
  5. #else   
  6. <span style="white-space:pre">    </span>.id<span style="white-space:pre">        </span>  = -1,  
  7. #endif   
  8. <span style="white-space:pre">    </span>.num_resources<span style="white-space:pre"> </span>  = ARRAY_SIZE(s3c_i2c_resource),  
  9. <span style="white-space:pre">    </span>.resource<span style="white-space:pre">  </span>  = s3c_i2c_resource,  
  10. };  

2、 看到系统注册了platform_device 我们会想到  platform_driver  在何处注册。

在 i2c-s3c2410.c 中我们看到了 i2c 平台驱动注册。

  1. static struct platform_driver s3c24xx_i2c_driver = {  
  2.     .probe      = s3c24xx_i2c_probe,  
  3.     .remove     = s3c24xx_i2c_remove,  
  4.     .id_table   = s3c24xx_driver_ids,  //此处需要注意   
  5.     .driver     = {  
  6.         .owner  = THIS_MODULE,  
  7.         .name   = "s3c-i2c",     //注意这里驱动名称 s3c-i2c  和 上面设备名称 s3c2410-i2c 不一致  why?    
  8.         .pm = S3C24XX_DEV_PM_OPS,  
  9.     },  
  10. };  
  11.   
  12. static int __init i2c_adap_s3c_init(void)  
  13. {  
  14.     return platform_driver_register(&s3c24xx_i2c_driver);  
  15. }  

下一页主要分析

  1. 驱动名称 s3c-i2c  和 上面设备名称 s3c2410-i2c 不一致  why?   20100730 --22:51  
  • 1
  • 2
  • 3
  • 下一页

相关内容