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

Linux IIC框架

IIC的框架結構和SPI是類似的,它們都擁有總線驅動層(IIC主控制器驅動層),核心層和從設備驅動層。本節主要介紹IIC主控制器的注冊以及從設備的注冊過程。首先要介紹描述IIC主控制器的結構struct i2c_adapter和描述IIC從設備的結構struct i2c_client

struct i2c_adapter的定義如下:

  1. struct i2c_adapter {  
  2.     struct module *owner;  /*所屬模塊*/  
  3.     unsigned int id;        /*algorithm的類型*/  
  4.     unsigned int class;     /* classes to allow probing for */  
  5.     const struct i2c_algorithm *algo; /*總線通信方法*/  
  6.     void *algo_data;       /*algorithm的數據*/  
  7.   
  8.     /* --- administration stuff. */  
  9.     /*從設備注冊時調用*/  
  10.     int (*client_register)(struct i2c_client *) __deprecated;  
  11.     /*從設備注銷時調用*/  
  12.     int (*client_unregister)(struct i2c_client *) __deprecated;  
  13.   
  14.     /* data fields that are valid for all devices   */  
  15.     u8 level;           /* nesting level for lockdep */  
  16.     struct mutex bus_lock;  
  17.     struct mutex clist_lock;  
  18.   
  19.     int timeout;            /* in jiffies */  
  20.     int retries;           /*重試次數*/  
  21.     struct device dev;        
  22.   
  23.     int nr;                     /*主控制器的編號*/  
  24.     struct list_head clients;   /*用於鏈接從設備的鏈表頭*/  
  25.     char name[48];              /*控制器名*/  
  26.     struct completion dev_released;/*用於同步的完成量*/  
  27. };  

algo中定義了主控制器的的數據傳輸方式,client是一個鏈表頭,由於可能有多個從設備掛接在該總線上,因此client用於鏈接該控制器下的從設備

和SPI控制器一樣,IIC控制器也是平台資源,因此以platform的方式注冊進內核

  1. static int __init i2c_adap_s3c_init(void)  
  2. {  
  3.     int ret;  
  4.   
  5.     ret = platform_driver_register(&s3c2410_i2c_driver);  
  6.     if (ret == 0) {  
  7.         ret = platform_driver_register(&s3c2440_i2c_driver);  
  8.         if (ret)  
  9.             platform_driver_unregister(&s3c2410_i2c_driver);  
  10.     }  
  11.   
  12.     return ret;  
  13. }  

s3c2410_i2c_driver和s3c2440_i2c_driver的定義除了name字段不一樣外,其他部分都一樣

  1. static struct platform_driver s3c2410_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   = "s3c2410-i2c",  
  9.     },  
  10. };  
  11.   
  12. static struct platform_driver s3c2440_i2c_driver = {  
  13.     .probe      = s3c24xx_i2c_probe,  
  14.     .remove     = s3c24xx_i2c_remove,  
  15.     .suspend_late   = s3c24xx_i2c_suspend_late,  
  16.     .resume     = s3c24xx_i2c_resume,  
  17.     .driver     = {  
  18.         .owner  = THIS_MODULE,  
  19.         .name   = "s3c2440-i2c",  
  20.     },  
  21. };  

