Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1245076
  • 博文数量: 105
  • 博客积分: 127
  • 博客等级: 入伍新兵
  • 技术积分: 962
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-29 15:22
文章分类

全部博文(105)

文章存档

2021年(1)

2019年(3)

2018年(1)

2017年(11)

2016年(47)

2015年(32)

2014年(4)

2012年(6)

我的朋友

分类: LINUX

2016-06-04 16:44:54


        与前面普通设备驱动1方法不同,这里的普通设备驱动利用i2c-core.c提供的i2c_transfer方法来实现设备驱动,
而不是普通设备驱动1里面的通过操纵s3c2440的i2c寄存器来与设备通信


 一、采用友善之臂的2.6.32.2内核,需要修改/linux-2.6.32.2/arch/arm/mach-s3c2440/mach-mini2440.c文件

1)添加 #include

2)在static struct platform_device *mini2440_devices[]前添加struct i2c_board_info i2c_devices[]结构体


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. //add  
  2. static struct i2c_board_info i2c_devices[] __initdata={  
  3.     {I2C_BOARD_INFO("at24c08", 0x50), },  
  4. };  
  5. /* devices we initialise */  
  6. static struct platform_device *mini2440_devices[] __initdata = {  
  7.     &s3c_device_usb,  
  8.     &s3c_device_rtc,  
  9.     &s3c_device_lcd,  
  10.     &s3c_device_wdt,  
  11.     &s3c_device_i2c0,//没有修改  
  12.     &s3c_device_iis,  
  13.     &mini2440_device_eth,  
  14.     &s3c24xx_uda134x,  
  15.     &s3c_device_nand,  
  16.     &s3c_device_sdi,  
  17.     &s3c_device_usbgadget,  
  18. };  

3)在mini2440_machine_init(void)函数内添加i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices));函数


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static void __init mini2440_machine_init(void)  
  2. {  
  3. i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices)); //add  
  4.   
  5. #if defined (LCD_WIDTH)  
  6.     s3c24xx_fb_set_platdata(&mini2440_fb_info);  
  7. #endif  
  8.     s3c_i2c0_set_platdata(NULL);  
  9.   
  10.     s3c2410_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);  
  11.   
  12.     s3c_device_nand.dev.platform_data = &friendly_arm_nand_info;  
  13.     s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;  
  14.     platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));  
  15.     s3c_pm_init();  
  16. }  

