內核版本:linux-3.4.2
源程序: linux-3.4.2\drivers\i2c\busses\I2c-s3c2410.c
這次要解決的問題是:如何配置soc的I2C模塊,輸出想要的時序波形?
關於Linux裡I2C驅動的架構,在轉載的文章講得相當透徹(《linux下I2C驅動架構全面分析》http://www.linuxidc.com/Linux/2014-05/101648.htm )。I2C驅動的框架如下圖,主要包括:
總線驅動層: 驅動Soc內部的I2c模塊,也稱之為適配器(adapter)驅動。覆蓋圖中硬件驅動層。
設備驅動層:實現i2c設備的device驅動(如Eeprom的驅動),使用I2C驅動的接口,編寫字符設備(多數是字符設備)。覆蓋圖中的driver驅動層。
核心層:是連接“總線驅動層”和“設備驅動層”的接口。如總線驅動層向核心層注冊一個使用總線的驅動,設備驅動調用這個總線驅動,控制對應的函數。由於
Linux能夠支持多種I2C總線和多種I2C設備,因此采用了總線平台驅動。采用了分層和分離的思想,使一個I2C設備可以使用任意一條I2C總線。
圖1. Linux的I2C驅動框架圖
簡要地回顧完I2C驅動的架構,回到主題——怎樣產生I2C時序?
在總線驅動層裡實現了產生I2C時序,注冊一個master_xfer()方法,使用soc的內部I2C模塊收發數據。我找了一個i2c總線的實例
進行說明:linux-3.4.2\drivers\i2c\busses\I2c-s3c2410.c
static int __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);//注冊一個平台驅動<span > platform_driver</span>
}
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe, //設置probe函數,初始化soc內的i2c模塊,設置收發函數
.remove = s3c24xx_i2c_remove,
.id_table = s3c24xx_driver_ids, //當一個設備的id與.id_table中的一項匹配時(相等),調用probe函數
.driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS,
.of_match_table = s3c24xx_i2c_match,
},
};
static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
i2c->adap.algo = &s3c24xx_i2c_algorithm; //設置具體的收發算法
ret = i2c_add_numbered_adapter(&i2c->adap); //把適配器的驅動注冊進內核,以後這個適配器由core層進行管理
}
/* i2c bus registration info */
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer, //設置<span >master_xfer函數,由這個函數產生I2C時序</span>
.functionality = s3c24xx_i2c_func,
};
當程序來到了master_xfer這一步,接下來就是硬件相關的部分了(和soc內部的i2c模塊相關的部分)。master_xfer會根據函數的參數,找到
對應的適配器,發送數據。看看master_xfer的參數:
static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msgs, int num)
adap:指定需要用到的適配器(Linux驅動能夠同時管理多個適配器)
msgs:需要發送的消息
num: 消息的長度
至此,已經用程序解了“怎樣產生I2C時序”:在master_xfer函數裡設置好如何發送一個I2C時序。當需要發送I2C時序時,調用core層的接口,指定使用哪一條總線、發送什麼數據,即可產生想要的I2C時序。
更多 I2C驅動情景分析 見 http://www.linuxidc.com/search.aspx?where=nkey&keyword=29201