新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM-Linux s3c2440 之I2C分析

        ARM-Linux s3c2440 之I2C分析

        作者: 時間:2016-11-19 來源:網絡 收藏
        內核版本linux-2.6.30.4
        I2C在Linux中是Bus下的一個子系統. 它由客戶驅動(client driver),i2c-core核心,i2c適配器驅動(adapter driver) ,算法aglorithm組成。s3c2440中有兩個i2c現適配器.作為platform_device設備在系統啟動先時被注冊和添加。下面我們分析i2c(設備,驅動,總線)的實現過程.
        //填充設備資源
        //struct resource結構體描述了掛接在cpu總線上的設備實體資源
        //.start:i2c寄存器起始地址; .end:i2c寄存器結束地址; .flag:描述設備實體的共性和特性標志
        1. staticstructresources3c_i2c_resource[]={
        2. [0]={//i2c-0
        3. .start=S3C_PA_IIC,
        4. .end=S3C_PA_IIC+SZ_4K-1,
        5. .flags=IORESOURCE_MEM,
        6. },
        7. [1]={//i2c-1
        8. .start=IRQ_IIC,
        9. .end=IRQ_IIC,
        10. .flags=IORESOURCE_IRQ,
        11. },
        12. };
        /i2c適配器初始化時數據
        1. staticstructs3c2410_platform_i2cdefault_i2c_data0__initdata={
        2. .flags=0,
        3. .slave_addr=0x10,
        4. .frequency=100*1000,
        5. .sda_delay=100,
        6. };

        //聲明i2c適配器為platform_device

        本文引用地址:http://www.104case.com/article/201611/318136.htm

        1. structplatform_devices3c_device_i2c0={
        2. .name="s3c2410-i2c",
        3. #ifdefCONFIG_S3C_DEV_I2C1
        4. .id=0,
        5. #else
        6. .id=-1,
        7. #endif
        8. .num_resources=ARRAY_SIZE(s3c_i2c_resource),
        9. .resource=s3c_i2c_resource,
        10. };
        11. staticstructs3c2410_platform_i2cdefault_i2c_data0__initdata={
        12. .flags=0,
        13. .slave_addr=0x10,
        14. .frequency=100*1000,
        15. .sda_delay=100,
        16. };

        //添加i2c適配器:
        1. staticstructplatform_device*smdk2440_devices[]__initdata={
        2. ...
        3. &s3c_device_i2c0,
        4. ...
        5. };
        //添加plat_from_data
        1. void__inits3c_i2c0_set_platdata(structs3c2410_platform_i2c*pd)
        2. {
        3. structs3c2410_platform_i2c*npd;
        4. if(!pd)
        5. pd=&default_i2c_data0;
        6. npd=kmemdup(pd,sizeof(structs3c2410_platform_i2c),GFP_KERNEL);
        7. if(!npd)
        8. printk(KERN_ERR"%s:nomemoryforplatformdatan",__func__);
        9. elseif(!npd->cfg_gpio)
        10. npd->cfg_gpio=s3c_i2c0_cfg_gpio;//i2c引腳配置
        11. s3c_device_i2c0.dev.platform_data=npd;//掛接plat_form_data數據
        12. }
        //定義好上面相關結構后,在smdk2440_machine_init()中被注冊和添加成platform_device
        1. staticvoid__initsmdk2440_machine_init(void)
        2. {
        3. s3c24xx_fb_set_platdata(&smdk2440_fb_info);
        4. s3c_i2c0_set_platdata(NULL);
        5. ...
        6. //注冊和添加platform_device
        7. platform_add_devices(smdk2440_devices,ARRAY_SIZE(smdk2440_devices));
        8. ...
        9. }
        其中 smdk2440_machine_init在被賦值在MACHINE_START中
        在start_kernel()-->setup_arch()時被調用,但值得注意的是i2c適配器并沒有被初始化,因為還沒有驅動!
        通過下面可以知道platform_device_register()和device_register()的區別:
        1. platform_add_devices()-->platform_device_register()-->
        2. platform_device_add()-->device-->add()
        platfrom_bus_init()時也將添加一個名叫platform的設備(struct device platform_bus):
        1. plat_form_bus_init()-->device_register()-->device_register()
        2. -->device-->add()
        但這個設備是虛擬的,所有platform_device_add()后的設備都是在/devices/platform/下
        因為所有plaform_device 的父母親都是platform_bus,是在platform_device_add()中
        1. if(!pdev->dev.parent)
        2. pdev->dev.parent=&platform_bus;
        我想這也就是platform_device_register()和device_register()區別吧
        在reset_init()-->kernel_init()-->do_basic_setup()
        -->driver_init()-->platform_bus_init()完成platform_bus總線的注冊
        但是現在i2c適配器并沒有和驅動綁上,因為到系現在為止驅動還沒有出現呢(初始化)
        只有做好前面一些的準備功夫,i2c適配器驅動才能初始化,這個是需要按照順序來的。
        s3c2440-i2c適配器驅動的初始化在drivers/i2c/bus/i2c-s3c2410.c中實現
        并且作為platform_driver注冊。
        //填充driver結構并完成相應probe,remove等函數
        1. staticstructplatform_drivers3c2440_i2c_driver={
        2. .probe=s3c24xx_i2c_probe,
        3. .remove=s3c24xx_i2c_remove,
        4. .suspend_late=s3c24xx_i2c_suspend_late,
        5. .resume=s3c24xx_i2c_resume,
        6. .driver={
        7. .owner=THIS_MODULE,
        8. .name="s3c2440-i2c",//
        9. },
        10. };

        //初始化并注冊platform_driver

        1. staticint__initi2c_adap_s3c_init(void)
        2. {
        3. intret;
        4. ret=platform_driver_register(&s3c2410_i2c_driver);//
        5. if(ret==0){
        6. printk("registers3c2440_i2c_driver.....n");
        7. ret=platform_driver_register(&s3c2440_i2c_driver);
        8. if(ret)
        9. {
        10. printk("registers3c2410_i2c_driver.....n");
        11. platform_driver_unregister(&s3c2410_i2c_driver);
        12. }
        13. }
        14. returnret;
        15. }
        16. subsys_initcall(i2c_adap_s3c_init);

        這樣適配器就和驅動綁定上了,過程是這樣的:
        1. platform_driver_register()-->driver_register()-->bus_add_driver()-->driver_attach()
        2. __driver_attach()-->driver_probe_device()-->s3c24xx_i2c_probe()
        并且在s3c24xx_i2c_probe()的時候調用
        1. i2c_add_numbered_adapter(&i2c->adap);
        最后添加自己為i2c總線的適配器。這樣分析過程也就結束了。


        關鍵詞: ARMLinuxs3c2440I2C分

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 嘉义市| 儋州市| 牙克石市| 浮山县| 耿马| 顺平县| 团风县| 玉屏| 长春市| 兴义市| 房产| 顺平县| 黎城县| 西乌珠穆沁旗| 玉龙| 措美县| 正宁县| 桂平市| 仙游县| 蒙阴县| 灌云县| 噶尔县| 曲阜市| 漳浦县| 嘉荫县| 积石山| 醴陵市| 青州市| 巩留县| 定陶县| 荔波县| 平湖市| 洱源县| 郎溪县| 陆川县| 永仁县| 彭水| 岳普湖县| 都昌县| 利辛县| 万年县|