二、在linux2.6.32.2/drivers/i2c/chips/目录下添加at24c08.c设备驱动文件,并对应的修改Kconfig和Makefile文件


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include    
  2. #include    
  3. #include    
  4. #include    
  5. #include    
  6. #include    
  7. #include    
  8. #include    
  9.   
  10. #define   major  155  
  11. static  struct  i2c_driver  at24c08_driver;  
  12. static  struct  i2c_adapter  *at24c08_adapter;  
  13. static  unsigned  short  addr;  
  14. static  struct  class  at24c08_cls  =  {  
  15.                     .name =  "at24c08_cls",  
  16.                 };  
  17.   
  18. ssize_t  at24c08_read  (struct  file  *filp,  char  __user  *buf,  size_t  sz,  loff_t  *off)  
  19. {  
  20.     struct  i2c_msg  msg[2];  
  21.     unsigned  char  args,  data;  
  22.   
  23.     if  (sz  !=  1)  
  24.         return  -EINVAL;  
  25.     copy_from_user((void  *)&args,  buf,  1);  
  26.     /* 先传读地址 */  
  27.     msg[0].addr =  addr;  
  28.     msg[0].buf =  &args;  
  29.     msg[0].len =  1;  
  30.     msg[0].flags =  0;  
  31.   
  32.     /* 再 读 */  
  33.     msg[1].addr =  addr;  
  34.     msg[1].buf =  &data;  
  35.     msg[1].len =  1;  
  36.     msg[1].flags =  1; /* 读 */  
  37.     if  (2  ==  i2c_transfer(at24c08_adapter,  msg,  2))  {  
  38.         /* 读成功 */  
  39.         copy_to_user((void  *)buf,  &data,  1);  
  40.         return  1;  
  41.     }  
  42.     else  
  43.         return  -EIO;  
  44. }  
  45.   
  46. ssize_t  at24c08_write  (struct  file  *filp,  const  char  __user  *buf,  size_t  sz,  loff_t  *off)  
  47. {  
  48.     struct  i2c_msg  msg;  
  49.     unsigned  char  args[2];  
  50.   
  51.     copy_from_user((void  *)&args,  buf,  2);  
  52.   
  53.     /* args[0] = addr, args[1] = val */  
  54.     msg.addr  =  addr;  
  55.     msg.buf =  args;  
  56.     msg.len =  2;  
  57.     msg.flags  =  0; /* 写 */  
  58.     if(1  ==  i2c_transfer(at24c08_adapter,&msg,  1))  
  59.         return  2;  
  60.     else  
  61.         return  -EIO;  
  62.   
  63. }  
  64.   
  65. static  struct  file_operations  at24c08_fops  =  {  
  66.     .owner  =  THIS_MODULE,  
  67.     .read    =  at24c08_read,  
  68.     .write  =  at24c08_write,  
  69. };  
  70.   
  71. static  struct  cdev  cdev;  
  72. static  int  at24c08_probe(struct  i2c_client  *client,  const  struct  i2c_device_id  *dev_id)  
  73. {  
  74.     register_chrdev_region(major,  1,  "at24c08");  
  75.     cdev_init(&cdev,  &at24c08_fops);  
  76.     cdev_add(&cdev,  MKDEV(major,  0),  1);  
  77.     class_register(&at24c08_cls);  
  78.     device_create(&at24c08_cls,  NULL,  MKDEV(major,  0),  NULL,  "at24c08_dev");  
  79.     return    0;  
  80. }  
  81.   
  82. static  int  at24c08_remove(struct  i2c_client  *client)  
  83. {  
  84.     device_destroy(&at24c08_cls,  MKDEV(major,  0));  
  85.     class_destroy(&at24c08_cls);  
  86.     cdev_del(&cdev);  
  87.     unregister_chrdev_region(MKDEV(major,  0),  1);  
  88.   
  89.     return    0;  
  90. }  
  91.   
  92. static  int  at24c08_detect(struct  i2c_client  *client,  int  kind,  struct  i2c_board_info  *bd_info)  
  93. {  
  94.     strcpy(bd_info->type,    "at24c08");  
  95.     addr  =  bd_info->addr  =  client->addr;  
  96.     at24c08_adapter  =  client->adapter;  
  97.     return    0;  
  98. }  
  99.   
  100. static  const  struct  i2c_device_id  at24c08_id[]  =  {  
  101.     {"at24c08",  0},  
  102.     {}  
  103. };  
  104.   
  105. static  unsigned  short  ignore[]            =  {  I2C_CLIENT_END  };  
  106.   
  107. static  const  unsigned  short  normal_i2c[]  =  {0x50,  I2C_CLIENT_END};  
  108.   
  109. static  const  struct  i2c_client_address_data  addr_data  =  {  
  110.     .normal_i2c =  normal_i2c,  
  111.     .probe =  ignore,  
  112.     .ignore =  ignore,  
  113. };  
  114. static  struct  i2c_driver  at24c08_driver=  {  
  115.     .probe =  at24c08_probe,  
  116.     .remove =  at24c08_remove,  
  117.     .driver  =  {  
  118.             .name  =  "at24c08",  
  119.             },  
  120.     .id_table =  at24c08_id,  
  121.     .detect =  at24c08_detect,  
  122.     .address_data =  &addr_data,  
  123.     .class      =  I2C_CLASS_HWMON  |  I2C_CLASS_SPD,  
  124. };  
  125.   
  126. static  int  at24c08_init(void)  
  127. {  
  128.     i2c_add_driver(&at24c08_driver);  
  129.     return  0;  
  130. }  
  131.   
  132. static  void  at24c08_exit(void)  
  133. {  
  134.     i2c_del_driver(&at24c08_driver);  
  135.     return  ;  
  136. }  
  137.   
  138. module_init(at24c08_init);  
  139. module_exit(at24c08_exit);  
  140. MODULE_LICENSE("GPL");  
  141. MODULE_AUTHOR("100ask.net Young");  
以上要说明的是为什么insmod at24c08.ko之后会在/dev/目录下自动创建/dev/at24c08_dev文件节点


主要归功于两个函数

static  struct  class  at24c08_cls  =  { .name =  "at24c08_cls", };

