歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux IIC框架

Linux IIC框架

日期:2017/3/1 10:13:00   编辑:Linux編程

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. /* --- administration stuff. */
  8. /*從設備注冊時調用*/
  9. int (*client_register)(struct i2c_client *) __deprecated;
  10. /*從設備注銷時調用*/
  11. int (*client_unregister)(struct i2c_client *) __deprecated;
  12. /* data fields that are valid for all devices */
  13. u8 level; /* nesting level for lockdep */
  14. struct mutex bus_lock;
  15. struct mutex clist_lock;
  16. int timeout; /* in jiffies */
  17. int retries; /*重試次數*/
  18. struct device dev;
  19. int nr; /*主控制器的編號*/
  20. struct list_head clients; /*用於鏈接從設備的鏈表頭*/
  21. char name[48]; /*控制器名*/
  22. struct completion dev_released;/*用於同步的完成量*/
  23. };

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

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

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

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

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

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

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