http://blog.csdn.net/yuanlulu/article/details/6557901


============================================
作者:yuanlulu
http://blog.csdn.net/yuanlulu


版權沒有,但是轉載請保留此段聲明
============================================


 


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


 


方法1:使用匯流排號聲明設備。


在內核的初始化中定義設備的資訊。前提是內核編譯的時候已經確定有哪些i2c設備和它們的位址,還要知道連接的匯流排的編號。


 


比如在/arch/arm/mach-xxxx/board_xxxx.c中可以有這麼一段代碼來註冊i2c設備的資訊。


 


[cpp] view plaincopyprint?


  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_driverprobe函數被調用。


 


方法2:枚舉設備。


使用i2c_new_device()或者i2c_new_probed_device().


方法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.。用法如下:


[cpp] view plaincopyprint?


  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_driverdetect成員。這個成員函數原型是:


int (*detect)(struct i2c_client *, int kind, struct i2c_board_info *);


這個函數必須檢查第二個參數的addr域是否自己支持的位址,是的話則至少填充info->typeinfo的其他成員也可以填充,但不應該修改addr


如果是就返回0,否則返回-ENODEV


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





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





方法4:從用戶控制項枚舉。


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


用戶空間通過兩個sysfs屬性檔來建立和刪除i2c_clientnew_devicedelete_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_driveri2c_client的匯流排類型均為i2c_bus_typei2c_clientname成員(對應info->type)和i2c_driver中的id_table中的名字


是它們相互綁定的依據。


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


 


20130712


另外注意


i2c_board_info 註冊時 同樣裝置 若有相同ID則需看是否在同個 adapter
有些硬體 會同一個
adapter 虛擬 兩個 BUS 如
I2C-0 與 I2C-1  雖然看到兩個 但實際是同一個硬體 所以若相同ID .第二個會無法註冊成功..


arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()