20150503 imx257下实现I2C驱动的四种方法
发布日期:2021-06-29 14:51:48 浏览次数:2 分类:技术文章

本文共 19654 字,大约阅读时间需要 65 分钟。

20150503 imx257下实现I2C驱动的四种方法

2015-05-3 Lover雪儿

时间过得好快,转眼间五一假期就即将结束了,假期期间,大家都潇洒的去玩了,徒留辛辛苦苦的程序员还是窝在宿舍乖乖的敲着代码...

好啦,开开玩笑,辛酸史每家都有一大本,还是要积极的面对生活!!!

今天我们的任务是简单的入门linux内核下i2c设备驱动分离的四种写法.

.一个简单的i2c驱动

和以前的驱动程序不同,i2c驱动分为drv驱动和dev设备驱动两个文件,不懂的可以参考我以前写的<>以及总线设备驱动模型这些博文

地址:

1.首先是drv驱动的编写at24cxx_drv_1.c:

drv驱动中,其实很简单,就是实现一个i2c_driver结构体,然后在init函数中注册i2c_driver结构体,最后自然是在exit函数中卸载i2c_driver结构体.

定义i2c_driver结构体以及实现相应的函数

1 //probe函数 2 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){ 3     printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__); 4     return 0; 5 } 6 //remove函数 7 static int __devexit at24cxx_remove(struct i2c_client *client) 8 { 9     printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);10     return 0;11 }12 static const struct i2c_device_id at24cxx_id_table[] = {13     {
"at24c08", 0}, //记录了设备的名字,用于去顶后面的驱动是否匹配14 {}15 }; 16 static struct i2c_driver at24cxx_driver = {17 .driver = {18 .name = "LoverXueEr",19 .owner = THIS_MODULE,20 },21 .probe = at24cxx_probe, //探测函数22 .remove = at24cxx_remove, //卸载函数23 .id_table = at24cxx_id_table,24 };

 

可以发现,i2c_driver结构体中总共实现了探测函数probe,用于探测匹配的设备,id_table定义了设备的名字用于匹配合适的驱动.

initexiti2c_driver分别注册和卸载

1 static int at24cxx_drv_init(void) 2 { 3     /* 2.注册i2c_driver*/ 4     i2c_add_driver(&at24cxx_driver); 5     return 0; 6 } 7 static void at24cxx_drv_exit(void) 8 { 9     i2c_del_driver(&at24cxx_driver);10 }

 

2.设备驱动程序编写at24cxx_dev_1.c

在设备驱动中主要是定义了一些设备的具体的信息,比如设备地址啊等等的信息.

在设备驱动中,主要就是I2C控制器(也称适配器)的使用了.

init函数中首先创建一个i2c_adapter控制器结构体,

接着通过格泰i2c_get_adapter获取内核存在的i2c控制器号,这个在/sys/class/i2c-adapter下可以查看,

接着使用i2c_new_device直接创建一个设备,不管设备存在与否,该函数都会强制认为该设备存在.

而如果使用i2c_new_probed_device的话:它和前面不同的是,它一定要对于能够"已经识别出来的设备"(probed_device),才会去创建,否则无法创建.(见下面方法二)

理论描述总是太抽象了,我们来看看程序就懂了.

1 //单板结构体,用于存放设备的硬件信息 2 static struct i2c_board_info at24cxx_info = { 3         I2C_BOARD_INFO("at24c08",0x50),        //注意这个名字 1010000 4 }; 5 static struct i2c_client *at24cxx_client; 6  7 /* 1.分配/设置i2c_driver */ 8 static int at24cxx_dev_init(void) 9 {10     struct i2c_adapter *i2c_adapt;11     printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);12     //创建i2c适配器13     //直接创建设备14     i2c_adapt = i2c_get_adapter(1);        //获得第0个适配器15     if (!i2c_adapt) {16         printk("can't get i2c adapter %d\n",1);17         return -EIO;18     }19     at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info);    //在总线下面创建一个i2c_adapt,强制认为设备存在20     //i2c_new_probed_device:    对于能够"已经识别出来的设备"(probed_device),才会去创建21     i2c_put_adapter(i2c_adapt);            //释放i2c_adapt22     return 0;23 }24 25 static void at24cxx_dev_exit(void)26 {27     if(at24cxx_client)28         i2c_unregister_device(at24cxx_client);29 }

 

3.编译测试

结果如图所示:

