Linux I2C驅動分析(二)----I2C板級設備掃描和數據傳輸



一、板級設備掃描

        針對上一篇博客最后的i2c_scan_static_board_info(adap)函數處,首先先看下在系統啟動的時候板級設備的注冊。

        針對我現在使用的開發板,對於I2C設備注冊程序如下:

點擊(此處)折疊或打開

  1. static struct i2c_board_info i2c_devices_info[] = {
  2. #ifdef CONFIG_SND_SOC_ALC5623
  3.         {
  4.                 I2C_BOARD_INFO("alc5623", 0x1a),
  5.                 .platform_data = &alc5623_data,
  6.         },
  7. #endif
  8. #ifdef CONFIG_RTC_DRV_DS3231M
  9.         {
  10.                 I2C_BOARD_INFO("ds3231m", 0x68),
  11.                 .platform_data = NULL,
  12.         },
  13. #endif
  14. #ifdef CONFIG_RTC_DRV_PCF8563
  15.         {
  16.                 I2C_BOARD_INFO("pcf8563", 0x51),
  17.                 .platform_data = NULL,
  18.         },
  19. #endif
  20. };
  21. static int __init gsc3280_i2c_devices_init(void)
  22. {
  23.     i2c_register_board_info(0, i2c_devices_info, ARRAY_SIZE(i2c_devices_info));
  24.     return 0;
  25. }
  26. device_initcall(gsc3280_i2c_devices_init);

        在這里總共有三個I2C設備,名稱分別為alc5623ds3231mpcf8563。宏I2C_BOARD_INFO的功能就是設置I2C設備的名稱和地址,由device_initcall可以看出,gsc3280_i2c_devices_init()函數在系統啟動的時候就會被調用,i2c_register_board_info()函數完成板級設備的注冊,程序如下:

點擊(此處)折疊或打開

  1. DECLARE_RWSEM(__i2c_board_lock);
  2. EXPORT_SYMBOL_GPL(__i2c_board_lock);

  3. LIST_HEAD(__i2c_board_list);
  4. EXPORT_SYMBOL_GPL(__i2c_board_list);

  5. int __i2c_first_dynamic_bus_num;
  6. EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);

  7. int __init
  8. i2c_register_board_info(int busnum,
  9.     struct i2c_board_info const *info, unsigned len)
  10. {
  11.     int status;
  12.     down_write(&__i2c_board_lock);
  13.     /* dynamic bus numbers will be assigned after the last static one */
  14.     if (busnum >= __i2c_first_dynamic_bus_num)
  15.         __i2c_first_dynamic_bus_num = busnum + 1;
  16.     for (status = 0; len; len--, info++) {
  17.         struct i2c_devinfo    *devinfo;
  18.         devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
  19.         if (!devinfo) {
  20.             pr_debug("i2c-core: can't register boardinfo!\n");
  21.             status = -ENOMEM;
  22.             break;
  23.         }
  24.         devinfo->busnum = busnum;
  25.         devinfo->board_info = *info;
  26.         list_add_tail(&devinfo->list, &__i2c_board_list);
  27.     }
  28.     up_write(&__i2c_board_lock);
  29.     return status;
  30. }

        上面的程序位於i2c-boardinfo.c中,i2c_register_board_info()函數的for循環中,首先會申請I2C設備信息結構體,如果申請成功,將I2C總線號和設備信息賦值給設備信息結構體,並且將設備信息結構體的鏈表插入到__i2c_board_list中,此處尤為重要,在本文的開頭中所提的函數i2c_scan_static_board_info(adap);,此函數就是通過__i2c_board_list鏈表找到上面注冊的設備信息,結合gsc3280_i2c_devices_init()函數和i2c_devices_info結構體,此處for循環的len為3,即正常情況下需要創建三個devinfo結構體,for循環結束后,__i2c_board_list鏈表中也就有了三個I2C設備的鏈表項,在程序的其他地方如果需要使用這里注冊的設備結構信息,只需要遍歷鏈表__i2c_board_list,通過總線號即可找到相應的設備信息。

        接下來就可以看下函數i2c_scan_static_board_info(adap)