當和platform_device匹配成功後,便調用s3c24xx_i2c_probe()函數

  1. static int s3c24xx_i2c_probe(struct platform_device *pdev)  
  2. {  
  3.     struct s3c24xx_i2c *i2c;  
  4.     struct s3c2410_platform_i2c *pdata;  
  5.     struct resource *res;  
  6.     int ret;  
  7.   
  8.     pdata = pdev->dev.platform_data;//獲取平台IIC數據   
  9.     if (!pdata) {  
  10.         dev_err(&pdev->dev, "no platform data\n");  
  11.         return -EINVAL;  
  12.     }  
  13.   
  14.     /*創建一個struct s3c24xx_i2c*/  
  15.     i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);  
  16.     if (!i2c) {  
  17.         dev_err(&pdev->dev, "no memory for state\n");  
  18.         return -ENOMEM;  
  19.     }  
  20.   
  21.     /*設置IIC總線的相關項*/  
  22.     strlcpy(i2c->adap.name, "s3c2410-i2c"sizeof(i2c->adap.name));  
  23.     i2c->adap.owner   = THIS_MODULE;  
  24.     i2c->adap.algo    = &s3c24xx_i2c_algorithm;  
  25.     i2c->adap.retries = 2;  
  26.     i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
  27.     i2c->tx_setup     = 50;  
  28.   
  29.     spin_lock_init(&i2c->lock);  
  30.     init_waitqueue_head(&i2c->wait);//初始化等待隊列   
  31.   
  32.     /* find the clock and enable it */  
  33.   
  34.     i2c->dev = &pdev->dev;  
  35.     i2c->clk = clk_get(&pdev->dev, "i2c");  
  36.     if (IS_ERR(i2c->clk)) {  
  37.         dev_err(&pdev->dev, "cannot get clock\n");  
  38.         ret = -ENOENT;  
  39.         goto err_noclk;  
  40.     }  
  41.   
  42.     dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);  
  43.   
  44.     clk_enable(i2c->clk);  
  45.   
  46.     /* map the registers */  
  47.   
  48.     /*獲取IIC的資源*/  
  49.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  50.     if (res == NULL) {  
  51.         dev_err(&pdev->dev, "cannot find IO resource\n");  
  52.         ret = -ENOENT;  
  53.         goto err_clk;  
  54.     }  
  55.   
  56.     /*為IIC的寄存器申請內存空間*/  
  57.     i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,  
  58.                      pdev->name);  
  59.   
  60.     if (i2c->ioarea == NULL) {  
  61.         dev_err(&pdev->dev, "cannot request IO\n");  
  62.         ret = -ENXIO;  
  63.         goto err_clk;  
  64.     }  
  65.   
  66.     /*重映射IIC的寄存器*/  
  67.     i2c->regs = ioremap(res->start, (res->end-res->start)+1);  
  68.   
  69.     if (i2c->regs == NULL) {  
  70.         dev_err(&pdev->dev, "cannot map IO\n");  
  71.         ret = -ENXIO;  
  72.         goto err_ioarea;  
  73.     }  
  74.   
  75.     dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",  
  76.         i2c->regs, i2c->ioarea, res);  
  77.   
  78.     /* setup info block for the i2c core */  
  79.   
  80.     i2c->adap.algo_data = i2c;  
  81.     i2c->adap.dev.parent = &pdev->dev;  
  82.   
  83.     /* initialise the i2c controller */  
  84.   
  85.     /*初始化s3c24xx的IIC控制器*/  
  86.     ret = s3c24xx_i2c_init(i2c);  
  87.     if (ret != 0)  
  88.         goto err_iomap;  
  89.   
  90.     /* find the IRQ for this unit (note, this relies on the init call to 
  91.      * ensure no current IRQs pending 
  92.      */  
  93.   
  94.     i2c->irq = ret = platform_get_irq(pdev, 0);  
  95.     if (ret <= 0) {  
  96.         dev_err(&pdev->dev, "cannot find IRQ\n");  
  97.         goto err_iomap;  
  98.     }  
  99.   
  100.     /*注冊IIC中斷*/  
  101.     ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,  
  102.               dev_name(&pdev->dev), i2c);  
  103.   
  104.     if (ret != 0) {  
  105.         dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);  
  106.         goto err_iomap;  
  107.     }  
  108.   
  109.     ret = s3c24xx_i2c_register_cpufreq(i2c);  
  110.     if (ret < 0) {  
  111.         dev_err(&pdev->dev, "failed to register cpufreq notifier\n");  
  112.         goto err_irq;  
  113.     }  
  114.   
  115.     /* Note, previous versions of the driver used i2c_add_adapter() 
  116.      * to add the bus at any number. We now pass the bus number via 
  117.      * the platform data, so if unset it will now default to always 
  118.      * being bus 0. 
  119.      */  
  120.   
  121.     i2c->adap.nr = pdata->bus_num;  
  122.   
  123.     /*通過IIC 核心層函數注冊IIC控制器*/  
  124.     ret = i2c_add_numbered_adapter(&i2c->adap);  
  125.     if (ret < 0) {  
  126.         dev_err(&pdev->dev, "failed to add bus to i2c core\n");  
  127.         goto err_cpufreq;  
  128.     }  
  129.   
  130.     platform_set_drvdata(pdev, i2c);  
  131.   
  132.     dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev));  
  133.     return 0;  
  134.   
  135.  err_cpufreq:  
  136.     s3c24xx_i2c_deregister_cpufreq(i2c);  
  137.   
  138.  err_irq:  
  139.     free_irq(i2c->irq, i2c);  
  140.   
  141.  err_iomap:  
  142.     iounmap(i2c->regs);  
  143.   
  144.  err_ioarea:  
  145.     release_resource(i2c->ioarea);  
  146.     kfree(i2c->ioarea);  
  147.   
  148.  err_clk:  
  149.     clk_disable(i2c->clk);  
  150.     clk_put(i2c->clk);  
  151.   
  152.  err_noclk:  
  153.     kfree(i2c);  
  154.     return ret;  
  155. }  