附上drv驱动程序: at24cxx_drv_1.c

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 8 9 //probe函数10 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){11 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);12 return 0;13 }14 15 //remove函数16 static int __devexit at24cxx_remove(struct i2c_client *client)17 {18 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);19 return 0;20 }21 22 23 static const struct i2c_device_id at24cxx_id_table[] = {24 { "at24c08", 0},25 {}26 };27 28 static struct i2c_driver at24cxx_driver = {29 .driver = {30 .name = "LoverXueEr",31 .owner = THIS_MODULE,32 },33 .probe = at24cxx_probe,34 .remove = at24cxx_remove,35 .id_table = at24cxx_id_table,36 };37 38 39 /* 1.分配/设置i2c_driver */40 41 static int at24cxx_drv_init(void)42 {43 /* 2.注册i2c_driver*/44 i2c_add_driver(&at24cxx_driver);45 return 0;46 }47 48 static void at24cxx_drv_exit(void)49 {50 i2c_del_driver(&at24cxx_driver);51 }52 53 module_init(at24cxx_drv_init);54 module_exit(at24cxx_drv_exit);55 MODULE_LICENSE("GPL");56 57 /*58 1.左边注册一个设备 i2c_client59 2.右边注册一个驱动 i2c_driver60 3.比较他们的名字,如果相同,则调用probe函数61 4.在probe函数里,register_chrdev62 */
at24cxx_drv_1.c

 

附上dev驱动程序: at24cxx_dev_1.c

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 10 //单板结构体,用于存放设备的硬件信息11 static struct i2c_board_info at24cxx_info = {12 I2C_BOARD_INFO("at24c08",0x50), //注意这个名字 101000013 };14 static struct i2c_client *at24cxx_client;15 16 /* 1.分配/设置i2c_driver */17 static int at24cxx_dev_init(void)18 {19 struct i2c_adapter *i2c_adapt;20 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);21 //创建i2c适配器22 //直接创建设备23 i2c_adapt = i2c_get_adapter(1); //获得第0个适配器24 if (!i2c_adapt) {25 printk("can't get i2c adapter %d\n",1);26 return -EIO;27 }28 at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info); //在总线下面创建一个i2c_adapt,强制认为设备存在29 //i2c_new_probed_device: 对于能够"已经识别出来的设备"(probed_device),才会去创建30 i2c_put_adapter(i2c_adapt); //释放i2c_adapt31 return 0;32 }33 34 static void at24cxx_dev_exit(void)35 {36 if(at24cxx_client)37 i2c_unregister_device(at24cxx_client);38 }39 40 module_init(at24cxx_dev_init);41 module_exit(at24cxx_dev_exit);42 MODULE_LICENSE("GPL");43 44 /*45 1.左边注册一个设备 i2c_client46 2.右边注册一个驱动 i2c_driver47 3.比较他们的名字,如果相同,则调用probe函数48 4.在probe函数里,register_chrdev49 */
at24cxx_dev_1.c

 

.创建已经能被识别的设备

前面我们已经涉及到了,i2c_new_device不同,使用i2c_new_probed_device的话,它会线查看设备是否存在,如果存在的话,才会创建设备.现在我们第二种方法就是使用它来实现.

再前面的程序基础上修改at24cxx_dev_1.c设备驱动程序.drv驱动不用修改.

1.定义一些用于探测的id数组

前面我们说了,它会探测id的设备是否存在,所以,意味着我们这里可以有多个id,并且id号也可以是不存在的,为了保存这些id,自然就需要一个数组来装咯.

程序如下所示:

 

1 static struct i2c_client *at24cxx_client;2 //一些用于试探是否存在的id3 static const unsigned short addr_list[] = {
0x60,0x50,0x70,NULL};

 

 

 

2.init函数中

和前面第一种方法不同的是,

我们此处是在init函数中动态的创建i2c_board_info结构体.

接着就是初始化i2c_board_info结构体,分配设备的名字用于匹配合适的总线.

创建适配器,获取适配器,和前面一样

使用i2c_new_probed_device来创建设备,i2c_new_probed_device,首先会遍历id数组,线测试id设备是否存在,接着就是调用i2c_new_device来创建设备.

动态是否i2c_adapt控制器.

程序如下:

1 /* 1.分配/设置i2c_driver */ 2 static int at24cxx_dev_init(void) 3 { 4     struct i2c_adapter *i2c_adapt; 5     struct i2c_board_info at24cxx_info; 6      7     printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__); 8      9     //初始化i2c_board_info 结构体10     memset(&at24cxx_info, 0, sizeof(struct i2c_board_info));11     strlcpy(at24cxx_info.type,"at24c08",20);12     13     //创建i2c适配器  //直接创建设备14     i2c_adapt = i2c_get_adapter(1);        //获得第1个i2c_bus总线15     if (!i2c_adapt) {16         printk("can't get i2c adapter %d\n",1);17         return -EIO;18     }19     //在总线下面创建一个i2c_adapt,强制认为设备存在20     //at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info);    21     //对于addr_list能够"已经识别出来的设备"(probed_device),才会去创建,i2c_new_device之前,先测试addr_List中的设备是否存在22     at24cxx_client = i2c_new_probed_device(i2c_adapt, &at24cxx_info, addr_list);    23     if(!at24cxx_client)24         return -ENODEV;25     if(i2c_adapt)26         i2c_put_adapter(i2c_adapt);            //释放i2c_adapt27     return 0;28 }29 30 static void at24cxx_dev_exit(void)31 {32     if(at24cxx_client)33         i2c_unregister_device(at24cxx_client);34 }

 

3.编译测试

附上drv驱动程序: at24cxx_drv_2.c

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 8 9 //probe函数10 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){11 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);12 return 0;13 }14 15 //remove函数16 static int __devexit at24cxx_remove(struct i2c_client *client)17 {18 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);19 return 0;20 }21 22 23 static const struct i2c_device_id at24cxx_id_table[] = {24 { "at24c08", 0},25 {}26 };27 28 static struct i2c_driver at24cxx_driver = {29 .driver = {30 .name = "LoverXueEr",31 .owner = THIS_MODULE,32 },33 .probe = at24cxx_probe,34 .remove = at24cxx_remove,35 .id_table = at24cxx_id_table,36 };37 38 39 /* 1.分配/设置i2c_driver */40 41 static int at24cxx_drv_init(void)42 {43 /* 2.注册i2c_driver*/44 i2c_add_driver(&at24cxx_driver);45 return 0;46 }47 48 static void at24cxx_drv_exit(void)49 {50 i2c_del_driver(&at24cxx_driver);51 }52 53 module_init(at24cxx_drv_init);54 module_exit(at24cxx_drv_exit);55 MODULE_LICENSE("GPL");56 57 /*58 1.左边注册一个设备 i2c_client59 2.右边注册一个驱动 i2c_driver60 3.比较他们的名字,如果相同,则调用probe函数61 4.在probe函数里,register_chrdev62 */
at24cxx_drv_2.c

 

附上dev驱动程序: at24cxx_dev_2.c

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 10 11 static struct i2c_client *at24cxx_client;12 //一些用于试探是否存在的id13 static const unsigned short addr_list[] = { 0x60,0x50,0x70,NULL}; 14 15 /* 1.分配/设置i2c_driver */16 static int at24cxx_dev_init(void)17 {18 struct i2c_adapter *i2c_adapt;19 struct i2c_board_info at24cxx_info;20 21 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);22 23 //初始化i2c_board_info 结构体24 memset(&at24cxx_info, 0, sizeof(struct i2c_board_info));25 strlcpy(at24cxx_info.type,"at24c08",20);26 27 //创建i2c适配器  //直接创建设备28 i2c_adapt = i2c_get_adapter(1); //获得第1个i2c_bus总线29 if (!i2c_adapt) {30 printk("can't get i2c adapter %d\n",1);31 return -EIO;32 }33 //在总线下面创建一个i2c_adapt,强制认为设备存在34 //at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info); 35 //对于addr_list能够"已经识别出来的设备"(probed_device),才会去创建,i2c_new_device之前,先测试addr_List中的设备是否存在36 at24cxx_client = i2c_new_probed_device(i2c_adapt, &at24cxx_info, addr_list); 37 if(!at24cxx_client)38 return -ENODEV;39 if(i2c_adapt)40 i2c_put_adapter(i2c_adapt); //释放i2c_adapt41 return 0;42 }43 44 static void at24cxx_dev_exit(void)45 {46 if(at24cxx_client)47 i2c_unregister_device(at24cxx_client);48 }49 50 module_init(at24cxx_dev_init);51 module_exit(at24cxx_dev_exit);52 MODULE_LICENSE("GPL");53 54 /*55 1.左边注册一个设备 i2c_client56 2.右边注册一个驱动 i2c_driver57 3.比较他们的名字,如果相同,则调用probe函数58 4.在probe函数里,register_chrdev59 */
at24cxx_dev_2.c

 

.创建设备的第三种方法,用户空间创建