class_register(&at24c08_cls);
device_create(&at24c08_cls,  NULL,  MKDEV(major,  0),  NULL,  "at24c08_dev");

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,
可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的
设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

与class_create等价的函数是class_register,只是他们对应的注销函数不同class_unregister和class_destory。


三、在linux2.6.32.2目录下make menuconfig进行内核定制之后再make则会生成i2c-core.ko,i2c-s3c2440.ko,at24c08.ko等文件,
将三个文件都insmod到内核中,在/dev/目录下会自动生成at24c08_dev文件节点,但是在重启之后会消失,因为insmod是动态加载的,
如果在重启后还要有文件节点,则要将加载命令写到启动脚本中去。


转载链接:http://blog.csdn.net/luckywang1103/article/details/16901625

补充:
VGA EDID 读取的驱动


点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/device.h>
  4. #include <linux/platform_device.h>
  5. #include <linux/input.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/irq.h>
  8. #include <linux/fb.h>
  9. #include <linux/init.h>
  10. #include <linux/list.h>
  11. #include <linux/delay.h>
  12. #include <linux/dma-mapping.h>
  13. #include <linux/err.h>
  14. #include <linux/clk.h>
  15. //#include <mach/clock.h>
  16. #include <linux/uaccess.h>
  17. #include <linux/cpufreq.h>
  18. #include <linux/firmware.h>
  19. #include <linux/kthread.h>
  20. #include <linux/regulator/driver.h>
  21. #include <linux/fsl_devices.h>
  22. #include <linux/ipu.h>

  23. #include <linux/console.h>
  24. #include <linux/types.h>

  25. #include <video/mxc_edid.h>
  26. //#include "mxc/mxc_dispdrv.h"

  27. #include <linux/mfd/mxc-hdmi-core.h>
  28. //#include <mach/mxc_hdmi.h>
  29. //#include <mach/hardware.h>
  30. #include <asm/gpio.h>
  31. #include <linux/gpio.h>
  32. #include <linux/i2c.h>
  33. #include <linux/i2c-dev.h>

  34. #define edid_buf_size 256

  35. struct i2c_client *edid_vga_client;
  36. struct device *edid_vga_dev;
  37. static struct class *edid_vga_class;
  38. unsigned char *edid_all_buf;
  39. unsigned int InOrOut;


  40. static const struct of_device_id imx_vga_i2c_match[] = {
  41.     { .compatible = "fsl,imx6-vga-i2c", },
  42.     { /* sentinel */ }
  43. };

  44. static const struct i2c_device_id mxc_vga_i2c_id[] = {
  45.     { "mxc_vga_i2c", 0 },
  46.     {},
  47. };
  48. MODULE_DEVICE_TABLE(i2c, mxc_vga_i2c_id);


  49. static int edid_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num){
  50.     int ret = 0;
  51.     
  52.     ret = i2c_transfer(adap, msgs, num);


  53.     if (ret != num)
  54.     {
  55.          printk(KERN_ERR"edid_i2c_transfer error %d\n",ret);
  56.      InOrOut = false;
  57.        return -EIO;
  58.     }

  59.     InOrOut = true;
  60.     return ret;
  61. }

  62. static int mxc_vga_edid_read(struct i2c_client *client){
  63.     int ret = 0;
  64.     unsigned char offset = 0;
  65.     struct i2c_adapter *adp = client->adapter;

  66.     struct i2c_msg msg[2] = {
  67.         {
  68.         .addr = client->addr,
  69.         .flags = 0,
  70.         .len = 1,
  71.         .buf = &offset,
  72.         }, {
  73.         .addr = client->addr,
  74.         .flags = I2C_M_RD,
  75.         .len = edid_buf_size,
  76.         .buf = edid_all_buf,
  77.         },
  78.     };
  79.     
  80.     ret = edid_i2c_transfer(adp, msg, ARRAY_SIZE(msg));
  81.     return ret;
  82. }

  83. static ssize_t mxc_edid_show_state(struct device *dev, struct device_attribute *attr, char *buf)
  84. {
  85.   int ret;
  86.   int len = 0;
  87.   
  88.   ret = mxc_vga_edid_read(edid_vga_client);
  89.   if (ret <= 0){
  90.      printk("mxc_vga_edid_read error %d\n",ret);
  91.       return ret;
  92.   }
  93.         
  94. #if 0
  95.     for (j = 0; j < edid_buf_size/16; j++) {
  96.         for (i = 0; i < 16; i++)
  97.             len += sprintf(buf+len, "0x%02X ",
  98.                     edid_all_buf[j*16 + i]);
  99.         len += sprintf(buf+len, "\n");
  100.     }
  101. #else
  102.   memcpy(buf, edid_all_buf, edid_buf_size);
  103.   len = edid_buf_size;
  104. #endif

  105.   return len;
  106. }


  107. static ssize_t mxc_rgb_show_state(struct device *dev,
  108.         struct device_attribute *attr, char *buf)
  109. {
  110.   if(InOrOut == false)
  111.         strcpy(buf, "plugout\n");
  112.     else
  113.         strcpy(buf, "plugin\n");

  114.     return strlen(buf);
  115. }

  116. static DEVICE_ATTR(plugin_state, S_IRUGO, mxc_rgb_show_state, NULL);
  117. static DEVICE_ATTR(show_edid, S_IRUGO, mxc_edid_show_state, NULL);



  118. static int mxc_vga_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id){

  119.     int ret;
  120.     edid_vga_client = client;
  121.     InOrOut = false;

  122.     if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
  123.         return -ENODEV;

  124.     edid_all_buf = kmalloc(edid_buf_size, GFP_KERNEL);
  125.     if(edid_all_buf == NULL)
  126.         goto kmalloc_fail;

  127.     edid_vga_class = class_create(THIS_MODULE, "mxc_edid_class");
  128.     if(edid_vga_class == NULL)
  129.         goto class_create_fail;
  130.         
  131.     edid_vga_dev = device_create(edid_vga_class, NULL, MKDEV(I2C_MAJOR, 50), NULL, "mxc_vga_edid");
  132.     if(edid_vga_dev == NULL)
  133.         goto device_create_fail;
  134.         
  135.     ret = device_create_file(edid_vga_dev, &dev_attr_plugin_state);
  136.     if (ret < 0){
  137.         dev_warn(&client->dev, "cound not create sys node for dev_attr_plug_state\n");
  138.         goto device_create_file_fail;
  139.     }
  140.     ret = device_create_file(edid_vga_dev, &dev_attr_show_edid);
  141.     if (ret < 0){
  142.         dev_warn(&client->dev, "cound not create sys node for dev_attr_edid\n");
  143.         goto device_create_file_fail;
  144.     }
  145.     printk("mxc_vga_i2c_probe ok \n");
  146.     return 0;
  147.     
  148.     device_create_file_fail:
  149.         device_destroy(edid_vga_class,MKDEV(I2C_MAJOR, 50));
  150.         device_create_fail:
  151.             class_destroy(edid_vga_class);
  152.     class_create_fail:            
  153.             kfree(edid_all_buf);
  154.     kmalloc_fail:
  155.         printk("mxc_vga_i2c_probe error..\n");
  156.         return -1;            
  157.     
  158. }

  159. static int mxc_vga_i2c_remove(struct i2c_client *client)
  160. {
  161.     device_destroy(edid_vga_class,MKDEV(I2C_MAJOR, 50));
  162.     class_destroy(edid_vga_class);
  163.         kfree(edid_all_buf);

  164.     printk("mxc_vga_i2c_remove_exit finished..\n");
  165.     return 0;
  166. }

  167. static struct i2c_driver mxc_vga_i2c_driver = {
  168.     .driver = {
  169.          .name = "mxc_vga_i2c",
  170.          .owner = THIS_MODULE,
  171.              .of_match_table    = imx_vga_i2c_match,
  172.          },
  173.     .probe = mxc_vga_i2c_probe,
  174.     .remove = mxc_vga_i2c_remove,
  175.     .id_table = mxc_vga_i2c_id,
  176. };

  177. static int __init mxc_vga_i2c_init(void)
  178. {
  179.     return i2c_add_driver(&mxc_vga_i2c_driver);
  180. }

  181. static void __exit mxc_vga_i2c_exit(void)
  182. {
  183.     i2c_del_driver(&mxc_vga_i2c_driver);
  184. }

  185. module_init(mxc_vga_i2c_init);
  186. module_exit(mxc_vga_i2c_exit);

阅读(4536) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~