新聞中心

ARM-Linux s3c2440 之I2C分析

作者: 時間:2016-11-19 來源:網(wǎng)絡(luò) 收藏
內(nèi)核版本linux-2.6.30.4
I2C在Linux中是Bus下的一個子系統(tǒng). 它由客戶驅(qū)動(client driver),i2c-core核心,i2c適配器驅(qū)動(adapter driver) ,算法aglorithm組成。s3c2440中有兩個i2c現(xiàn)適配器.作為platform_device設(shè)備在系統(tǒng)啟動先時被注冊和添加。下面我們分析i2c(設(shè)備,驅(qū)動,總線)的實(shí)現(xiàn)過程.
//填充設(shè)備資源
//struct resource結(jié)構(gòu)體描述了掛接在cpu總線上的設(shè)備實(shí)體資源
//.start:i2c寄存器起始地址; .end:i2c寄存器結(jié)束地址; .flag:描述設(shè)備實(shí)體的共性和特性標(biāo)志
  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適配器初始化時數(shù)據(jù)
  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://2s4d.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數(shù)據(jù)
  12. }
//定義好上面相關(guān)結(jié)構(gòu)后,在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()時被調(diào)用,但值得注意的是i2c適配器并沒有被初始化,因?yàn)檫€沒有驅(qū)動!
通過下面可以知道platform_device_register()和device_register()的區(qū)別:
  1. platform_add_devices()-->platform_device_register()-->
  2. platform_device_add()-->device-->add()
platfrom_bus_init()時也將添加一個名叫platform的設(shè)備(struct device platform_bus):
  1. plat_form_bus_init()-->device_register()-->device_register()
  2. -->device-->add()
但這個設(shè)備是虛擬的,所有platform_device_add()后的設(shè)備都是在/devices/platform/下
因?yàn)樗衟laform_device 的父母親都是platform_bus,是在platform_device_add()中
  1. if(!pdev->dev.parent)
  2. pdev->dev.parent=&platform_bus;
我想這也就是platform_device_register()和device_register()區(qū)別吧
在reset_init()-->kernel_init()-->do_basic_setup()
-->driver_init()-->platform_bus_init()完成platform_bus總線的注冊
但是現(xiàn)在i2c適配器并沒有和驅(qū)動綁上,因?yàn)榈较惮F(xiàn)在為止驅(qū)動還沒有出現(xiàn)呢(初始化)
只有做好前面一些的準(zhǔn)備功夫,i2c適配器驅(qū)動才能初始化,這個是需要按照順序來的。
s3c2440-i2c適配器驅(qū)動的初始化在drivers/i2c/bus/i2c-s3c2410.c中實(shí)現(xiàn)
并且作為platform_driver注冊。
//填充driver結(jié)構(gòu)并完成相應(yīng)probe,remove等函數(shù)
  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);

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


關(guān)鍵詞: ARMLinuxs3c2440I2C分

評論


技術(shù)專區(qū)

關(guān)閉