linux|linux i2c子系统代码分析7 ---i2c适配器注册时机、方法以及例程

i2c适配器注册时机:
1、在paltform驱动中注册,在板级初始化时注册一个platform设备,然后在注册platform驱动时将i2c适配器注册。
这种方法属于适配器静态注册,是soc中i2c适配器通用注册方法,因为这样保证后续的i2c驱动注册以及i2c设备注册能找到匹配的适配器,i2c驱动和i2c设备注册在i2c适配器注册之后。
2、加载一个内核模块,在模块中完成i2c适配器注册,该方法是适配器动态注册,注意必须保证i2c驱动和i2c设备注册在i2c适配器注册之后

i2c适配器代表i2c外设,因此其要先与i2c驱动和设备注册



i2c适配注册方法、例程
1、内核模块的方法注册
下面简单例程,以说明情况为主,不做i2c适配器算法具体实现

#define DEBUG
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#include
#include
#include
int GpioI2cDataOpt(struct i2c_adapter *adapter,struct i2c_msg *msg,int num)
{
printk("do a GpioI2cDataOpt\n");
return 1;
}
struct i2c_algorithm GpioI2cOpt=
{
.master_xfer=GpioI2cDataOpt
};
struct i2c_adapter SocI2cAdapter=
{
.owner=THIS_MODULE,
.algo=&GpioI2cOpt,
.name="SocI2cAdapter"
};

static int __init I2cAdapterInit(void)
{
i2c_add_adapter(&SocI2cAdapter);
return 0;
}
static void __exit I2cAdapterExit(void)
{
i2c_del_adapter(&SocI2cAdapter);
}

module_init(I2cAdapterInit);
module_exit(I2cAdapterExit);
MODULE_AUTHOR("xxxx");
MODULE_DESCRIPTION("xxx i2c adapter register");
MODULE_LICENSE("GPL");


关键在于struct i2c_adapter 结构体实例化以及i2c_algorithm.master_xfer实例化
i2c_add_adapter是动态分配总线号的注册方法。



2、platform平台总线驱动注册方式

platform总线是虚拟总线,cpu能直接通过总线访问的外设和模块设备挂载到该总线上。platform设备在arch_init阶段被注册,paltform驱动一般不动态加载而是编译进内核,从而来初始化soc外设设备。
1、注册platfrom设备
在kernel/arch/arm/mach-xxx/core.c中

static struct platform_device I2cDev=
{
.name="I2cDev",
.id=-1,
};
定义一个名为I2cDev的platform设备。
然后找到平台初始化函数
MACHINE_START(xxx, "xxx")
.boot_params= PLAT_PHYS_OFFSET + 0x100,
.map_io= xxx_map_io,
.init_irq= xxx_gic_init_irq,
.timer= &xxx_timer,
.init_machine= xxx_init,
MACHINE_END

.init_machine= xxx_init,为平台初始化函数

void __init xxx_init(void)
{
xxxx
platform_device_register(&I2cDev);
xxx
}
platform_device_register(&I2cDev); 注册I2cDev platform设备到platform总线,此时驱动还没有注册,因此不会执行probe


2、注册platform驱动
因为platform驱动是为了初始化i2c外设,所以该驱动在内核目录为kernel/drivers/i2c/busses/下
建立一个i2c-Gpio.c驱动文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int GpioI2cDataOpt(struct i2c_adapter *adapter,struct i2c_msg *msg,int num)
{
printk("do a GpioI2cDataOpt\n");
return 1;
}
struct i2c_algorithm GpioI2cOpt=
{
.master_xfer=GpioI2cDataOpt
};
struct i2c_adapter GpioI2cAdapter=
{
.owner=THIS_MODULE,
.nr=1,
.algo=&GpioI2cOpt,
.name="GpioI2cAdapter"
};
static int xxx_i2c_probe(struct platform_device *pdev)
{
i2c_add_numbered_adapter(&GpioI2cAdapter);
return 0;
}
static int xxx_i2c_remove(struct platform_device *pdev)
{
i2c_del_adapter(&GpioI2cAdapter);
return 0;
}
static struct platform_driver I2cDevDriver = {
.probe= xxx_i2c_probe,
.remove= xxx_i2c_remove,
.driver= {
.owner = THIS_MODULE,
.name = "I2cDev",
},
};
static int __init I2cDevInit(void)
{
return platform_driver_register(&I2cDevDriver);
}
subsys_initcall(I2cDevInit);
static void __exit I2cDevExit(void)
{
platform_driver_unregister(&I2cDevDriver);
}
module_exit(I2cDevExit);
MODULE_DESCRIPTION("xxx I2C Dev driver");
MODULE_AUTHOR("xxx");
MODULE_LICENSE("GPL");

关键在i2c_probe函数,该函数实现i2c适配器的注册功能。




【linux|linux i2c子系统代码分析7 ---i2c适配器注册时机、方法以及例程】

    推荐阅读