============================================
作者:yuanlulu
http://blog.csdn.net/yuanlulu
版權沒有,但是轉載請保留此段聲明
============================================
根據自己的理解翻譯了http://lxr.linux.no/linux+v2.6.34/Documentation/i2c/instantiating-devices中關於枚舉建立i2c_client的文檔。有異議或疑問請參照原文,畢竟內核的文檔才是真正的精華。s
方法1:使用匯流排號聲明設備。
在內核的初始化中定義設備的資訊。前提是內核編譯的時候已經確定有哪些i2c設備和它們的位址,還要知道連接的匯流排的編號。
比如在/arch/arm/mach-xxxx/board_xxxx.c中可以有這麼一段代碼來註冊i2c設備的資訊。
[cpp] view plaincopyprint?
- static struct i2c_board_info __initdata h4_i2c_board_info[] = {
- {
- I2C_BOARD_INFO("isp1301_omap", 0x2d),
- .irq = OMAP_GPIO_IRQ(125),
- },
- { /* EEPROM on mainboard */
- I2C_BOARD_INFO("24c01", 0x52),
- .platform_data = &m24c01,
- },
- { /* EEPROM on cpu card */
- I2C_BOARD_INFO("24c01", 0x57),
- .platform_data = &m24c01,
- },
- };
- static void __init omap_h4_init(void)
- {
- (...)
- i2c_register_board_info(1, h4_i2c_board_info,
- ARRAY_SIZE(h4_i2c_board_info));
- (...)
- }
這樣註冊之後,i2c_adapter註冊的時候就會掃描所有的已註冊的2c_board_info,並為連接 自己的i2c設備建立一個i2c_client。這樣在2c_board_info中的同名i2c_driver註冊的時候,i2c_client就會和 i2c_driver綁定了,i2c_driver的probe函數被調用。
方法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?
- Example (from the pnx4008 OHCI driver):
- static const unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
- static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
- {
- (...)
- struct i2c_adapter *i2c_adap;
- struct i2c_board_info i2c_info;
- (...)
- i2c_adap = i2c_get_adapter(2);
- memset(&i2c_info, 0, sizeof(struct i2c_board_info));
- strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
- isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
- normal_i2c);
- i2c_put_adapter(i2c_adap);
- (...)
- }
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設備的名字是全局的,因此不同設備的名字不要相同。
20130712
另外注意
留言列表