I2C設備驅動要使用i2c_driver和i2c_client數據結構並填充i2c_driver中的成員函數。i2c_client一般被包含在設備的私有信息結構體xxx_data中,而i2c_driver則適合被定義為全局變數並初始化。下麵提供i2c_driver的初始化模版: 1 Linux I2 ...
I2C設備驅動要使用i2c_driver和i2c_client數據結構並填充i2c_driver中的成員函數。i2c_client一般被包含在設備的私有信息結構體xxx_data中,而i2c_driver則適合被定義為全局變數並初始化。下麵提供i2c_driver的初始化模版:
1 static struct i2c_driver xxx_driver = { 2 .driver = { 3 .name = "xxx", 4 }, 5 .probe = xxx_probe, 6 .remove = xxx_remove, 7 .id_table = xxx_id, 8 };
1 Linux I2C設備驅動的模塊載入和卸載
I2C設備驅動的模塊載入用i2c_add_driver()來完成;模塊卸載用i2c_del_driver()來完成。
1 static int __init xxx_init(void) { 2 return i2c_add_driver(&xxx_driver); 3 } 4 module_init(xxx_init); 5 6 static void __exit xxx_exit(void) { 7 i2c_del_driver(&xxx_driver); 8 } 9 module_exit(xxx_exit);
2 Linux I2C設備驅動的數據傳輸
在I2C設備上讀寫數據是通過i2c_msg數組進行組織的,最後通過i2c_transfer()函數完成。
下麵提供I2C設備驅動數據傳輸模版:
1 struct i2c_msg msg[2]; 2 /* 第一條消息是寫消息(從機地址) */ 3 msg[0].addr = client->addr; 4 msg[0].flags = 0; 5 msg[0].len = 1; 6 msg[0].buf = &offs; 7 /* 第二條消息是讀消息 */ 8 msg[1].addr = client->addr; 9 msg[1].flags = I2C_M_RD; 10 msg[1].len = sizeof(buf); 11 msg[1].buf = &buf[0]; 12 i2c_transfer(client->adapter, msg, 2);
3 Linux的i2c-dev.c文件分析
i2c-dev.c文件完全可以被看作是一個I2C設備驅動。i2c-dev.c針對每個I2C適配器生成一個主設備號89的設備文件,實現了i2c_driver的成員函數以及文件操作介面,因此i2c-dev.c的主體是“i2c_driver成員函數+字元設備驅動”。
i2c-dev.c提供的i2cdev_read()、i2c_write()函數對應於用戶空間要使用的read()和write()文件操作介面,這兩個函數分別調用I2C核心的i2c_master_recv()和i2c_master_send()函數來構造一條I2C消息並引發適配器Algorithm通信函數的調用,以完成消息的傳輸。
但是,大多數稍微複雜一點的I2C設備的讀寫流程並不對應於一條消息,往往需要兩條甚至多條消息來進行一次讀寫周期(對應於上圖的重覆開始位的RepStart模式),在這種情況下,在應用層仍然調用read()、write()文件API來讀寫I2C設備,將不能正確地讀寫。
鑒於上述原因,i2c-dev.c中的i2cdev_read()和i2cdev_write()函數不具備太強的通用性,沒有太大的實用價值,只能適用於非RepStart模式的情況。對於由兩條以上消息組成的讀寫,在用戶空間需要組織i2c_msg消息數組並調用I2C_RDWR IOCTL命令。