i2c_add_numbered_adapter()會調用i2c_register_adapter()來完成實際的注冊工作

  1. static int i2c_register_adapter(struct i2c_adapter *adap)  
  2. {  
  3.     int res = 0, dummy;  
  4.   
  5.     /* Can't register until after driver model init */  
  6.     if (unlikely(WARN_ON(!i2c_bus_type.p)))  
  7.         return -EAGAIN;  
  8.   
  9.     mutex_init(&adap->bus_lock);  
  10.     mutex_init(&adap->clist_lock);  
  11.     INIT_LIST_HEAD(&adap->clients);//初始化主控制器的從設備鏈表   
  12.   
  13.     mutex_lock(&core_lock);  
  14.   
  15.     /* Add the adapter to the driver core. 
  16.      * If the parent pointer is not set up, 
  17.      * we add this adapter to the host bus. 
  18.      */  
  19.     if (adap->dev.parent == NULL) {  
  20.         adap->dev.parent = &platform_bus;  
  21.         pr_debug("I2C adapter driver [%s] forgot to specify "  
  22.              "physical device\n", adap->name);  
  23.     }  
  24.   
  25.     /* Set default timeout to 1 second if not already set */  
  26.     if (adap->timeout == 0)  
  27.         adap->timeout = HZ;  
  28.   
  29.     dev_set_name(&adap->dev, "i2c-%d", adap->nr);  
  30.     adap->dev.release = &i2c_adapter_dev_release;  
  31.     adap->dev.class = &i2c_adapter_class;//所屬類為i2c_adaoter_class   
  32.     res = device_register(&adap->dev);//注冊設備   
  33.     if (res)  
  34.         goto out_list;  
  35.   
  36.     dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);  
  37.   
  38.     /* create pre-declared device nodes for new-style drivers */  
  39.     /*浏覽板級信息注冊依附在該控制器下的從設備*/  
  40.     if (adap->nr < __i2c_first_dynamic_bus_num)  
  41.         i2c_scan_static_board_info(adap);  
  42.   
  43.     /* Notify drivers */  
  44.     dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,  
  45.                  i2c_do_add_adapter);  
  46.   
  47. out_unlock:  
  48.     mutex_unlock(&core_lock);  
  49.     return res;  
  50.   
  51. out_list:  
  52.     idr_remove(&i2c_adapter_idr, adap->nr);  
  53.     goto out_unlock;  
  54. }  
  1. static void i2c_scan_static_board_info(struct i2c_adapter *adapter)  
  2. {  
  3.     struct i2c_devinfo  *devinfo;  
  4.   
  5.     mutex_lock(&__i2c_board_lock);  
  6.     /*遍歷IIC板級信息列表*/  
  7.     list_for_each_entry(devinfo, &__i2c_board_list, list) {  
  8.         /*如果從設備所屬的總線號等於IIC控制器的編號則創建新設備*/  
  9.         if (devinfo->busnum == adapter->nr  
  10.                 && !i2c_new_device(adapter,  
  11.                         &devinfo->board_info))  
  12.             dev_err(&adapter->dev,  
  13.                 "Can't create device at 0x%02x\n",  
  14.                 devinfo->board_info.addr);  
  15.     }  
  16.     mutex_unlock(&__i2c_board_lock);  
  17. }  
  1. struct i2c_client *  
  2. i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)  
  3. {  
  4.     struct i2c_client   *client;  
  5.     int         status;  
  6.   
  7.     client = kzalloc(sizeof *client, GFP_KERNEL);  
  8.     if (!client)  
  9.         return NULL;  
  10.   
  11.     client->adapter = adap;//設定從設備所屬的IIC控制器   
  12.   
  13.     client->dev.platform_data = info->platform_data;  
  14.   
  15.     if (info->archdata)  
  16.         client->dev.archdata = *info->archdata;  
  17.   
  18.     client->flags = info->flags;  
  19.     client->addr = info->addr;//從設備的地址   
  20.     client->irq = info->irq;  
  21.   
  22.     strlcpy(client->name, info->type, sizeof(client->name));  
  23.   
  24.     /* a new style driver may be bound to this device when we 
  25.      * return from this function, or any later moment (e.g. maybe 
  26.      * hotplugging will load the driver module).  and the device 
  27.      * refcount model is the standard driver model one. 
  28.      */  
  29.     status = i2c_attach_client(client);  
  30.     if (status < 0) {  
  31.         kfree(client);  
  32.         client = NULL;  
  33.     }  
  34.     return client;  
  35. }  
  1. int i2c_attach_client(struct i2c_client *client)  
  2. {  
  3.     struct i2c_adapter *adapter = client->adapter;  
  4.     int res;  
  5.   
  6.     /* Check for address business */  
  7.     /*檢測該從設備的地址是否和已有從設備的地址相同*/  
  8.     res = i2c_check_addr(adapter, client->addr);  
  9.     if (res)  
  10.         return res;  
  11.   
  12.     client->dev.parent = &client->adapter->dev;  
  13.     client->dev.bus = &i2c_bus_type;//設置從設備所屬的總線類型   
  14.   
  15.     if (client->driver)  
  16.         client->dev.driver = &client->driver->driver;  
  17.   
  18.     if (client->driver && !is_newstyle_driver(client->driver)) {  
  19.         client->dev.release = i2c_client_release;  
  20.         dev_set_uevent_suppress(&client->dev, 1);  
  21.     } else  
  22.         client->dev.release = i2c_client_dev_release;  
  23.   
  24.     dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter),  
  25.              client->addr);//名字的構成為控制器號+地址   
  26.     res = device_register(&client->dev);//注冊設備   
  27.     if (res)  
  28.         goto out_err;  
  29.   
  30.     mutex_lock(&adapter->clist_lock);  
  31.     list_add_tail(&client->list, &adapter->clients);//將從設備鏈入IIC控制器   
  32.     mutex_unlock(&adapter->clist_lock);  
  33.   
  34.     dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",  
  35.         client->name, dev_name(&client->dev));  
  36.   
  37.     /*如果adapter中定義了從設備注冊函數,則進一步調用該函數進行注冊,s3c24xx中沒定義該函數*/  
  38.     if (adapter->client_register)  {  
  39.         if (adapter->client_register(client)) {  
  40.             dev_dbg(&adapter->dev, "client_register "  
  41.                 "failed for client [%s] at 0x%02x\n",  
  42.                 client->name, client->addr);  
  43.         }  
  44.     }  
  45.   
  46.     return 0;  
  47.   
  48. out_err:  
  49.     dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "  
  50.         "(%d)\n", client->name, client->addr, res);  
  51.     return res;  
  52. }  
Copyright © Linux教程網 All Rights Reserved