虽然Linux中有了自己的I2C模块,但是对于一些外设需要通过I2C来设置寄存器,Linux中的I2C模块就不那么灵活了,这里主要说明了如何利用已有的总线驱动自己编写设备驱动来实现I2C的通信。
I2C通信的主要手段是使用i2c_client这个结构体,只要获得了与i2c控制器对应的i2c_client结构体指针,就能够操纵I2C总线。获得这个结构体的方法是使用两个函数:
i2c_get_adapter(int index); 和 i2c_new_device(i2c_adapter* ,i2c_board_info*);
这两个函数都是i定义在/drivers/i2c/i2c-core.c中的,目的是在不知道板载注册的I2C模块的情况下获得I2C控制器指针。使用方法参看这篇博客,说得很好:
http://blog.csdn.net/yuanlulu/article/details/6557901
美中不足的是这篇博客没有给出示例,这里给出一个示例说明这两个东西怎么使用:
struct i2c_dev_t {
struct cdev dev;
};
/*Global Variables*/
static struct i2c_dev_t* global_devp;
static dev_t i2cdev_no;
static struct i2c_board_info i2c_info = {
I2C_BOARD_INFO("myi2c",0xa0>>1),
};
static struct i2c_client* my_I2C_Client;
static int __init i2c_dev_init(void){
int ret = 0;
int err = 0;
struct i2c_adapter* myI2cAdapter;
printk("i2c_dev_init is called!");
/*Register cdev*/
if( alloc_chrdev_region(&i2cdev_no,0,1,"i2cEEPROM")){
printk("%s failed register dev_t",__func__);
return -1;
}
global_devp = kmalloc(sizeof(struct i2c_dev_t),GFP_KERNEL);
if(global_devp == 0){
/*申请失败*/
unregister_chrdev_region(i2cdev_no,1);
return -1;
}
memset(global_devp,0,sizeof(struct i2c_dev_t));
global_devp->dev.owner = THIS_MODULE;
cdev_init(&global_devp->dev,&i2cdev_fopt);
err = cdev_add(&global_devp->dev,i2cdev_no,1);
if(err){
printk("%s failed add cdev",__func__);
return -1;
}
//Get property i2c_client
myI2cAdapter = i2c_get_adapter(0);
my_I2C_Client = i2c_new_device(myI2cAdapter,&i2c_info);
if(my_I2C_Client == 0){
printk("%s failed create i2c client",__func__);
return -1;
}
i2c_put_adapter(myI2cAdapter);
printk("%s succeed!",__func__);
printk("clinet addr is %x",my_I2C_Client->addr);
return 0;
}
static void __exit i2c_dev_exit(void){
cdev_del(&global_devp->dev);
kfree(global_devp);
unregister_chrdev_region(i2cdev_no,1);
i2c_unregister_device(my_I2C_Client);
}
i2c_board_info给出了外设地址(低七位为外设地址,因为在i2c_xfer里面会把这个地址左移一位添加操作字),这样就不用使用ioctl来设置外设地址了,在exit里面注意要注销已经注册的i2c设备。
感觉这样做比较简单,就没有i2c_driver什么事情了~只把系统给的模块调入就行。