打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
十九、I2C驱动及应用_i2c_add

一、概述

1、Linux主机驱动和外设驱动分离思想

        外设驱动→API→主机驱动→板级逻辑--具体的i2c设备(camera,ts,eeprom等等)
        主机驱动:根据控制器硬件手册,操作具体的寄存器,产生波形。(单片机工程师肯定有强烈的冲动去配置i2c寄存器,产生波形!)。
        linux应用工程师:屏蔽了驱动和硬件。
        linux驱动工程师:屏蔽硬件!提供标准的主机驱动,驱动工程师需要完成“外设驱动”
       内核函数接口:(API)。主机驱动提供给外设驱动的函数接口。
       注册i2c设备:i2c_board_info
       驱动注册和卸载函数以及结构体:i2c_del_driver/i2c_add_driver,i2c_driver
       读写函数和结构体:i2c_transfer,i2c_msg
       这几个函数是放之四海而皆准!
       外设驱动:针对具体的外部器件的代码。
       摄像头以及声卡中i2c用来配置外部设备(声卡和摄像头)→地址和配置的内容都不一样!
板级逻辑:描述主机和外部设备是怎么连接的。

教程中介绍:I2C函数接口(API):
    设备注册:i2c_board_info
    驱动注册函数和结构体:i2c_del_driver/i2c_add_driver,i2c_driver
    读写函数和结构体:i2c_transfer,i2c_msg 

2.设备-i2c设备注册以及设备注册之后的查询方法

        查询i2c设备地址:

ls /sys/bus/i2c/devices/

        怎么和原理图以及外部设备对应:3-0038→I2C_3_SCL(addr:datasheet中查0x38)
        查询i2c设备名称:

cat /sys/bus/i2c/devices/3-0038/name

        menuconfig中去掉触摸的驱动
        Device Drivers  ---> 
        Input device support  --->
        Touchscreens  ---> 
        FT5X0X based touchscreens(去掉)
        

        在arch\arm\mach-exynos\mach-itop4412.c
        添加i2c设备:i2c_devs3[]中添加
        {
                I2C_BOARD_INFO("i2c_test", 0x70>>1),
        },
       cat /sys/bus/i2c/devices/3-0038/name结果是i2c_test    

3.驱动-i2c驱动注册和卸载。

        i2c设备驱动初始化完成-进入probe函数。

        i2c_del_driver/i2c_add_driver:i2c_driver

        module_initlate_initcall:module_init先运行,late_initcall后运行

4.驱动-i2c数据的传输

        i2c_transfer,i2c_msg

  1. struct i2c_msg {
  2.     __u16 addr;     /* slave address  */
  3.     __u16 flags;
  4.     #define I2C_M_RD        0x0001    /* read data, from slave to master */
  5.     __u16 len;         /* msg length                */
  6.     __u8 *buf;         /* pointer to msg data            */
  7. };

        要完成i2c的读,必须要先写再读!写的时候,你要通知从机,你要读哪个寄存器!

二、驱动代码

1、late_initcall(i2c_test_init);

模块延后执行i2c_test_init,在函数中调用i2c_add_driver(&i2c_test_driver);

2、i2c_add_driver(&i2c_test_driver);

将i2c_test_driver驱动添加到I2C总线上。开始调用i2c_test_driver中的i2c_test_probe。

3、i2c_test_probe

匹配我们前面注册的设备:i2c_test,i2c_test_driver驱动开始运行,

4、misc_register(&i2c_dev);

创建成杂项设备。设备名"i2c_control", // 可以在/dev目录下看到

5、i2c_ops:

定义设备操作函数

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/i2c.h>
  4. #include <linux/input.h>
  5. #include <linux/delay.h>
  6. #include <linux/slab.h>
  7. #include <linux/gpio.h>
  8. #include <linux/platform_device.h>
  9. #ifdef CONFIG_HAS_EARLYSUSPEND
  10. #include <linux/earlysuspend.h>
  11. #endif
  12. #include <linux/regulator/consumer.h>
  13. #include <mach/gpio.h>
  14. #include <plat/gpio-cfg.h>
  15. #include <asm/uaccess.h>
  16. #include <linux/miscdevice.h>
  17. static struct i2c_client *this_client;
  18. static int i2c_tes_read_reg(struct i2c_client *client,u8 addr, u8 *pdata) {
  19. u8 buf1[4] = { 0 };
  20. u8 buf2[4] = { 0 };
  21. struct i2c_msg msgs[] = {
  22. {
  23. .addr = client->addr, //0x38
  24. .flags = 0, //写
  25. .len = 1, //要写的数据的长度
  26. .buf = buf1,
  27. },
  28. {
  29. .addr = client->addr,
  30. .flags = I2C_M_RD,
  31. .len = 1,
  32. .buf = buf2,
  33. },
  34. };
  35. int ret;
  36. buf1[0] = addr;
  37. ret = i2c_transfer(client->adapter, msgs, 2);
  38. if (ret < 0) {
  39. pr_err("read reg (0x%02x) error, %d\n", addr, ret);
  40. } else {
  41. *pdata = buf2[0];
  42. }
  43. return ret;
  44. }
  45. static int i2c_tes_read_fw_reg(struct i2c_client *client,unsigned char *val)
  46. {
  47. int ret;
  48. *val = 0xff;
  49. ret = i2c_tes_read_reg(client,0xa6, val);
  50. printk("ts reg 0xa6 val is %d\n",*val);
  51. return ret;
  52. }
  53. static int i2c_open_func(struct file *filp)
  54. {
  55. return 0;
  56. }
  57. static int i2c_release_func(struct file *filp)
  58. {
  59. return 0;
  60. }
  61. static ssize_t i2c_read_func(struct file *filp, char __user *buffer, size_t count, loff_t *ppos){
  62. int ret;
  63. u8 reg_data;
  64. ret = copy_from_user(&reg_data,buffer,1);
  65. struct i2c_msg msgs[] = {
  66. {
  67. .addr = this_client->addr, //0x38
  68. .flags = 0, //写
  69. .len = 1, //要写的数据的长度
  70. .buf = &reg_data,
  71. },
  72. {
  73. .addr = this_client->addr,
  74. .flags = I2C_M_RD,
  75. .len = 1,
  76. .buf = &reg_data,
  77. },
  78. };
  79. ret = i2c_transfer(this_client->adapter, msgs, 2);
  80. if (ret < 0) {
  81. pr_err("read reg error!\n");
  82. }
  83. ret = copy_to_user(buffer,&reg_data,1);
  84. return ret;
  85. }
  86. static ssize_t i2c_write_func(struct file *filp, char __user *buffer, size_t count, loff_t *ppos){
  87. int ret;
  88. u8 buf[2];
  89. struct i2c_msg msgs[1];
  90. ret = copy_from_user(&buf,buffer,2);
  91. msgs[0].addr = this_client->addr; //0x38
  92. msgs[0].flags = 0; //写
  93. msgs[0].len = 2; //第一个是要写的寄存器地址,第二个是要写的内容
  94. msgs[0].buf = buf;
  95. ret = i2c_transfer(this_client->adapter, msgs, 1);
  96. if (ret < 0) {
  97. pr_err("write reg 0x%02x error!\n",buf[0]);
  98. }
  99. ret = copy_to_user(buffer,buf,1);
  100. return ret;
  101. }
  102. static struct file_operations i2c_ops = {
  103. .owner = THIS_MODULE,
  104. .open = i2c_open_func,
  105. .release= i2c_release_func,
  106. .write = i2c_write_func,
  107. .read = i2c_read_func,
  108. };
  109. static struct miscdevice i2c_dev = {
  110. .minor = MISC_DYNAMIC_MINOR,
  111. .fops = &i2c_ops,
  112. .name = "i2c_control", // 可以在/dev目录下看到
  113. };
  114. static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)
  115. {
  116. unsigned char val;
  117. printk("==%s:\n", __FUNCTION__);
  118. i2c_tes_read_fw_reg(client,&val);
  119. this_client = client;
  120. misc_register(&i2c_dev);
  121. return 0;
  122. }
  123. static int __devexit i2c_test_remove(struct i2c_client *client)
  124. {
  125. i2c_set_clientdata(client, NULL);
  126. misc_deregister(&i2c_dev);
  127. printk("==%s:\n", __FUNCTION__);
  128. return 0;
  129. }
  130. static const struct i2c_device_id i2c_test_id[] = {
  131. { "i2c_test", 0 },
  132. { }
  133. };
  134. static struct i2c_driver i2c_test_driver = {
  135. .probe = i2c_test_probe,
  136. .remove = __devexit_p(i2c_test_remove),
  137. .id_table = i2c_test_id, // 驱动能匹配的设备
  138. .driver = {
  139. .name = "i2c_test", // 可以在sys/bus/i2c/drivers/目录下看到驱动名称
  140. .owner = THIS_MODULE,
  141. },
  142. };
  143. static void i2c_io_init(void)
  144. {
  145. int ret;
  146. ret = gpio_request(EXYNOS4_GPL0(2), "TP1_EN");
  147. if (ret) {
  148. printk(KERN_ERR "failed to request TP1_EN for "
  149. "I2C control\n");
  150. //return err;
  151. }
  152. gpio_direction_output(EXYNOS4_GPL0(2), 1);
  153. s3c_gpio_cfgpin(EXYNOS4_GPL0(2), S3C_GPIO_OUTPUT);
  154. gpio_free(EXYNOS4_GPL0(2));
  155. mdelay(5);
  156. ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3");
  157. if (ret) {
  158. gpio_free(EXYNOS4_GPX0(3));
  159. ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3");
  160. if(ret)
  161. {
  162. printk("ft5xox: Failed to request GPX0_3 \n");
  163. }
  164. }
  165. gpio_direction_output(EXYNOS4_GPX0(3), 0);
  166. mdelay(200);
  167. gpio_direction_output(EXYNOS4_GPX0(3), 1);
  168. s3c_gpio_cfgpin(EXYNOS4_GPX0(3), S3C_GPIO_OUTPUT);
  169. gpio_free(EXYNOS4_GPX0(3));
  170. msleep(300);
  171. }
  172. static int __init i2c_test_init(void)
  173. {
  174. printk("==%s:\n", __FUNCTION__);
  175. i2c_io_init();
  176. printk("==%s:\n", __FUNCTION__);
  177. return i2c_add_driver(&i2c_test_driver);
  178. }
  179. static void __exit i2c_test_exit(void)
  180. {
  181. printk("==%s:\n", __FUNCTION__);
  182. i2c_del_driver(&i2c_test_driver);
  183. }
  184. late_initcall(i2c_test_init);
  185. module_exit(i2c_test_exit);
  186. MODULE_AUTHOR("xunwei_rty");
  187. MODULE_DESCRIPTION("TsI2CTest");
  188. MODULE_LICENSE("GPL");