點擊(此處)折疊或打開

  1. static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
  2. {
  3.     struct i2c_devinfo    *devinfo;
  4.     down_read(&__i2c_board_lock);
  5.     list_for_each_entry(devinfo, &__i2c_board_list, list) {
  6.         if (devinfo->busnum == adapter->nr
  7.                 && !i2c_new_device(adapter,
  8.                         &devinfo->board_info))
  9.             dev_err(&adapter->dev,
  10.                 "Can't create device at 0x%02x\n",
  11.                 devinfo->board_info.addr);
  12.     }
  13.     up_read(&__i2c_board_lock);
  14. }

        從上面程序可以看到,語句list_for_each_entry(devinfo, &__i2c_board_list, list) 實現對__i2c_board_list的遍歷,if語句的前半部分“devinfo->busnum == adapter->nr”判斷是否是需要尋找的結構體,如果是,就調用函數i2c_new_device()創建新的I2C設備,i2c_new_device函數如下:

點擊(此處)折疊或打開

  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;
  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.     /* Check for address validity */
  18.     status = i2c_check_client_addr_validity(client);
  19.     if (status) {
  20.         dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
  21.             client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
  22.         goto out_err_silent;
  23.     }
  24.     /* Check for address business */
  25.     status = i2c_check_addr_busy(adap, client->addr);
  26.     if (status)
  27.         goto out_err;
  28.     client->dev.parent = &client->adapter->dev;
  29.     client->dev.bus = &i2c_bus_type;
  30.     client->dev.type = &i2c_client_type;
  31.     client->dev.of_node = info->of_node;
  32.     dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
  33.          client->addr);
  34.     status = device_register(&client->dev);
  35.     if (status)
  36.         goto out_err;
  37.     dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
  38.         client->name, dev_name(&client->dev));
  39.     return client;
  40. out_err:
  41.     dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
  42.         "(%d)\n", client->name, client->addr, status);
  43. out_err_silent:
  44.     kfree(client);
  45.     return NULL;
  46. }
  47. EXPORT_SYMBOL_GPL(i2c_new_device);

        從函數i2c_new_device()中可以看到,此函數創建了i2c_client結構體,對結構體的內容進行了注冊,設備信息進行了填充,對於本文所使用的開發板,如果程序執行正常,系統啟動成功后,在內存中就有了三個

i2c_client結構體了,分別對應alc5623ds3231mpcf8563

        到此位置,I2C總線驅動,I2C設備的注冊和相應結構體的申請就已經完成了,接下來看下常用的I2C數據傳輸函數,I2C設備驅動主要調用這些數據傳輸接口完成數據的傳輸。

二、I2C數據傳輸

        I2C數據傳輸分為兩種,一種為符合I2C協議的普通數據傳輸,另外一種為符合SMBUS協議的數據傳輸,接下來我們首先看下符合I2C協議的普通數據傳輸。

1、I2C協議的普通數據傳輸

        I2C協議普通數據傳輸的接口函數基本為i2c_master_send和i2c_master_recv,查看其函數發現,最后都是調用i2c_transfer函數實現傳輸的,i2c_transfer函數如下:

