歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

I2C子系統之platform_driver初始化——I2C_adap_s3c_init()

在完成platform_device的添加之後,i2c子系統將進行platform_driver的注冊過程。

platform_driver的注冊通過調用初始化函數i2c_adapter_s3c_init函數來完成。

i2c_adap_s3c_init()函數體如下:

  1. static int __init i2c_adap_s3c_init(void)  
  2. {  
  3.     return platform_driver_register(&s3c24xx_i2c_driver);  
  4. }  
platform_driver_register(&s3c24xx_i2c_driver),將完成向platform_bus總線注冊platform_driver類型驅動

s3c24xx_i2c_driver的工作。s3c24xx_i2c_driver如下:

  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",  
  8.         .pm = S3C24XX_DEV_PM_OPS,  
  9.     },  
  10. };  
id_table被初始化為s3c24xx_driver_ids:
  1. static struct platform_device_id s3c24xx_driver_ids[] = {  
  2.     {  
  3.         .name       = "s3c2410-i2c",  
  4.         .driver_data    = TYPE_S3C2410,  
  5.     }, {  
  6.         .name       = "s3c2440-i2c",  
  7.         .driver_data    = TYPE_S3C2440,  
  8.     }, { },  
  9. };  

platform_driver在注冊到platform_bus總線的過程中會嘗試將已注冊的platform_driver

與已注冊到platform_bus上的所有platform_device進行配對。

platform_bus總線的相關操作如下:

  1. struct bus_type platform_bus_type = {  
  2.     .name       = "platform",  
  3.     .dev_attrs  = platform_dev_attrs,  
  4.     .match      = platform_match,  
  5.     .uevent     = platform_uevent,  
  6.     .pm     = &platform_dev_pm_ops,  
  7. };  
配對過程通過調用總線的match方法實現,即platform_match函數。如下:
  1. static int platform_match(struct device *dev, struct device_driver *drv)  
  2. {  
  3.     struct platform_device *pdev = to_platform_device(dev);  
  4.     struct platform_driver *pdrv = to_platform_driver(drv);  
  5.   
  6.     /* Attempt an OF style match first */  
  7.     if (of_driver_match_device(dev, drv))  
  8.         return 1;  
  9.   
  10.     /* Then try to match against the id table */  
  11.     if (pdrv->id_table)  
  12.         return platform_match_id(pdrv->id_table, pdev) != NULL;  
  13.   
  14.     /* fall-back to driver name match */  
  15.     return (strcmp(pdev->name, drv->name) == 0);  
  16. }  
可以看到函數中有
  1. if (pdrv->id_table)  
  2.         return platform_match_id(pdrv->id_table, pdev) != NULL;  
相關語句。

此處就是根據platfor_device和platform_driver的名字來實現配對。但是platform_driver有好幾個名字

可以選擇,通過id_table來實現配對。執行到此處,之前已注冊到platform_bus的platform_device

型設備s3c_devicei2c0和現在剛注冊到platform_bus總線的platfor_drver型驅動s3c24xx_i2c_drive將

實現配對成功。

成功配對之後將嘗試進行probe

  1. static int really_probe(struct device *dev, struct device_driver *drv)  
  2. {       
  3.         。。。 。。。  
  4.   
  5.     if (dev->bus->probe) {  
  6.         ret = dev->bus->probe(dev);  
  7.         if (ret)  
  8.             goto probe_failed;  
  9.     } else if (drv->probe) {  
  10.         ret = drv->probe(dev);  
  11.         if (ret)  
  12.             goto probe_failed;  
  13.     }  
  14.         。。。 。。。  
  15. }   
有上述代碼可知,成功配對後首先調用的是總線的probe,假如總線未初始化probe方法才會去

調用驅動中的probe,即platform_driver.drv->probe,而platform_bus本身未初始化probe方法,

所以此處調用驅動的probe方法,驅動的probe在注冊過程中已被初始化

  1. int platform_driver_register(struct platform_driver *drv)  
  2. {  
  3.     drv->driver.bus = &platform_bus_type;  
  4.     if (drv->probe)  
  5.         drv->driver.probe = platform_drv_probe;  
  6.     if (drv->remove)  
  7.         drv->driver.remove = platform_drv_remove;  
  8.     if (drv->shutdown)  
  9.         drv->driver.shutdown = platform_drv_shutdown;  
  10.   
  11.     return driver_register(&drv->driver);  
  12. }  
即直接調用函數platform_drv_probe,函數如下:
  1. static int platform_drv_probe(struct device *_dev)  
  2. {  
  3.     struct platform_driver *drv = to_platform_driver(_dev->driver);  
  4.     struct platform_device *dev = to_platform_device(_dev);  
  5.   
  6.     return drv->probe(dev);  
  7. }  
函數的工作很簡單,即通過_dev->driver找到包含它的platform_driver型驅動,然後再

調用此驅動的probe方法,即s3c24xx_i2c_probe函數。

probe函數的功能如下:

1.首先創建struct s3c24xx_i2c  *i2c。

i2c相關數據的初始化來源於s3c2_device_i2c0.dev.platdata。

2.通過i2c->adap.algo    = &s3c24xx_i2c_algorithm;初始化algo方法。

在write系統調用的時候會調用到s3c24xx_i2c_algorithm函數。

3.init_waitqueue_head(&i2c->wait); 初始化一個等待隊列

4.s3c24xx_i2c_init (i2c);初始化i2c控制器,主要是對s3c24xx的i2c控制

寄存器進行一些操作,比如配置s3c2440i/o功能,設置從機地址,以及

設置i2c時鐘頻率等相關操作。時鐘頻率的設置參見博文。

5.request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
              dev_name(&pdev->dev), i2c);
申請中斷,內核中的i2c讀寫是通過中斷來實現的,具體稍後分析

6.i2c_add_numbered_adapter(&i2c->adap);最後向系統注冊一個i2c adapter

這裡需要著重注意第2、5、6點。

下面先分析第6點。第2、5點待到後面讀寫at24c02的時候再分析。

相關閱讀:

I2C子系統之at24c02讀寫測試 http://www.linuxidc.com/Linux/2012-08/68256.htm
I2C子系統之ioctl()  http://www.linuxidc.com/Linux/2012-08/68257.htm
I2C子系統之at24c02簡介 http://www.linuxidc.com/Linux/2012-08/68258.htm
I2C子系統之總結 http://www.linuxidc.com/Linux/2012-08/68259.htm
I2C子系統之內核中I2C子系統的結構 http://www.linuxidc.com/Linux/2012-08/68260.htm
I2C子系統之I2C bus初始化——I2C_init() http://www.linuxidc.com/Linux/2012-08/68261.htm
I2C子系統之platfor_device初始化——smdk2440_machine_init() http://www.linuxidc.com/Linux/2012-08/68262.htm
I2C子系統之platform_driver初始化——I2C_adap_s3c_init() http://www.linuxidc.com/Linux/2012-08/68263.htm
I2C子系統之I2C總線時鐘頻率設置 http://www.linuxidc.com/Linux/2012-08/68264.htm
I2C子系統之adapter device和client device注冊——I2C_add_number_adapter() http://www.linuxidc.com/Linux/2012-08/68265.htm
I2C子系統之__I2C_first_dynamic_bus_num變量的相關分析 http://www.linuxidc.com/Linux/2012-08/68266.htm
I2C子系統之 adapter driver注冊——I2C_dev_init() http://www.linuxidc.com/Linux/2012-08/68267.htm
I2C子系統之write() http://www.linuxidc.com/Linux/2012-08/68268.htm

Copyright © Linux教程網 All Rights Reserved