模块运行结果

 三、应用程序代码

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <sys/ioctl.h>
  7. int main(int argc,char **argv)
  8. {
  9. int fd,ret;
  10. char *i2c_device = "/dev/i2c_control";
  11. unsigned char buffer[2];
  12. printf("open %s!\n",i2c_device);
  13. if((fd = open(i2c_device,O_RDWR|O_NDELAY))<0)
  14. printf("APP open %s failed",i2c_device);
  15. else{
  16. printf("APP open %s success!\n",i2c_device);
  17. }
  18. //读一个数据0xa6
  19. buffer[0] = 0xa6;
  20. ret = read(fd,buffer,1);
  21. if(ret<0)
  22. printf("i2c read failed!\n");
  23. else{
  24. printf("i2c read reg 0xa6 data is 0x%02x!\n",buffer[0]);
  25. }
  26. //01先从0x00读出一个数据,02写一个数据到0x00,03再读出来对比
  27. //01
  28. buffer[0] = 0x00;
  29. read(fd,buffer,1);
  30. printf("i2c read reg 0x00 data is 0x%02x!\n",buffer[0]);
  31. //02
  32. buffer[0] = 0x00;
  33. buffer[1] = 0x40;
  34. ret = write(fd,buffer,2);
  35. if(ret<0){
  36. printf("i2c write failed!\n");
  37. goto exit;
  38. }
  39. //03
  40. buffer[0] = 0x00;
  41. read(fd,buffer,1);
  42. printf("i2c read reg 0x00 data is 0x%02x!\n",buffer[0]);
  43. close(fd);
  44. exit:
  45. close(fd);
  46. return -1;
  47. }

运行应用程序结果

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
linux IIC驱动开发(详)
i2c
Linux i2c子系统应用之Linux ARM嵌入式i2c通信(设备驱动完成i2c从设备寄存器的配...
迅为iTOP-i.MX6ULL开发板I2C驱动程序实现 I2C通信
Linux的i2c驱动详解
驱动模块使用I2C总线范例
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服