點擊(此處)折疊或打開

  1. int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
  2. {
  3.     int ret;
  4.     if (adap->algo->master_xfer) {
  5. #ifdef DEBUG
  6.         for (ret = 0; ret < num; ret++) {
  7.             dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
  8.                 "len=%d%s/n", ret, (msgs[ret].flags & I2C_M_RD)
  9.                 ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
  10.                 (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
  11.         }
  12. #endif
  13.         if (in_atomic() || irqs_disabled()) {
  14.             ret = mutex_trylock(&adap->bus_lock);
  15.             if (!ret)
  16.                 /* I2C activity is ongoing. */
  17.                 return -EAGAIN;
  18.         } else {
  19.             mutex_lock_nested(&adap->bus_lock, adap->level);
  20.         }
  21.         ret = adap->algo->master_xfer(adap,msgs,num);
  22.         mutex_unlock(&adap->bus_lock);
  23.         return ret;
  24.     } else {
  25.         dev_dbg(&adap->dev, "I2C level transfers not supported/n");
  26.         return -ENOSYS;
  27.     }
  28. }

        因為在這里的同步用的是mutex。首先判斷是否允許睡眠,如果不允許,嘗試獲鎖,如果獲鎖失敗,則返回。這樣的操作是避免進入睡眠,我們在后面也可以看到,實際的傳輸工作交給了adap->algo->master_xfer()完成,也就是我們在(一)中注冊的algorithm中的i2c_gsc_func函數。

2、SMBUS協議I2C數據傳輸

        SMBUS協議的具體內容可以參考網絡,在I2C驅動中,符合SMBUS協議傳輸的函數很多,包括i2c_smbus_read_byte、i2c_smbus_write_byte、i2c_smbus_read_byte_data、i2c_smbus_write_byte_data、i2c_smbus_read_word_data和i2c_smbus_write_word_data等,閱讀這些函數發現,程序里面都是根據SMBUS協議和函數功能,完成對函數i2c_smbus_xfer形參的賦值,最后調用此函數來實現傳輸。接下來看下i2c_smbus_xfer函數:

點擊(此處)折疊或打開

  1. s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
  2.          char read_write, u8 command, int protocol,
  3.          union i2c_smbus_data *data)
  4. {
  5.     unsigned long orig_jiffies;
  6.     int try;
  7.     s32 res;
  8.     flags &= I2C_M_TEN | I2C_CLIENT_PEC;
  9.     if (adapter->algo->smbus_xfer) {
  10.         i2c_lock_adapter(adapter);
  11.         /* Retry automatically on arbitration loss */
  12.         orig_jiffies = jiffies;
  13.         for (res = 0, try = 0; try <= adapter->retries; try++) {
  14.             res = adapter->algo->smbus_xfer(adapter, addr, flags,
  15.                             read_write, command,
  16.                             protocol, data);
  17.             if (res != -EAGAIN)
  18.                 break;
  19.             if (time_after(jiffies,
  20.                  orig_jiffies + adapter->timeout))
  21.                 break;
  22.         }
  23.         i2c_unlock_adapter(adapter);
  24.     } else
  25.         res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
  26.                      command, protocol, data);
  27.     return res;
  28. }

          如果adapter有smbus_xfer()函數,則直接調用它發送數據。否則也就是在adapter不支持smbus協議的情況下,調用i2c_smbus_xfer_emulated()繼續處理。根據(一)中的總線驅動是不支持smbus協議的。繼續看函數i2c_smbus_xfer_emulated