相对于前面两种方法来说,这第三种方法却是相对简单,并且不需要写设备程序,只需要加载drv驱动程序即可.

使用/sys/class/i2c-adapter/i2c-1/new_device来创建设备

使用/sys/class/i2c-adapter/i2c-1/delete_device来删除设备

从用户空间创建设备:

创建设备:

echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-1/new_device

删除设备

echo 0x50 > /sys/class/i2c-adapter/i2c-1/delete_device

操作过程如下:

root@EasyARM-iMX257 /# cd /sys/class/i2c-adapter/i2c-1

root@EasyARM-iMX257 /sys/class/i2c-adapter/i2c-1# ls

1-0051 power uevent    new_device

delete_device i2c-dev subsystem

root@EasyARM-iMX257 /sys/class/i2c-adapter/i2c-1#

##############################################

创建设备:

echo at24c08 0x50 > /sys/class/i2c-adapter/i2c-1/new_device

删除设备

echo 0x50 > /sys/class/i2c-adapter/i2c-1/delete_device

##############################################

root@EasyARM-iMX257 /sys/class/i2c-adapter/i2c-1# cd /mnt/nfs/module/42_I2C/

加载驱动:

root@EasyARM-iMX257 /mnt/nfs/module/42_I2C# insmod at24cxx_drv.ko

root@EasyARM-iMX257 /mnt/nfs/module/42_I2C#

创建设备: 导致i2c_device_probe被调用

root@EasyARM-iMX257 /mnt/nfs/module/42_I2C# echo at24c08 0x50 > /sys/class/i2c-a

dapter/i2c-1/new_device

i2c-adapter i2c-1: The new_device interface is still experimental and may change in a near future

/home/study/nfs_home/module/42_I2C/at24cxx_drv.c, at24cxx_probe, 11

i2c-adapter i2c-1: new_device: Instantiated device at24c08 at 0x50

删除设备:

root@EasyARM-iMX257 /mnt/nfs/module/42_I2C# echo 0x50 > /sys/class/i2c-adapter/i

2c-1/delete_device

i2c-adapter i2c-1: delete_device: Deleting device at24c08 at 0x50

/home/study/nfs_home/module/42_I2C/at24cxx_drv.c, at24cxx_remove, 18

root@EasyARM-iMX257 /mnt/nfs/module/42_I2C#

##############################################

原因:在drivers/i2c/i2c-core.c

static struct device_attribute i2c_adapter_attrs[] = {

__ATTR(name, S_IRUGO, show_adapter_name, NULL),

__ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device),

__ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device),

{ },

};

当写入new_device 时,导致 i2c_sysfs_new_device被调用,最后知道导致i2c_new_device被调用

当写入delete_device 时,导致 i2c_sysfs_delete_device 被调用,最后知道导致i2c_unregister_device被调用

结果图如下所示:

四.第四种方法detech函数实现进一步确认设备存在与否

第四种方法,其实我们曾经些过了,都差不多,

博文地址:

也可以把这种方法成为旧方法,它是再2.6内核以前使用的,几乎被淘汰了,编写程序也特别复杂,初学者很难懂,之所以在次提及,因为它还是有独特之处的.

前面三种方法,都有一个前提,必须提前指定i2c控制器,定义在/sys/class/i2c-adapter/.

但是,如果我的设备有多个控制器,事先并不知道i2c控制器再哪个适配器上,此时我们该如何写驱动程序呢?

:classadapter上去查询

沿用前面第二种方法的驱动程序,我们在at24cxx_drv_2.c中修改.

写程序是我们可以参考/drivers/hwmon/lm77.c.

1.定义以及实现i2c_driver结构体

和前面的有些不同,此处我们的i2c结构体却增加了三个成员.

.class: 由于事先未确定控制器,此参数用于确定设备在哪一类i2c控制器上去找能够支持的设备.

.detect: i2c_new_probed_device这个函数进行id设备的过滤后,这个函数用来进一步的检测是否能够找到设备,检测设备的类型.最是在的方法就是使用i2c的读写方法向设备进行读写,若是成功则返回0,接着就调用probe函数.

.address_data: 这个参数用于存放我们要探测的设备地址

