2、編寫I2C的總線通訊方法algorithm
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
int num);
/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);
主要實(shí)現(xiàn)上面的兩個(gè)函數(shù)。
大部分時(shí)間,我們需要定義一個(gè)XXX_i2c結(jié)構(gòu)體,比如drivers/i2c/busses/i2c-s3c2410.c中的struct s3c24xx_i2c。
XXX_i2c結(jié)構(gòu)體中包含struct i2c_msg *msg;struct i2c_adapter adap;void __iomem *regs;等
struct i2c_msg *msg接收用戶層的數(shù)據(jù)發(fā)到i2c總線,或從i2c總線讀取數(shù)據(jù)到用戶層。
在適配器的probe函數(shù)中:
struct xi2cps *id;
platform_set_drvdata(pdev, id);
id->adap.dev.of_node = pdev->dev.of_node;
id->adap.algo = (struct i2c_algorithm *) &xi2cps_algo;
id->adap.timeout = 0x1F;
/* Default timeout value */
id->adap.retries = 3;
/* Default retry value. */
id->adap.algo_data = id;
id->adap.dev.parent = &pdev->dev;
四、linux i2c從設(shè)備驅(qū)動(dòng)
硬件方面,I2C主設(shè)備已經(jīng)集成在主芯片內(nèi),軟件方面,linux也為我們提供了相應(yīng)的驅(qū)動(dòng)程序,位于drivers/i2c/bus下。那么接下來I2C從設(shè)備驅(qū)動(dòng)就變得容易得多。既然系統(tǒng)加載I2C主設(shè)備驅(qū)動(dòng)時(shí)已經(jīng)注冊了i2c_adapter和i2c_client,那么I2C從設(shè)備主要完成三大任務(wù):
系統(tǒng)初始化時(shí)添加以i2c_board_info為結(jié)構(gòu)的I2C從設(shè)備的信息(針對(duì)不使用dts描述硬件信息的電路板)
在I2C從設(shè)備驅(qū)動(dòng)程序里使用i2c_adapter里所提供的算法,即實(shí)現(xiàn)I2C通信。
將I2C從設(shè)備的特有數(shù)據(jù)結(jié)構(gòu)掛在到i2c_client.dev->driver_data下。
以/driver/misc/eeprom/eeprom.c為例:
static struct i2c_driver eeprom_driver = {
.driver = {
.name = "eeprom",
},
.probe = eeprom_probe,
.remove = eeprom_remove,
.id_table = eeprom_id,
.class = I2C_CLASS_DDC | I2C_CLASS_SPD,
.detect = eeprom_detect,
.address_list = normal_i2c,
};
static struct i2c_driver eeprom_driver = {
.driver = {
.name = "eeprom",
},
.probe = eeprom_probe,
.remove = eeprom_remove,
.id_table = eeprom_id,
.class = I2C_CLASS_DDC | I2C_CLASS_SPD,
.detect = eeprom_detect,
.address_list = normal_i2c,
};
i2c_driver 中的driver.name 不一定要和i2c_client一致,因?yàn)檫@只是他們配備的依據(jù)之一。id_table 是i2c_device_id結(jié)構(gòu)體的一個(gè)對(duì)象,里面定義了i2c驅(qū)動(dòng)對(duì)應(yīng)設(shè)備的i2c地址。struct i2c_device_id里面的字符串與 I2C_BOARD_INFO里面的匹配后,xxx_led_probe也會(huì)調(diào)用,這是設(shè)備和驅(qū)動(dòng)匹配的依據(jù)之二。
使用Device Tree后,驅(qū)動(dòng)需要與.dts中描述的設(shè)備結(jié)點(diǎn)進(jìn)行匹配,從而引發(fā)驅(qū)動(dòng)的probe()函數(shù)執(zhí)行。對(duì)于platform_driver而言,需要添加一個(gè)OF匹配表
static const struct i2c_device_id pcf8563_id[] = {
{ "pcf8563", 0 },
{ "rtc8564", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8563_id);
#ifdef CONFIG_OF
static const struct of_device_id pcf8563_of_match[] = {
{ .compatible = "nxp,pcf8563" },
{}
};
MODULE_DEVICE_TABLE(of, pcf8563_of_match);
#endif
static struct i2c_driver pcf8563_driver = {
.driver = {
.name = "rtc-pcf8563",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcf8563_of_match),
},
.probe = pcf8563_probe,
.id_table = pcf8563_id,
};
/* Each client has this additional data */
不過這邊有一點(diǎn)需要提醒的是,I2C和SPI外設(shè)驅(qū)動(dòng)和Device Tree中設(shè)備結(jié)點(diǎn)的compatible 屬性還有一種弱式匹配方法,就是別名匹配。compatible 屬性的組織形式為,,別名其實(shí)就是去掉compatible 屬性中逗號(hào)前的manufacturer前綴。關(guān)于這一點(diǎn),可查看drivers/spi/spi.c的源代碼,函數(shù)spi_match_device()暴露了更多的細(xì)節(jié),如果別名出現(xiàn)在設(shè)備spi_driver的id_table里面,或者別名與spi_driver的name字段相同,SPI設(shè)備和驅(qū)動(dòng)都可以匹配上:
struct eeprom_data {
struct mutex update_lock;
u8 valid; /* bitfield, bit!=0 if slice is valid */
unsigned long last_updated[8]; /* In jiffies, 8 slices */
u8 data[EEPROM_SIZE]; /* Register values */
enum eeprom_nature nature;
};
static int eeprom_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
... ...
struct eeprom_data *data;
......
i2c_set_clientdata(client, data);//將設(shè)備的數(shù)據(jù)結(jié)構(gòu)掛到i2c_client.dev->p->driver_data下
.............
name[0] = i2c_smbus_read_byte_data(client, 0x80);//i2c-core提供的接口,利用i2c_adapter的算法實(shí)現(xiàn)I2C通信
}
這部分內(nèi)容建議參考
以及
也就是說,i2c_adapter是一個(gè)i2c總線控制器,i2c_add_driver會(huì)把i2c_driver掛到i2c總線上,并搜索總線上所有和它匹配的i2c_client,成功的話i2c_driver的probe函數(shù)就會(huì)被調(diào)用,搜索到的i2c_client會(huì)作為參數(shù)傳遞給probe函數(shù)。因?yàn)橐粋€(gè)i2c_driver可能被多個(gè)i2c_client使用,因此就了解i2c_set_clientdata(client, data);調(diào)用的必要性了。就是說多個(gè)clients可以用一個(gè)driver,但是各自有自己的私有數(shù)據(jù)。
注:module_i2c_driver是一個(gè)針對(duì)i2c的宏定義,
定義位于/include/linux/i2c.h/
評(píng)論
查看更多