Lover雪儿
想念时,就看看天空,无论距离有多远,我们总在同一片天空下!

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

2015-05-3 Lover雪儿


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

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

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


.一个简单的i2c驱动

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

地址:http://www.cnblogs.com/lihaiyan/p/4336165.html


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_adapt
22     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 <linux/kernel.h>
 2 #include <linux/module.h>
 3 #include <linux/platform_device.h>
 4 #include <linux/i2c.h>
 5 #include <linux/err.h>
 6 #include <linux/slab.h>
 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_client
59 2.右边注册一个驱动 i2c_driver
60 3.比较他们的名字,如果相同,则调用probe函数
61 4.在probe函数里,register_chrdev
62 */
at24cxx_drv_1.c

 


附上dev驱动程序: at24cxx_dev_1.c

 1 #include <linux/kernel.h>
 2 #include <linux/module.h>
 3 #include <linux/platform_device.h>
 4 #include <linux/i2c.h>
 5 #include <linux/i2c-dev.h>
 6 #include <mach/i2c.h>
 7 #include <linux/err.h>
 8 #include <linux/slab.h>
 9 
10 //单板结构体,用于存放设备的硬件信息
11 static struct i2c_board_info at24cxx_info = {
12         I2C_BOARD_INFO("at24c08",0x50),        //注意这个名字 1010000
13 };
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_adapt
31     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_client
46 2.右边注册一个驱动 i2c_driver
47 3.比较他们的名字,如果相同,则调用probe函数
48 4.在probe函数里,register_chrdev
49 */
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 //一些用于试探是否存在的id
3 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_adapt
27     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 <linux/kernel.h>
 2 #include <linux/module.h>
 3 #include <linux/platform_device.h>
 4 #include <linux/i2c.h>
 5 #include <linux/err.h>
 6 #include <linux/slab.h>
 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_client
59 2.右边注册一个驱动 i2c_driver
60 3.比较他们的名字,如果相同,则调用probe函数
61 4.在probe函数里,register_chrdev
62 */
at24cxx_drv_2.c

 


附上dev驱动程序: at24cxx_dev_2.c

 1 #include <linux/kernel.h>
 2 #include <linux/module.h>
 3 #include <linux/platform_device.h>
 4 #include <linux/i2c.h>
 5 #include <linux/i2c-dev.h>
 6 #include <mach/i2c.h>
 7 #include <linux/err.h>
 8 #include <linux/slab.h>
 9 
10 
11 static struct i2c_client *at24cxx_client;
12 //一些用于试探是否存在的id
13 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_adapt
41     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_client
56 2.右边注册一个驱动 i2c_driver
57 3.比较他们的名字,如果相同,则调用probe函数
58 4.在probe函数里,register_chrdev
59 */
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函数实现进一步确认设备存在与否

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

博文地址:http://www.cnblogs.com/lihaiyan/p/4452875.html

也可以把这种方法成为旧方法,它是再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->type
10     */
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     }else
19         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 <linux/kernel.h>
 2 #include <linux/module.h>
 3 #include <linux/platform_device.h>
 4 #include <linux/i2c.h>
 5 #include <linux/err.h>
 6 #include <linux/slab.h>
 7 #include <linux/init.h>
 8 #include <linux/jiffies.h>
 9 #include <linux/hwmon.h>
10 #include <linux/hwmon-sysfs.h>
11 #include <linux/mutex.h>
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_data
17 
18 static int at24cxx_detect(struct i2c_client *client, int kind,struct i2c_board_info *info)
19 {
20     /*    能运行到这里,标识该addr的设备是存在的,但是有些设备单凭地址无法分辨
21         (设备地址可能完全一样,还需进一步读写i2c来分辨是哪一款芯片)
22         detect就是用来进一步分辨芯片设备是哪一款并且设置info->type
23     */
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     }else
32         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_client
94 2.右边注册一个驱动 i2c_driver
95 3.比较他们的名字,如果相同,则调用probe函数
96 4.在probe函数里,register_chrdev
97 */
at24cxx_drv_4.c

 


附上dev驱动程序: at24cxx_dev_4.c

 1 #include <linux/kernel.h>
 2 #include <linux/module.h>
 3 #include <linux/platform_device.h>
 4 #include <linux/i2c.h>
 5 #include <linux/i2c-dev.h>
 6 #include <mach/i2c.h>
 7 #include <linux/err.h>
 8 #include <linux/slab.h>
 9 
10 
11 static struct i2c_client *at24cxx_client;
12 //一些用于试探是否存在的id
13 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-adapter
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_adapt
41     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_client
56 2.右边注册一个驱动 i2c_driver
57 3.比较他们的名字,如果相同,则调用probe函数
58 4.在probe函数里,register_chrdev
59 */
at24cxx_dev_4.c

 

 

posted on 2015-05-04 07:14  Lover雪儿  阅读(590)  评论(0编辑  收藏  举报