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定义了设备的名字用于匹配合适的驱动.
②在init和exit对i2c_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 #include2 #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 */
附上dev驱动程序: at24cxx_dev_1.c
1 #include2 #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 */
二.创建已经能被识别的设备
前面我们已经涉及到了,和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 #include2 #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 */
附上dev驱动程序: at24cxx_dev_2.c
1 #include2 #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 */
三.创建设备的第三种方法,用户空间创建
相对于前面两种方法来说,这第三种方法却是相对简单,并且不需要写设备程序,只需要加载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控制器再哪个适配器上,此时我们该如何写驱动程序呢?
答:去class的adapter上去查询
沿用前面第二种方法的驱动程序,我们在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_driver的id_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_type的drv链表,并且从dev链表里取出能够匹配的i2c_client并调用probe,driver_register
②对于每一个适配器,调用__process_new_driver
对于每一个适配器,调用它的函数确定address_list里的设备是否存在
如果存在,再调用detect进一步确定,设置,然后i2c_new_device
前三种都是比较简单的,最后一种很复杂,内核的文档中也告诉我们,尽量使用前三种方法去实现,最后一种方法不是是万不得已尽量不要用.
附上drv驱动程序: at24cxx_drv_4.c
1 #include2 #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 */
附上dev驱动程序: at24cxx_dev_4.c
1 #include2 #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 */