概述
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 <linux/module.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
#include <linux/i2c.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
int GpioI2cDataOpt(struct i2c_adapter *adapter,struct i2c_msg *msg,int num)
{
printk("do a GpioI2cDataOptn");
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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <asm/irq.h>
int GpioI2cDataOpt(struct i2c_adapter *adapter,struct i2c_msg *msg,int num)
{
printk("do a GpioI2cDataOptn");
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 i2c子系统代码分析7 ---i2c适配器注册时机、方法以及例程的全部内容,希望文章能够帮你解决linux i2c子系统代码分析7 ---i2c适配器注册时机、方法以及例程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复