1 参考lm90.c,/drivers/hwmon/lm77.c lm90.c 2 static const unsigned short normal_i2c[] = {
0x50,0x60,0x70,I2C_CLIENT_END}; 3 4 I2C_CLIENT_INSMOD_1(at24c08); //调用normal_i2c动态创建addr_data 5 6 static struct i2c_driver lm90_driver = { 7 .class = I2C_CLASS_HWMON, //去哪一类I2C控制器查找能支持的设备 8 .driver = { 9 .name = "lm90",10 },11 .probe = lm90_probe,12 .remove = lm90_remove,13 .id_table = lm90_id,14 .detect = lm90_detect, //用这个函数来检测能否找打设备15 .address_data = &addr_data, //这些设备的地址16 };

 

总结一下:class表示的这一类i2c控制器,detect函数来确定能否找到addr_list里面的设备,如果能够找到则调用i2c_new_device注册i2c_client,这会和i2c_driverid_table来比较,如果匹配则调用probe函数.

我们的程序如下所示:

1 static const unsigned short normal_i2c[] = {
0x50,0x60,0x70,I2C_CLIENT_END}; 2 3 I2C_CLIENT_INSMOD_1(at24c08); //调用normal_i2c动态创建addr_data 4 5 static int at24cxx_detect(struct i2c_client *client, int kind,struct i2c_board_info *info) 6 { 7 /* 能运行到这里,标识该addr的设备是存在的,但是有些设备单凭地址无法分辨 8 (设备地址可能完全一样,还需进一步读写i2c来分辨是哪一款芯片) 9 detect就是用来进一步分辨芯片设备是哪一款并且设置info->type10 */11 printk("at24cxx_detect: addr = 0x%x\n",client->addr);12 /* 本来应该发送i2c命令,确定设备确实存在,此处我们简单实现一下 */13 /* 进一步确定是哪一款设备 */14 15 if(client->addr == 0x50){16 strlcpy(info->type, "at24c08", 20);17 return 0;18 }else19 return -ENODEV;20 }21 22 //probe函数23 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){24 //当确定设备存在,切确定了设备类型之后,就会调用这个函数25 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);26 return 0;27 }28 29 //remove函数30 static int __devexit at24cxx_remove(struct i2c_client *client)31 {32 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);33 return 0;34 }35 36 37 static const struct i2c_device_id at24cxx_id_table[] = {38 {
"at24c08", 0},39 {}40 };41 42 43 /*static const struct i2c_client_address_data addr_data = {44 .normal_i2c = normal_i2c,45 };46 */47 static struct i2c_driver at24cxx_driver = {48 .class = I2C_CLASS_HWMON, //去哪一类I2C控制器查找能支持的设备49 .driver = {50 .name = "LoverXueEr",51 .owner = THIS_MODULE,52 },53 .probe = at24cxx_probe,54 .remove = at24cxx_remove,55 .id_table = at24cxx_id_table, 56 .detect = at24cxx_detect, //用这个函数来检测能否找到设备57 .address_data = &addr_data, //这些设备的地址58 };

 

2.init函数中注册结构体

1 static int at24cxx_drv_init(void) 2 { 3     /* 2.注册i2c_driver*/ 4     i2c_add_driver(&at24cxx_driver); 5     return 0; 6 } 7  8 static void at24cxx_drv_exit(void) 9 {10     i2c_del_driver(&at24cxx_driver);11 }

 

3.编译测试

从上图中,我们得知注册驱动的步骤:

at24cxx_driver放入i2c_bus_typedrv链表,并且从dev链表里取出能够匹配的i2c_client并调用probe,driver_register

对于每一个适配器,调用__process_new_driver

对于每一个适配器,调用它的函数确定address_list里的设备是否存在

如果存在,再调用detect进一步确定,设置,然后i2c_new_device

 

前三种都是比较简单的,最后一种很复杂,内核的文档中也告诉我们,尽量使用前三种方法去实现,最后一种方法不是是万不得已尽量不要用.

附上drv驱动程序: at24cxx_drv_4.c

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 13 14 static const unsigned short normal_i2c[] = { 0x50,0x60,0x70,I2C_CLIENT_END}; 15 16 I2C_CLIENT_INSMOD_1(at24c08); //调用normal_i2c动态创建addr_data17 18 static int at24cxx_detect(struct i2c_client *client, int kind,struct i2c_board_info *info)19 {20 /* 能运行到这里,标识该addr的设备是存在的,但是有些设备单凭地址无法分辨21 (设备地址可能完全一样,还需进一步读写i2c来分辨是哪一款芯片)22 detect就是用来进一步分辨芯片设备是哪一款并且设置info->type23 */24 printk("at24cxx_detect: addr = 0x%x\n",client->addr);25 /* 本来应该发送i2c命令,确定设备确实存在,此处我们简单实现一下 */26 /* 进一步确定是哪一款设备 */27 28 if(client->addr == 0x50){29 strlcpy(info->type, "at24c08", 20);30 return 0;31 }else32 return -ENODEV;33 }34 35 //probe函数36 static int __devinit at24cxx_probe(struct i2c_client *client, const struct i2c_device_id *id){37 //当确定设备存在,切确定了设备类型之后,就会调用这个函数38 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);39 return 0;40 }41 42 //remove函数43 static int __devexit at24cxx_remove(struct i2c_client *client)44 {45 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);46 return 0;47 }48 49 50 static const struct i2c_device_id at24cxx_id_table[] = {51 { "at24c08", 0},52 {}53 };54 55 56 /*static const struct i2c_client_address_data addr_data = {57 .normal_i2c = normal_i2c,58 };59 */60 static struct i2c_driver at24cxx_driver = {61 .class = I2C_CLASS_HWMON, //去哪一类I2C控制器查找能支持的设备62 .driver = {63 .name = "LoverXueEr",64 .owner = THIS_MODULE,65 },66 .probe = at24cxx_probe,67 .remove = at24cxx_remove,68 .id_table = at24cxx_id_table, 69 .detect = at24cxx_detect, //用这个函数来检测能否找到设备70 .address_data = &addr_data, //这些设备的地址71 };72 73 74 /* 1.分配/设置i2c_driver */75 76 static int at24cxx_drv_init(void)77 {78 /* 2.注册i2c_driver*/79 i2c_add_driver(&at24cxx_driver);80 return 0;81 }82 83 static void at24cxx_drv_exit(void)84 {85 i2c_del_driver(&at24cxx_driver);86 }87 88 module_init(at24cxx_drv_init);89 module_exit(at24cxx_drv_exit);90 MODULE_LICENSE("GPL");91 92 /*93 1.左边注册一个设备 i2c_client94 2.右边注册一个驱动 i2c_driver95 3.比较他们的名字,如果相同,则调用probe函数96 4.在probe函数里,register_chrdev97 */
at24cxx_drv_4.c

 

附上dev驱动程序: at24cxx_dev_4.c

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 10 11 static struct i2c_client *at24cxx_client;12 //一些用于试探是否存在的id13 static const unsigned short addr_list[] = { 0x60,0x50,0x70,NULL}; 14 15 /* 1.分配/设置i2c_driver */16 static int at24cxx_dev_init(void)17 {18 struct i2c_adapter *i2c_adapt;19 struct i2c_board_info at24cxx_info;20 21 printk("%s, %s, %d\n\n",__FILE__,__FUNCTION__,__LINE__);22 23 //初始化i2c_board_info 结构体24 memset(&at24cxx_info, 0, sizeof(struct i2c_board_info));25 strlcpy(at24cxx_info.type,"at24c08",20);26 27 //创建i2c适配器  //直接创建设备28 i2c_adapt = i2c_get_adapter(1); //获得第1个i2c_bus总线 看 /sys/class/i2c-adapter29 if (!i2c_adapt) {30 printk("can't get i2c adapter %d\n",1);31 return -EIO;32 }33 //在总线下面创建一个i2c_adapt,强制认为设备存在34 //at24cxx_client = i2c_new_device(i2c_adapt,&at24cxx_info); 35 //对于addr_list能够"已经识别出来的设备"(probed_device),才会去创建,i2c_new_device之前,先测试addr_List中的设备是否存在36 at24cxx_client = i2c_new_probed_device(i2c_adapt, &at24cxx_info, addr_list); 37 if(!at24cxx_client)38 return -ENODEV;39 if(i2c_adapt)40 i2c_put_adapter(i2c_adapt); //释放i2c_adapt41 return 0;42 }43 44 static void at24cxx_dev_exit(void)45 {46 if(at24cxx_client)47 i2c_unregister_device(at24cxx_client);48 }49 50 module_init(at24cxx_dev_init);51 module_exit(at24cxx_dev_exit);52 MODULE_LICENSE("GPL");53 54 /*55 1.左边注册一个设备 i2c_client56 2.右边注册一个驱动 i2c_driver57 3.比较他们的名字,如果相同,则调用probe函数58 4.在probe函数里,register_chrdev59 */
at24cxx_dev_4.c

 

 

转载地址:https://ciellee.blog.csdn.net/article/details/106022783 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:20150429 调试分析之 imx257中proc下mymsg及myprintk的实现
下一篇:20150430 调试分析之 根据内核报错信息PC指针分析错误

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月18日 04时57分06秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章