Linux驅動I2C分析



  一:前言

  I2c是philips提出的外設總線。I2C只有兩條線,一條串行數據線:SDA,一條是時鐘線SCL.正因爲這樣,它方便了工程人員的佈線。另外,I2C是一種多主機控制總線。它和USB總線不同,USB是基於master-slave機制,任何設備的通信必須由主機發起纔可以。而I2C是基於multi master機制。一同總線上可允許多個master.關於I2C協議的知識,這裏不再贅述。可自行下載spec閱讀即可。

  二:I2C架構概述

  如上圖所示,每一條I2C對應一個adapter.在kernel中,每一個adapter提供了一個描述的結構(struct i2c_adapter),也定義了adapter支持的操作(struct i2c_adapter)。再通過i2c core層將i2c設備與i2c adapter關聯起來。

  這個圖只是提供了一個大概的框架。在下面的代碼分析中,從下至上的來分析這個框架圖。以下的代碼分析是基於linux 2.6.26.分析的代碼基本位於: linux-2.6.26.3/drivers/i2c/位置。

  三:adapter註冊

  在kernel中提供了兩個adapter註冊接口,分別爲i2c_add_adapter()和i2c_add_numbered_adapter()。由於在系統中可能存在多個adapter,因爲將每一條I2C總線對應一個編號,下文中稱爲I2C總線號。這個總線號的PCI中的總線號不同。它和硬件無關,只是軟件上便於區分而已。

  對於i2c_add_adapter()而言,它使用的是動態總線號,即由系統給其分析一個總線號,而i2c_add_numbered_adapter()則是自己指定總線號,如果這個總線號非法或者是被佔用,就會註冊失敗。

  分別來看一下這兩個函數的代碼:

  int i2c_add_adapter(struct i2c_adapter *adapter)

  {

      int id, res = 0;

      retry:

      if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)

          return -ENOMEM;

      mutex_lock(&core_lock);

  /* "above" here means "above or equal to", sigh */

      res = idr_get_new_above(&i2c_adapter_idr, adapter,

      __i2c_first_dynamic_bus_num, &id);

      mutex_unlock(&core_lock);

      if (res < 0)

          {

          if (res == -EAGAIN)

          goto retry;

          return res;

     }

     adapter->nr = id;

     return i2c_register_adapter(adapter);

  }

  在這裏涉及到一個idr結構。idr結構本來是爲了配合page cache中的radix tree而設計的。在這裏我們只需要知道,它是一種高效的搜索樹,且這個樹預先存放了一些內存。避免在內存不夠的時候出現問題。所在,在往idr中插入結構的時候,首先要調用idr_pre_get()爲它預留足夠的空閒內存,然後再調用idr_get_new_above()將結構插入idr中,該函數以參數的形式返回一個id.以後憑這個id就可以在idr中找到相對應的結構了。對這個數據結構操作不太理解的可以查閱本站《 linux文件系統之文件的讀寫》中有關radix tree的分析。

  注意一下idr_get_new_above(&i2c_adapter_idr, adapter,__i2c_first_dynamic_bus_num, &id)的參數的含義,它是將adapter結構插入到i2c_adapter_idr中,存放位置的id必須要大於或者等於__i2c_first_dynamic_bus_num,

  然後將對應的id號存放在adapter->nr中。調用i2c_register_adapter(adapter)對這個adapter進行進一步註冊。

  看一下另外一人註冊函數: i2c_add_numbered_adapter( ),如下所示:

  int i2c_add_numbered_adapter(struct i2c_adapter *adap)

  {

  int id;

  int status;

  if (adap->nr & ~MAX_ID_MASK)

  return -EINVAL;

  retry:

  if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)

  return -ENOMEM;

  mutex_lock(&core_lock);

  /* "above" here means "above or equal to", sigh;

  * we need the "equal to" result to force the result

  */

  status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);

  if (status == 0 && id != adap->nr) {

  status = -EBUSY;

  idr_remove(&i2c_adapter_idr, id);

  }

  mutex_unlock(&core_lock);

  if (status == -EAGAIN)

  goto retry;

  if (status == 0)

  status = i2c_register_adapter(adap);

  return status;

  }

  對比一下就知道差別了,在這裏它已經指定好了adapter->nr了。如果分配的id不和指定的相等,便返回錯誤。

  過一步跟蹤i2c_register_adapter()。代碼如下:

  static int i2c_register_adapter(struct i2c_adapter *adap)

  {

  int res = 0, dummy;

  mutex_init(&adap->bus_lock);

  mutex_init(&adap->clist_lock);

  INIT_LIST_HEAD(&adap->clients);

  mutex_lock(&core_lock);

  /* Add the adapter to the driver core.

  * If the parent pointer is not set up,

  * we add this adapter to the host bus.

  */

  if (adap->dev.parent == NULL) {

  adap->dev.parent = &platform_bus;

  pr_debug("I2C adapter driver [%s] forgot to specify "

  "physical device\n", adap->name);

  }

  sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);

  adap->dev.release = &i2c_adapter_dev_release;

  adap->dev.class = &i2c_adapter_class;

  res = device_register(&adap->dev);

  if (res)

  goto out_list;

  dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

  /* create pre-declared device nodes for new-style drivers */

  if (adap->nr < __i2c_first_dynamic_bus_num)

  i2c_scan_static_board_info(adap);

  /* let legacy drivers scan this bus for matching devices */

  dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,

  i2c_do_add_adapter);

  out_unlock:

  mutex_unlock(&core_lock);

  return res;

  out_list:

  idr_remove(&i2c_adapter_idr, adap->nr);

  goto out_unlock;

  }

  首先對adapter和adapter中內嵌的struct device結構進行必須的初始化。之後將adapter內嵌的struct device註冊。

  在這裏注意一下adapter->dev的初始化。它的類別爲i2c_adapter_class,如果沒有父結點,則將其父結點設爲platform_bus.adapter->dev的名字爲i2c + 總線號。

  測試一下:

  [eric@mochow i2c]$ cd /sys/class/i2c-adapter/

  [eric@mochow i2c-adapter]$ ls

  i2c-0

  可以看到,在我的PC上,有一個I2C adapter,看下詳細信息:

  [eric@mochow i2c-adapter]$ tree

  .

  `-- i2c-0

  |-- device -> ///devices/pci0000:00/0000:00:1f.3/i2c-0

  |-- name

  |-- subsystem -> ///class/i2c-adapter

  `-- uevent

  3 directories, 2 files

  可以看到,該adapter是一個PCI設備。

  繼續往下看:

  之後,在註釋中看到,有兩種類型的driver,一種是new-style drivers,另外一種是legacy drivers

  New-style drivers是在2.6近版的kernel加入的。它們最主要的區別是在adapter和i2c driver的匹配上。

  3.1: new-style 形式的adapter註冊

  對於第一種,也就是new-style drivers,將相關代碼再次列出如下:

  if (adap->nr < __i2c_first_dynamic_bus_num)

  i2c_scan_static_board_info(adap);

  如果adap->nr 小於__i2c_first_dynamic_bus_num的話,就會進入到i2c_scan_static_board_info()。

  結合我們之前分析的adapter的兩種註冊分式: i2c_add_adapter()所分得的總線號肯會不會小於__i2c_first_dynamic_bus_num.只有i2c_add_numbered_adapter()纔有可能滿足:

  (adap->nr < __i2c_first_dynamic_bus_num)

  而且必須要調用i2c_register_board_info()將板子上的I2C設備信息預先註冊時纔會更改__i2c_first_dynamic_bus_num的值。在x86上只沒有使用i2c_register_board_info()的。因此,x86平臺上的分析可以忽略掉new-style driver的方式。不過,還是詳細分析這種情況下。

  首先看一下i2c_register_board_info(),如下:

  int __init

  i2c_register_board_info(int busnum,

  struct i2c_board_info const *info, unsigned len)

  {

  int status;

  mutex_lock(&__i2c_board_lock);

  /* dynamic bus numbers will be assigned after the last static one */

  if (busnum >= __i2c_first_dynamic_bus_num)

  __i2c_first_dynamic_bus_num = busnum + 1;

  for (status = 0; len; len--, info++) {

  struct i2c_devinfo *devinfo;

  devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);

  if (!devinfo) {

  pr_debug("i2c-core: can't register boardinfo!\n");

  status = -ENOMEM;

  break;

  }

  devinfo->busnum = busnum;

  devinfo->board_info = *info;

  list_add_tail(&devinfo->list, &__i2c_board_list);

  }

  mutex_unlock(&__i2c_board_lock);

  return status;

  }

  這個函數比較簡單, struct i2c_board_info用來表示I2C設備的一些情況,比如所在的總線。名稱,地址,中斷號等。最後,這些信息會被存放到__i2c_board_list鏈表。

  跟蹤i2c_scan_static_board_info():代碼如下:

  static void i2c_scan_static_board_info(struct i2c_adapter *adapter)

  {

  struct i2c_devinfo *devinfo;

  mutex_lock(&__i2c_board_lock);

  list_for_each_entry(devinfo, &__i2c_board_list, list) {

  if (devinfo->busnum == adapter->nr

  && !i2c_new_device(adapter,

  &devinfo->board_info))

  printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",

  i2c_adapter_id(adapter),

  devinfo->board_info.addr);

  }

  mutex_unlock(&__i2c_board_lock);

  }

  該函數遍歷掛在__i2c_board_list鏈表上面的i2c設備的信息,也就是我們在啓動的時候指出的i2c設備的信息。

  如果指定設備是位於adapter所在的I2C總線上,那麼,就調用i2c_new_device()。代碼如下:

  struct i2c_client *

  i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

  {

  struct i2c_client *client;

  int status;

  client = kzalloc(sizeof *client, GFP_KERNEL);

  if (!client)

  return NULL;

  client->adapter = adap;

  client->dev.platform_data = info->platform_data;

  device_init_wakeup(&client->dev, info->flags & I2C_CLIENT_WAKE);

  client->flags = info->flags & ~I2C_CLIENT_WAKE;

  client->addr = info->addr;

  client->irq = info->irq;

  strlcpy(client->name, info->type, sizeof(client->name));

  /* a new style driver may be bound to this device when we

  * return from this function, or any later moment (e.g. maybe

  * hotplugging will load the driver module)。 and the device

  * refcount model is the standard driver model one.

  */

  status = i2c_attach_client(client);

  if (status < 0) {

  kfree(client);

  client = NULL;

  }

  return client;

  }

  我們又遇到了一個新的結構:struct i2c_client,不要被這個結構嚇倒了,其實它就是一個嵌入struct device的I2C設備的封裝。它和我們之前遇到的struct usb_device結構的作用是一樣的。

  首先,在clinet裏保存該設備的相關消息。特別的, client->adapter指向了它所在的adapter.

  特別的,clinet->name爲info->name.也是指定好了的。

  一切初始化完成之後,便會調用i2c_attach_client( )。看這個函數的字面意思,是將clinet關聯起來。到底怎麼樣關聯呢?繼續往下看:

  int i2c_attach_client(struct i2c_client *client)

  {

          struct i2c_adapter *adapter = client->adapter;

          int res = 0;

    //初始化client內嵌的dev結構

   //父結點爲所在的adapter,所在bus爲i2c_bus_type

          client->dev.parent = &client->adapter->dev;

          client->dev.bus = &i2c_bus_type;

  //如果client已經指定了driver,將driver和內嵌的dev關聯起來

          if (client->driver)

          client->dev.driver = &client->driver->driver;

  //指定了driver, 但不是newstyle的

          if (client->driver && !is_newstyle_driver(client->driver)) {

          client->dev.release = i2c_client_release;

          client->dev.uevent_suppress = 1;

  } else

          client->dev.release = i2c_client_dev_release;

          //clinet->dev的名稱

          snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),

          "%d-%04x", i2c_adapter_id(adapter), client->addr);

    //將內嵌的dev註冊

          res = device_register(&client->dev);

          if (res)

                goto out_err;

  //將clinet鏈到adapter->clients中

          mutex_lock(&adapter->clist_lock);

          list_add_tail(&client->list, &adapter->clients);

          mutex_unlock(&adapter->clist_lock);

          dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",

          client->name, client->dev.bus_id);

  //如果adapter->cleinet_reqister存在,就調用它

          if (adapter->client_register) {

                 if (adapter->client_register(client)) {

                         dev_dbg(&adapter->dev, "client_register "

                        "failed for client [%s] at 0x%02x\n",

                         client->name, client->addr);

                   }

                }

   return 0;

  out_err:

  dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "

  "(%d)\n", client->name, client->addr, res);

  return res;

  }

  參考上面添加的註釋,應該很容易理解這段代碼了,就不加詳細分析了。這個函數的名字不是i2c_attach_client()麼?怎麼沒看到它的關係過程呢?

  這是因爲:在代碼中設置了client->dev所在的bus爲i2c_bus_type .以爲只需要有bus爲i2c_bus_type的driver註冊,就會產生probe了。這個過程呆後面分析i2c driver的時候再來詳細分析。

  3.2: legacy形式的adapter註冊

  Legacy形式的adapter註冊代碼片段如下:

  dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,

  i2c_do_add_adapter);

  這段代碼遍歷掛在i2c_bus_type上的驅動,然後對每一個驅動和adapter調用i2c_do_add_adapter()。

  代碼如下:

  static int i2c_do_add_adapter(struct device_driver *d, void *data)

  {

  struct i2c_driver *driver = to_i2c_driver(d);

  struct i2c_adapter *adap = data;

  if (driver->attach_adapter) {

  /* We ignore the return code; if it fails, too bad */

  driver->attach_adapter(adap);

  }

  return 0;

  }

  該函數很簡單,就是調用driver的attach_adapter()接口。

  到此爲止,adapter的註冊已經分析完了。

  四:i2c driver註冊

  在分析i2c driver的時候,有必要先分析一下i2c架構的初始化

  代碼如下:

  static int __init i2c_init(void)

  {

  int retval;

  retval = bus_register(&i2c_bus_type);

  if (retval)

  return retval;

  retval = class_register(&i2c_adapter_class);

  if (retval)

  goto bus_err;

  retval = i2c_add_driver(&dummy_driver);

  if (retval)

  goto class_err;

  return 0;

  class_err:

  class_unregister(&i2c_adapter_class);

  bus_err:

  bus_unregister(&i2c_bus_type);

  return retval;

  }

  subsys_initcall(i2c_init);

  很明顯,i2c_init()會在系統初始化的時候被調用。

  在i2c_init中,先註冊了i2c_bus_type的bus,i2c_adapter_class的class.然後再調用i2c_add_driver()註冊了一個i2c driver.

  I2c_bus_type結構如下:

  static struct bus_type i2c_bus_type = {

  .name = "i2c",

  .dev_attrs = i2c_dev_attrs,

  .match = i2c_device_match,

  .uevent = i2c_device_uevent,

  .probe = i2c_device_probe,

  .remove = i2c_device_remove,

  .shutdown = i2c_device_shutdown,

  .suspend = i2c_device_suspend,

  .resume = i2c_device_resume,

  };

  這個結構先放在這裏吧,以後還會用到裏面的信息的。

  從上面的初始化函數裏也看到了,註冊i2c driver的接口爲i2c_add_driver()。代碼如下:

  static inline int i2c_add_driver(struct i2c_driver *driver)

  {

  return i2c_register_driver(THIS_MODULE, driver);

  }

  繼續跟蹤:

  int i2c_register_driver(struct module *owner, struct i2c_driver *driver)

  {

  int res;

  /* new style driver methods can't mix with legacy ones */

  //如果是一個newstyle的driver.但又定義了attach_adapter/detach_adapter.非法

  if (is_newstyle_driver(driver)) {

  if (driver->attach_adapter || driver->detach_adapter

  || driver->detach_client) {

  printk(KERN_WARNING

  "i2c-core: driver [%s] is confused\n",

  driver->driver.name);

  return -EINVAL;

  }

  }

  /* add the driver to the list of i2c drivers in the driver core */

  //關聯到i2c_bus_types

  driver->driver.owner = owner;

  driver->driver.bus = &i2c_bus_type;

  /* for new style drivers, when registration returns the driver core

  * will have called probe() for all matching-but-unbound devices.

  */

  //註冊內嵌的driver

  res = driver_register(&driver->driver);

  if (res)

  return res;

  mutex_lock(&core_lock);

  pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

  /* legacy drivers scan i2c busses directly */

  //遍歷所有的adapter,對其都調用driver->attach_adapter

  if (driver->attach_adapter) {

  struct i2c_adapter *adapter;

  down(&i2c_adapter_class.sem);

  list_for_each_entry(adapter, &i2c_adapter_class.devices,

  dev.node) {

  driver->attach_adapter(adapter);

  }

  up(&i2c_adapter_class.sem);

  }

  mutex_unlock(&core_lock);

  return 0;

  }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章