如何枚舉產生i2c_client ,何時使用i2c_new_device

根據自己的理解翻譯了http://lxr.linux.no/linux+v2.6.34/Documentation/i2c/instantiating-devices 中關於枚舉建立i2c_client的文檔。有異議或疑問請參照原文,畢竟內核的文檔纔是真正的精華。

方法1:使用總線號聲明設備。

在內核的初始化中定義設備的信息。前提是內核編譯的時候已經確定有哪些i2c設備和它們的地址,還要知道連接的總線的編號。
 
比如在/arch/arm/mach-xxxx/board_xxxx.c中可以有這麼一段代碼來註冊i2c設備的信息。
  1. static struct i2c_board_info __initdata h4_i2c_board_info[] = {    
  2.          {    
  3.                 I2C_BOARD_INFO("isp1301_omap",0x2d),    
  4.                .irq            = OMAP_GPIO_IRQ(125),    
  5.          },    
  6.          {       /* EEPROM on mainboard */    
  7.                  I2C_BOARD_INFO("24c01", 0x52),    
  8.                  .platform_data  = &m24c01,    
  9.         },    
  10.          {       /* EEPROM on cpu card */    
  11.                 I2C_BOARD_INFO("24c01", 0x57),    
  12.                  .platform_data  = &m24c01,    
  13.          },    
  14. };    
  15.     
  16. static void __init omap_h4_init(void)    
  17. {    
  18.          (...)    
  19.         i2c_register_board_info(1,h4_i2c_board_info,    
  20.                      ARRAY_SIZE(h4_i2c_board_info));    
  21.          (...)    
  22. }    

這 樣註冊之後,i2c_adapter註冊的時候就會掃描所有的已註冊的2c_board_info,併爲連接自己的i2c設備建立一個 i2c_client。這樣在2c_board_info中的同名i2c_driver註冊的時候,i2c_client就會和i2c_driver綁定 了,i2c_driver的probe函數被調用。

方法2:枚舉設備。
方法1有諸多限制,必須必須在編譯內核的時候知道i2c的總線編號和物理的連接。有時開發者面對的是一個已經存在的系統,無法修改內核。
或者內核開發者移植系統的時候也不知道有哪些i2c設備或者到底有多少i2c總線。
在這種情況下就需要用到i2c_new_device()了。它的原型是:
struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
這個函數將會使用info提供的信息建立一個i2c_client並與第一個參數指向的i2c_adapter綁定。返回的參數是一個i2c_client指針。
驅動中可以直接使用i2c_client指針和設備通信了。這個方法是一個比較簡單的方法。


獲取i2c_adapter指針的函數是:
struct i2c_adapter* i2c_get_adapter(int id);//它的參數是i2c總線編號。
使用完要釋放:
void i2c_put_adapter(struct i2c_adapter *adap);
如果連i2c設備的地址都是不固定的,甚至在不同的板子上有不同的地址,可以提供一個地址列表供系統探測。
此時應該使用的函數是i2c_new_probe_device.。用法如下:
  1. Example (from the pnx4008 OHCI driver):    
  2. static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };    
  3. static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)    
  4. {    
  5.            (...)    
  6.             struct i2c_adapter *i2c_adap;    
  7.             struct i2c_board_info i2c_info;    
  8.             (...)    
  9.             i2c_adap = i2c_get_adapter(2);    
  10.             memset(&i2c_info, 0, sizeof(struct i2c_board_info));    
  11.             strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);    
  12.             isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,    
  13.                                                        normal_i2c);    
  14.             i2c_put_adapter(i2c_adap);    
  15.             (...)    
  16.   }    

i2c_new_probed_device的原型是: 

struct i2c_client * i2c_new_probed_device(struct i2c_adapter *adap,struct i2c_board_info *info,unsigned short const *addr_list);

這個函數將會在指定的總線上探測addr_list中的地址,將第一個有ACK反饋的地址賦給info->addr 然後使用前兩個參數調用i2c_new_device。它的返回值也是一個可用的i2c_client指針。 i2c_unregister_device() 可以註銷 i2c_new_device()/i2c_new_probed_device()申請的i2c_client。

補充:驅動開發者如何知道一個物理i2c總線的編號?

[root@zlg /]# cat /sys/class/i2c-dev/i2c-0/name

PNX4008-I2C0

[root@zlg /]# cat /sys/class/i2c-dev/i2c-1/name

PNX4008-I2C1

[root@zlg /]# cat /sys/class/i2c-dev/i2c-2/name

USB-I2C

 

方法3:在所有i2c總線上探測特定設備

內核文檔中關於方法2的限制及方法3的好處我沒看懂。說一下自己的理解,那就是方法2雖然可以探測多個地址,
但是僅僅能在一個指定的總線上探測,並且探測到第一個可用的地址就停止探測了。如果之前並不確定總線的編號,或者一次探測多個i2c設備,就需要用到方法3了。
實現方法3需要兩個條件:******實現i2c_driver的detect成員。這個成員函數原型是: 
int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *); 
這個函數必須檢查第二個參數的addr域是否自己支持的地址,是的話則至少填充info->type,info的其它成員也可以填充,但不應該修改addr。 
如果是就返回0,否則返回-ENODEV。 

******初始化i2c_driver的 
address_list成員。i2c_driver註冊的時候,i2c_core會在所有已經註冊的i2c_adapter上探測 
address_list中的所有地址,硬件探測成功之後後調用i2c_driver的detect成員,然後根據detect填充的info建立一個i2c_client。如果兩個總線上有相同的地址的設備,那麼會分別建立兩個i2c_client。如果 
address_list中的多個地址都有設備佔用,那麼會建立多個i2c_client。 

或許因爲方法3太過於強大和靈活,內核文檔不推薦這種方法。優先選用方法1和2。


方法4:從用戶控件枚舉。如果編寫驅動的時候實在無法知道i2c設備的地址(連可能的地址列表也不知道),那就需要系統運行後從用戶空間輸入了。

用戶空間通過兩個sysfs屬性文件來建立和刪除i2c_client:new_device和delete_device。這兩個文件都是隻寫的。

new_device有兩個參數:i2c設備的名字(字符串)和地址(以0x開頭的16進制數)。

delete_device只有一個參數,那就是設備的地址。



舉例:

# echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device可以看到,此時已經指定了總線編號。 
補充--方法5 :在i2c_driver中的attach_adapter中調用i2c_new_device()或者i2c_new_probed_device()

 

這個方法色實質和方法2類似。

 

 

這樣的例子在2.6.34內核的/sound/ppc/keywest.c中,可以參考。

i2c_driver和i2c_client的總線類型均爲i2c_bus_type,i2c_client的name成員(對應info->type)和i2c_driver中的id_table中的名字 是它們相互綁定的依據。

不同的 i2c_adapter上可以掛靠相同地址的設備,但是i2c設備的名字是全局的,因此不同設備的名字不要相同。(並不是不能相同)。


轉自:http://blog.csdn.net/newger/article/details/6571740

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