i2c适配器源码位置在driver/i2c/buss下这里以i2c-sunxi.c为例,i2c适配器设备和驱动的加载绑定过程也可以看做是i2c总线驱动的加载过程,I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可由CPU控制,甚至可以直接集成在CPU内部。
下面以源码进行分析:
函数的入口:
subsys_initcall(sunxi_i2c_adap_init); //和一般的驱动函数一样存在入口函数
static int __init sunxi_i2c_adap_init(void)//入口函数
{
I2C_DBG("Sunxi I2C adapt init\n");
return platform_driver_register(&sunxi_i2c_driver);//向platform总线注册这个驱动
}
定义适配器驱动:
static struct platform_driver sunxi_i2c_driver = {
.probe = sunxi_i2c_probe,//定义probe函数,设备和驱动绑定后
第一个执行的函数
.remove = sunxi_i2c_remove,
.driver = {
.name = SUNXI_TWI_DEV_NAME, //该驱动的名称
.owner = THIS_MODULE,
.pm = SUNXI_I2C_DEV_PM_OPS,
.of_match_table = sunxi_i2c_match, //定义匹配函数,这个函数
很重要,内核会依据这个
函数中compatible的值
是否相等来决定是否绑定
},
};
static const struct of_device_id sunxi_i2c_match[] = {
{ .compatible = "allwinner,sun8i-twi", },
{ .compatible = "allwinner,sun50i-twi", },
{ .compatible = "allwinner,sun3i-twi", },
{},//内核会自动将这里的值和设备树中的compatible的值进行匹配,匹配成功则将设备和驱动绑定并执行probe函数
};
probe函数:
主要完成adapter的注册和向i2c总线添加adapter工作
static int sunxi_i2c_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct sunxi_i2c *i2c = NULL;
struct resource *mem_res = NULL;
struct sunxi_i2c_platform_data *pdata = NULL;
int ret, irq;
unsigned long int_flag = IRQF_DISABLED;
if (np == NULL) {
I2C_ERR("I2C failed to get of node\n");//获取设备的节点
return -ENODEV;
}
i2c = kzalloc(sizeof(struct sunxi_i2c), GFP_KERNEL);
if (!i2c) {
return -ENOMEM;
}
pdata = kzalloc(sizeof(struct sunxi_i2c_platform_data), GFP_KERNEL);
if (pdata == NULL) {
kfree(i2c);
return -ENOMEM;
}
pdev->dev.platform_data = pdata;
pdev->id = of_alias_get_id(np, "twi");
if (pdev->id < 0) {
I2C_ERR("I2C failed to get alias id\n");
ret = -EINVAL;
goto emem;
}
pdata->bus_num = pdev