ARM-Linux s3c2440 之I2C分析
I2C在Linux中是Bus下的一個(gè)子系統(tǒng). 它由客戶(hù)驅(qū)動(dòng)(client driver),i2c-core核心,i2c適配器驅(qū)動(dòng)(adapter driver) ,算法aglorithm組成。s3c2440中有兩個(gè)i2c現(xiàn)適配器.作為platform_device設(shè)備在系統(tǒng)啟動(dòng)先時(shí)被注冊(cè)和添加。下面我們分析i2c(設(shè)備,驅(qū)動(dòng),總線(xiàn))的實(shí)現(xiàn)過(guò)程.
//填充設(shè)備資源
//struct resource結(jié)構(gòu)體描述了掛接在cpu總線(xiàn)上的設(shè)備實(shí)體資源
//.start:i2c寄存器起始地址; .end:i2c寄存器結(jié)束地址; .flag:描述設(shè)備實(shí)體的共性和特性標(biāo)志
- staticstructresources3c_i2c_resource[]={
- [0]={//i2c-0
- .start=S3C_PA_IIC,
- .end=S3C_PA_IIC+SZ_4K-1,
- .flags=IORESOURCE_MEM,
- },
- [1]={//i2c-1
- .start=IRQ_IIC,
- .end=IRQ_IIC,
- .flags=IORESOURCE_IRQ,
- },
- };
- staticstructs3c2410_platform_i2cdefault_i2c_data0__initdata={
- .flags=0,
- .slave_addr=0x10,
- .frequency=100*1000,
- .sda_delay=100,
- };
//聲明i2c適配器為platform_device
本文引用地址:http://www.ex-cimer.com/article/201611/318136.htm- structplatform_devices3c_device_i2c0={
- .name="s3c2410-i2c",
- #ifdefCONFIG_S3C_DEV_I2C1
- .id=0,
- #else
- .id=-1,
- #endif
- .num_resources=ARRAY_SIZE(s3c_i2c_resource),
- .resource=s3c_i2c_resource,
- };
- staticstructs3c2410_platform_i2cdefault_i2c_data0__initdata={
- .flags=0,
- .slave_addr=0x10,
- .frequency=100*1000,
- .sda_delay=100,
- };
- staticstructplatform_device*smdk2440_devices[]__initdata={
- ...
- &s3c_device_i2c0,
- ...
- };
- void__inits3c_i2c0_set_platdata(structs3c2410_platform_i2c*pd)
- {
- structs3c2410_platform_i2c*npd;
- if(!pd)
- pd=&default_i2c_data0;
- npd=kmemdup(pd,sizeof(structs3c2410_platform_i2c),GFP_KERNEL);
- if(!npd)
- printk(KERN_ERR"%s:nomemoryforplatformdatan",__func__);
- elseif(!npd->cfg_gpio)
- npd->cfg_gpio=s3c_i2c0_cfg_gpio;//i2c引腳配置
- s3c_device_i2c0.dev.platform_data=npd;//掛接plat_form_data數(shù)據(jù)
- }
- staticvoid__initsmdk2440_machine_init(void)
- {
- s3c24xx_fb_set_platdata(&smdk2440_fb_info);
- s3c_i2c0_set_platdata(NULL);
- ...
- //注冊(cè)和添加platform_device
- platform_add_devices(smdk2440_devices,ARRAY_SIZE(smdk2440_devices));
- ...
- }
在start_kernel()-->setup_arch()時(shí)被調(diào)用,但值得注意的是i2c適配器并沒(méi)有被初始化,因?yàn)檫€沒(méi)有驅(qū)動(dòng)!
通過(guò)下面可以知道platform_device_register()和device_register()的區(qū)別:
- platform_add_devices()-->platform_device_register()-->
- platform_device_add()-->device-->add()
- plat_form_bus_init()-->device_register()-->device_register()
- -->device-->add()
因?yàn)樗衟laform_device 的父母親都是platform_bus,是在platform_device_add()中
- if(!pdev->dev.parent)
- pdev->dev.parent=&platform_bus;
在reset_init()-->kernel_init()-->do_basic_setup()
-->driver_init()-->platform_bus_init()完成platform_bus總線(xiàn)的注冊(cè)
但是現(xiàn)在i2c適配器并沒(méi)有和驅(qū)動(dòng)綁上,因?yàn)榈较惮F(xiàn)在為止驅(qū)動(dòng)還沒(méi)有出現(xiàn)呢(初始化)
只有做好前面一些的準(zhǔn)備功夫,i2c適配器驅(qū)動(dòng)才能初始化,這個(gè)是需要按照順序來(lái)的。
s3c2440-i2c適配器驅(qū)動(dòng)的初始化在drivers/i2c/bus/i2c-s3c2410.c中實(shí)現(xiàn)
并且作為platform_driver注冊(cè)。
//填充driver結(jié)構(gòu)并完成相應(yīng)probe,remove等函數(shù)
- staticstructplatform_drivers3c2440_i2c_driver={
- .probe=s3c24xx_i2c_probe,
- .remove=s3c24xx_i2c_remove,
- .suspend_late=s3c24xx_i2c_suspend_late,
- .resume=s3c24xx_i2c_resume,
- .driver={
- .owner=THIS_MODULE,
- .name="s3c2440-i2c",//
- },
- };
//初始化并注冊(cè)platform_driver
- staticint__initi2c_adap_s3c_init(void)
- {
- intret;
- ret=platform_driver_register(&s3c2410_i2c_driver);//
- if(ret==0){
- printk("registers3c2440_i2c_driver.....n");
- ret=platform_driver_register(&s3c2440_i2c_driver);
- if(ret)
- {
- printk("registers3c2410_i2c_driver.....n");
- platform_driver_unregister(&s3c2410_i2c_driver);
- }
- }
- returnret;
- }
- subsys_initcall(i2c_adap_s3c_init);
- platform_driver_register()-->driver_register()-->bus_add_driver()-->driver_attach()
- __driver_attach()-->driver_probe_device()-->s3c24xx_i2c_probe()
- i2c_add_numbered_adapter(&i2c->adap);
評(píng)論