點擊(此處)折疊或打開

  1. static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
  2.                                   unsigned short flags,
  3.                                   char read_write, u8 command, int size,
  4.                                   union i2c_smbus_data * data)
  5. {
  6.     /* So we need to generate a series of msgs. In the case of writing, we
  7.       need to use only one message; when reading, we need two. We initialize
  8.       most things with sane defaults, to keep the code below somewhat
  9.       simpler. */
  10.     //寫操作只會進行一次交互而讀操作有時會有兩次操作.
  11.     //因為有時候讀操作要先寫command,再從總線上讀數據
  12.     //在這里為了代碼的簡潔,使用了兩個緩存區,將兩種情況統一起來.
  13.     unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
  14.     unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
  15.     //一般來說讀操作要交互兩次,例外的情況我們在下面會接着分析
  16.     int num = read_write == I2C_SMBUS_READ?2:1;
  17.     //與設備交互的數據,一般在msg[0]存放寫入設備的信息,在msb[1]里存放接收到的
  18.     //信息,不過也有例外的
  19.     //msg[2]的初始化,默認發送緩存區占一個字節,無接收緩存
  20.     struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
  21.                               { addr, flags | I2C_M_RD, 0, msgbuf1 }
  22.                             };
  23.     int i;
  24.     u8 partial_pec = 0;
  25.     //將要發送的信息copy到發送緩存區的第一字節
  26.     msgbuf0[0] = command;
  27.     switch(size) {
  28.         //quick類型,它並不傳輸有效數據,只是將地址寫到總線上,等待應答即可
  29.         //所以將發送緩存區長度置為0。再根據讀/寫操作,調整msg[0]的標志位
  30.         //這類傳輸只需要一次總線交互
  31.     case I2C_SMBUS_QUICK:
  32.         msg[0].len = 0;
  33.         /* Special case: The read/write field is used as data */
  34.         msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
  35.         num = 1;
  36.         break;
  37.     case I2C_SMBUS_BYTE:
  38.         //BYTE類型指一次寫和讀只有一個字節.這種情況下,讀和寫都只會交互一次
  39.         //這種類型的讀有例外,它讀取出來的數據不是放在msg[1]中的,而是存放在msg[0]
  40.         if (read_write == I2C_SMBUS_READ) {
  41.             /* Special case: only a */
  42.             msg[0].flags = I2C_M_RD | flags;
  43.             num = 1;
  44.         }
  45.         break;
  46.     case I2C_SMBUS_BYTE_DATA:
  47.         //Byte_Data是指命令+數據的傳輸形式,在這種情況下,寫只需要一次交互,讀卻要兩次
  48.         //第一次將command寫到總線上,第二次要轉換方向,要將設備地址和read標志寫入總線.
  49.         //應回答之后再進行read操作
  50.         //寫操作占兩字節,分別是command+data,讀操作的有效數據只有一個字節
  51.         //交互次數用初始化值就可以了
  52.         if (read_write == I2C_SMBUS_READ)
  53.             msg[1].len = 1;
  54.         else {
  55.             msg[0].len = 2;
  56.             msgbuf0[1] = data->byte;
  57.         }
  58.         break;
  59.     case I2C_SMBUS_WORD_DATA:
  60.         //Word_Data是指命令+雙字節的形式.這種情況跟Byte_Data的情況類似
  61.         //兩者相比只是交互的數據大小不同
  62.         if (read_write == I2C_SMBUS_READ)
  63.             msg[1].len = 2;
  64.         else {
  65.             msg[0].len=3;
  66.             msgbuf0[1] = data->word & 0xff;
  67.             msgbuf0[2] = data->word >> 8;
  68.         }
  69.         break;
  70.     case I2C_SMBUS_PROC_CALL:
  71.         //Proc_Call的方式與write 的Word_Data相似,只不過寫完Word_Data之后,要等待它的應答
  72.         //應該它需要交互兩次,一次寫一次讀
  73.         num = 2; /* Special case */
  74.         read_write = I2C_SMBUS_READ;
  75.         msg[0].len = 3;
  76.         msg[1].len = 2;
  77.         msgbuf0[1] = data->word & 0xff;
  78.         msgbuf0[2] = data->word >> 8;
  79.         break;
  80.     case I2C_SMBUS_BLOCK_DATA:
  81.         //Block_Data:指command+N段數據的情況.
  82.         //如果是讀操作,它首先要寫command到總線,然后再讀N段數據,要寫的command已經
  83.         //放在msg[0]了,現在只需要將msg[1]的標志置I2C_M_RECV_LEN位,msg[1]有效長度為1字節,因為
  84.         //adapter驅動會處理好的,現在還不知道要傳多少段數據.
  85.         //對於寫的情況:msg[1]照例不需要.將要寫的數據全部都放到msb[0].相應的也要更新
  86.         //msg[0]中的緩存區長度
  87.         if (read_write == I2C_SMBUS_READ) {
  88.             msg[1].flags |= I2C_M_RECV_LEN;
  89.             msg[1].len = 1; /* block length will be added by
  90.                       the underlying bus driver */
  91.         } else {
  92.             //data->block[0]表示后面有多少段數據.總長度要加2是因為command+count+N段數據
  93.             msg[0].len = data->block[0] + 2;
  94.             if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
  95.                 dev_err(&adapter->dev, "smbus_access called with "
  96.                       "invalid block write size (%d)/n",
  97.                       data->block[0]);
  98.                 return -1;
  99.             }
  100.             for (= 1; i < msg[0].len; i++)
  101.                 msgbuf0 = data->block[i-1];
  102.         }
  103.         break;
  104.     case I2C_SMBUS_BLOCK_PROC_CALL:
  105.         //Proc_Call:表示寫完Block_Data之后,要等它的應答消息它和Block_Data相比,只是多了一部份應答而已
  106.         num = 2; /* Another special case */
  107.         read_write = I2C_SMBUS_READ;
  108.         if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
  109.             dev_err(&adapter->dev, "%s called with invalid "
  110.                 "block proc call size (%d)/n", __func__,
  111.                 data->block[0]);
  112.             return -1;
  113.         }
  114.         msg[0].len = data->block[0] + 2;
  115.         for (= 1; i < msg[0].len; i++)
  116.             msgbuf0 = data->block[i-1];
  117.         msg[1].flags |= I2C_M_RECV_LEN;
  118.         msg[1].len = 1; /* block length will be added by
  119.                   the underlying bus driver */
  120.         break;
  121.     case I2C_SMBUS_I2C_BLOCK_DATA:
  122.         //I2c Block_Data與Block_Data相似,只不過read的時候,數據長度是預先定義好了的.另外
  123.         //與Block_Data相比,中間不需要傳輸Count字段.(Count表示數據段數目)
  124.         if (read_write == I2C_SMBUS_READ) {
  125.             msg[1].len = data->block[0];
  126.         } else {
  127.             msg[0].len = data->block[0] + 1;
  128.             if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
  129.                 dev_err(&adapter->dev, "i2c_smbus_xfer_emulated called with "
  130.                       "invalid block write size (%d)/n",
  131.                       data->block[0]);
  132.                 return -1;
  133.             }
  134.             for (= 1; i <= data->block[0]; i++)
  135.                 msgbuf0 = data->block;
  136.         }
  137.         break;
  138.     default:
  139.         dev_err(&adapter->dev, "smbus_access called with invalid size (%d)/n",
  140.               size);
  141.         return -1;
  142.     }
  143.     //如果啟用了PEC.Quick和I2c Block_Data是不支持PEC的
  144.     i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
  145.                       && size != I2C_SMBUS_I2C_BLOCK_DATA);
  146.     if (i) {
  147.         /* Compute PEC if first message is a write */
  148.         //如果第一個操作是寫操作
  149.         if (!(msg[0].flags & I2C_M_RD)) {
  150.             //如果只是寫操作
  151.             if (num == 1) /* Write only */
  152.                 //如果只有寫操作,寫緩存區要擴充一個字節,用來存放計算出來的PEC
  153.                 i2c_smbus_add_pec(&msg[0]);
  154.             else /* Write followed by read */
  155.                 //如果后面還有讀操作,先計算前面寫部份的PEC(注意這種情況下不需要
  156.                 //擴充寫緩存區,因為不需要發送PEC.只會接收到PEC)
  157.                 partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
  158.         }
  159.         /* Ask for PEC if last message is a read */
  160.         //如果最后一次是讀消息.還要接收到來自slave的PEC.所以接收緩存區要擴充一個字節
  161.         if (msg[num-1].flags & I2C_M_RD)
  162.             msg[num-1].len++;
  163.     }
  164.     if (i2c_transfer(adapter, msg, num) < 0)
  165.         return -1;
  166.     /* Check PEC if last message is a read */
  167.     //操作完了之后,如果最后一個操作是PEC的讀操作.檢驗后面的PEC是否正確
  168.     if (&& (msg[num-1].flags & I2C_M_RD)) {
  169.         if (i2c_smbus_check_pec(partial_pec, &msg[num-1]) < 0)
  170.             return -1;
  171.     }
  172.     //操作完了,現在可以將數據放到data部份返回了.
  173.     if (read_write == I2C_SMBUS_READ)
  174.         switch(size) {
  175.             case I2C_SMBUS_BYTE:
  176.                 data->byte = msgbuf0[0];
  177.                 break;
  178.             case I2C_SMBUS_BYTE_DATA:
  179.                 data->byte = msgbuf1[0];
  180.                 break;
  181.             case I2C_SMBUS_WORD_DATA:
  182.             case I2C_SMBUS_PROC_CALL:
  183.                 data->word = msgbuf1[0] | (msgbuf1[1] << 8);
  184.                 break;
  185.             case I2C_SMBUS_I2C_BLOCK_DATA:
  186.                 for (= 0; i < data->block[0]; i++)
  187.                     data->block[i+1] = msgbuf1;
  188.                 break;
  189.             case I2C_SMBUS_BLOCK_DATA:
  190.             case I2C_SMBUS_BLOCK_PROC_CALL:
  191.                 for (= 0; i < msgbuf1[0] + 1; i++)
  192.                     data->block = msgbuf1;
  193.                 break;
  194.         }
  195.     return 0;
  196. }
        此處也是調用i2c_transfer函數實現數據的最終傳輸的,在上面已經講述了此函數。

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com