i2c的操作在內核中是當做字符設備來操作的,相關初始化在由i2c_dev_init函數來初始化。
並且i2c adapter的驅動通過i2cdev_driver這個通用驅動的attach方法來實現注冊的。
下面具體分析整個過程。
- static int __init i2c_dev_init(void)
- {
- 。。。 。。。
- res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
- if (res)
- goto out;
-
- i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
- if (IS_ERR(i2c_dev_class)) {
- res = PTR_ERR(i2c_dev_class);
- goto out_unreg_chrdev;
- }
-
- res = i2c_add_driver(&i2cdev_driver);
- 。。。 。。。
- }
函數首先調用register_chardev函數向內核注冊主備號為I2C_MAJOR、操作集為i2cdev_fops的字符設備。
register_chrdev函數最終會向系統注冊主設備為I2C_MAJOR,此設備號為0~255的設備。這表示系統最多可以容納256個i2c adapter,adapter的字符操作方法i2cdev_fops如下:
- static const struct file_operations i2cdev_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = i2cdev_read,
- .write = i2cdev_write,
- .unlocked_ioctl = i2cdev_ioctl,
- .open = i2cdev_open,
- .release = i2cdev_release,
- };
當read()、write()、open()、close()、ioctl()等系統調用發生時就會調用到這些函數。
但是i2cdev_fops其實是通用的的操作,應為不同的adapter對應的操作方法肯定有區別所以這裡的fops只是具體adapter操作方法的一層外殼,具體稍後分析。
字符設備注冊完畢後通過class_create()函數初始化一個類i2c_dev_class,這個類稍後需要使用,用於在/dev/i2c-0下自動創建設備,後面分析。
類初始化完畢後,然後調用函數i2c_add_driver函數注冊i2c driver。這裡所說的i2c其實對應的是系統中所有的i2c類設備。
通過i2c driver中的attach_adapter方法來實現將adapter和對應的驅動綁定。
- static struct i2c_driver i2cdev_driver = {
- .driver = {
- .name = "dev_driver",
- },
- .attach_adapter = i2cdev_attach_adapter,
- .detach_adapter = i2cdev_detach_adapter,
- };
此處注意attach_adapter這個方法,/dev目錄下的設備創建是在通過執行此函數實現的。
下面具體分析i2c_add_driver注冊i2cdev_driver的過程
2.i2c_add_driver
i2c_add_driver函數只是對i2c_register_driver做了簡單的封裝,下面直接分析i2c_register_driver
- int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
- {
- int res;
-
- /* Can't register until after driver model init */
- if (unlikely(WARN_ON(!i2c_bus_type.p))){
- printk("Can't register until after driver model init\n");
- return -EAGAIN;
- }
-
- /* add the driver to the list of i2c drivers in the driver core */
- driver->driver.owner = owner;
- driver->driver.bus = &i2c_bus_type;
-
- /* When registration returns, the driver core
- * will have called probe() for all matching-but-unbound devices.
- */
- res = driver_register(&driver->driver);
- if (res)
- return res;
-
- pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
-
- INIT_LIST_HEAD(&driver->clients);
- /* Walk the adapters that are already present */
- mutex_lock(&core_lock);
- bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
- mutex_unlock(&core_lock);
-
- return 0;
- }
函數通過
- driver->driver.bus = &i2c_bus_type;
可見此驅動通過函數driver_register()之後 同樣會被注冊到了i2c總線上。
值得一提的是此處i2cdev_driver中的attach_adapter的執行機會很大,通過bus_for_each_dev()函數
- bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
會嘗試和i2c總線上所有的dev進行一次匹配,只要獲取的dev為adapter時,就可執行後續操作。
此處的bus_for_each_dev函數主要功能就是循環查詢一遍i2c總線上所有的dev,包括adapter device和client device。
然後依次將dev和driver作為__process_new_driver的參數並執行__process_new_driver函數,但是只有adapter device
才會執行後續的操作,否則返回繼續輪詢i2c總線上的dev。
- static int __process_new_driver(struct device *dev, void *data)
- {
- if (dev->type != &i2c_adapter_type)
- return 0;
- return i2c_do_add_adapter(data, to_i2c_adapter(dev));
- }
可以發現__process_new_driver函數首先判斷的是dev的類型,假如是adapter類型才會繼續執行後面的代碼,假如不是則立即返回繼續摘取下個dev然後循環執行__process_new_driver。因為對我們來說,我們只需要注冊adapter的驅動就可以了,i2c的所有操作是通過主機來完成的,從機只是被動接受。由於之前已經通過i2cadd_numbered_adapter()注冊過adapter到總線i2c_bus_type,所以此處有機會執行後面的i2c_do_add_adapter函數。
- static int i2c_do_add_adapter(struct i2c_driver *driver,
- struct i2c_adapter *adap)
- {
- /* Detect supported devices on that bus, and instantiate them */
- i2c_detect(adap, driver);
-
- /* Let legacy drivers scan this bus for matching devices */
- if (driver->attach_adapter) {
- /* We ignore the return code; if it fails, too bad */
- driver->attach_adapter(adap);
- }
- return 0;
- }
可以發現在i2c_do_add_adapter函數主要執行的是i2c_dectect和driver->attach_adapter。
由於此處驅動並未初始化driver->detect,所以i2c_detect函數未執行有效操作就會退出。
接著通過傳統方式執行driver->attach_adapter方法。
- tatic int i2cdev_attach_adapter(struct i2c_adapter *adap)
- {
- struct i2c_dev *i2c_dev;
- int res;
-
- i2c_dev = get_free_i2c_dev(adap);
- if (IS_ERR(i2c_dev))
- return PTR_ERR(i2c_dev);
-
- /* register this i2c device with the driver core */
- i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
- MKDEV(I2C_MAJOR, adap->nr), NULL,
- "i2c-%d", adap->nr);
- if (IS_ERR(i2c_dev->dev)) {
- res = PTR_ERR(i2c_dev->dev);
- goto error;
- }
- res = device_create_file(i2c_dev->dev, &dev_attr_name);
- if (res)
- goto error_destroy;
-
- pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
- adap->name, adap->nr);
- return 0;
- error_destroy:
- device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
- error:
- return_i2c_dev(i2c_dev);
- return res;
- }
可見attach_adapter函數的作用就是調用device_create()函數 通過之前class_create的類信息在/dev下自動創建設備文件。
並且此設備的設備號是由固定的主設備號I2C_MAJOR 和 從設備號組成的,從設備號取的就是adapter的nr,此處為0。
並且可以推斷出系統最多可以容納0~255 總共256個i2c adapter。
到此i2c部分的初始化就完成了,可以通過read write來操作設備了。
補充:上面說的新方法好像在驅動裡面就會detect client,然後把所有檢測到的client放到一條鏈表裡。
相關閱讀:
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