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

2024-08-13  

今天我们的任务是简单的入门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, %dnn',__FILE__,__FUNCTION__,__LINE__);

 4     return 0;

 5 }

 6 //remove函数

 7 static int __devexit at24cxx_remove(struct i2c_client *client)

 8 {

 9     printk('%s, %s, %dnn',__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, %dnn',__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 %dn',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.编译测试


结果如图所示:

afe9cc762fc38f60f41c3efd04746c84_8DcWtWMqzORnEAAAAASUVORK5CYII=.png

附上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, %dnn',__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, %dnn',__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 */


附上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),        //注意这个名字 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, %dnn',__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 %dn',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 */


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



前面我们已经涉及到了,和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, %dnn',__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 %dn',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

 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){

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。