i2c--2.6.34文檔:如何枚舉產生i2c_client
============================================
作者: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 plain copy print ? 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 plain copy print ? 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裝置的名字是全域的,因此不同裝置的名字不要相同。(並不是不能相同)。