I2C总线的EEPROM(24C08)Linux驱动

基于Linux 2.6.30内核

符合Linux驱动架构模型

针对24C08的Page读写做了优化。

完全模拟文件读写方式,支持lseek操作。


这个代码中,包含了设备的地址,在i2c_add_driver时会去探测该地址上是否有设备。

但通常,做板级开发时,i2c_device被放在board文件中,

i2c_device和i2c_driver根据name字段来匹配。


转载请注明出处http://blog.csdn.net/terminalnt/article/details/6582577

代码原创

注:更新的Linux版本内核中,i2c_driver结构体有少许的变化。 


[cpp]  view plain copy
  1. /* 
  2.  * eeprom-24c08.c - eeprom driver for some mostly-compatible I2C chips. 
  3.  * 
  4.  *  Copyright (C) 2011 William Smith 
  5.  * 
  6.  * This program is free software; you can redistribute it and/or modify 
  7.  * it under the terms of the GNU General Public License version 2 as 
  8.  * published by the Free Software Foundation. 
  9.  */  
  10.   
  11. #include <linux/module.h>  
  12. #include <linux/init.h>  
  13. #include <linux/slab.h>  
  14. #include <linux/i2c.h>  
  15. //#include <linux/bcd.h>  
  16. /*New Add */  
  17. #include <linux/cdev.h>  
  18. #include <arm-asm/uaccess.h>  
  19. #include <linux/fs.h>  
  20.   
  21. #include <linux/device.h>  
  22.   
  23.   
  24. #define EEP_MAJOR 236   /* Major number can also be dynamically allocated. */  
  25. #define BNK_SIZE 1024   /* BANK SIZE */  
  26. #define BLK_SIZE 256    /* BLOCK SIZE */  
  27. #define PG_SIZE 16  /* PAGE SIZE */  
  28. #define EEPROM_SLAVE_ADDR0 0x50 /* 7bit. Binary: 1010000 */  
  29. #define EEPROM_SLAVE_ADDR1 0x51 /* 7bit. Binary: 1010001 */  
  30. #define EEPROM_SLAVE_ADDR2 0x52 /* 7bit. Binary: 1010010 */  
  31. #define EEPROM_SLAVE_ADDR3 0x53 /* 7bit. Binary: 1010011 */  
  32.   
  33. #define MAX_RETRYS 30  
  34.   
  35. /* For DEBUG */  
  36. //#define DEBUG_EEP  
  37. #define DEBUG_EEP_R  
  38.   
  39. static int max_retrys_record = 0;  
  40.   
  41. static struct eep_24c08 {  
  42.     struct i2c_client *client[4];   /* I2C client for this eeprom */  
  43.     struct cdev eep_cdev;       /* cdev */  
  44.     dev_t dev_num;              /* dev num */  
  45.     unsigned int cur_ptr;       /* Current File pointer */  
  46. } *eep;  
  47.   
  48. static int eep_open (struct inode *inode, struct file *file)  
  49. {  
  50.     #ifdef DEBUG_EEP  
  51.     printk(KERN_ALERT "EEPROM open\n");  
  52.     #endif  
  53.   
  54.     max_retrys_record = 0;  
  55.   
  56.     eep->cur_ptr = 0;  
  57.     return 0;  
  58. }  
  59.   
  60. static int eep_release (struct inode *inode, struct file *file)  
  61. {  
  62.     #ifdef DEBUG_EEP  
  63.     printk(KERN_ALERT "EEPROM close\n");  
  64.     #endif  
  65.     return 0;  
  66. }  
  67.   
  68. static loff_t eep_llseek(struct file *filp, loff_t off, int whence)  
  69. {  
  70.     #ifdef DEBUG_EEP  
  71.     printk(KERN_ALERT "EEPROM lseek\n");  
  72.     #endif  
  73.       
  74.     switch(whence)  
  75.     {  
  76.         case 0: /* SEEK_SET */  
  77.             eep->cur_ptr = off;  
  78.             break;  
  79.         case 1: /* SEEK_CUR */  
  80.             eep->cur_ptr += off;  
  81.             break;  
  82.         case 2: /* SEEK_END */  
  83.             eep->cur_ptr = BNK_SIZE + off;  
  84.             break;  
  85.         default/* can't happen */  
  86.             return -EINVAL;  
  87.     }  
  88.     if ((eep->cur_ptr < 0) || (eep->cur_ptr > BNK_SIZE)) {  
  89.         printk(KERN_ALERT "EEPROM 'lseek()' call, param mistake\n");  
  90.         eep->cur_ptr = 0;  
  91.         return -1;  
  92.     }  
  93.       
  94.     return eep->cur_ptr;  
  95. }  
  96.   
  97. static int __rw_page(char *buf, int length, int rw)  
  98. {  
  99.     int ret,err=0;  
  100.     int block;  
  101.     unsigned char word_addr;  
  102.     struct i2c_adapter *adap;  
  103.     struct i2c_msg msg[2];  
  104.     int msg_num;  
  105.     unsigned char *buf_tmp=NULL;  
  106.   
  107.     block = eep->cur_ptr / BLK_SIZE;  
  108.     adap = eep->client[block]->adapter;  
  109.     word_addr = eep->cur_ptr % BLK_SIZE;  
  110.     #ifdef DEBUG_EEP  
  111.     printk(KERN_ALERT "__rw_page(): %s: client[%d]->addr = 0x%02X, cur_ptr = %d, block = %d, word_addr = %d\n",   
  112.         (rw?"write":"read"), block, eep->client[block]->addr, eep->cur_ptr, block, word_addr);  
  113.     #endif  
  114.   
  115.     if(rw) {  
  116.         /* write data */  
  117.   
  118.         /* alloc memory for buf_tmp */  
  119.         buf_tmp = kmalloc(length+1, GFP_KERNEL);  
  120.         if (!buf_tmp) {  
  121.             printk(KERN_ALERT "EEPROM kmalloc %d failed\n", length+1);  
  122.             return -ENOMEM;  
  123.         }  
  124.   
  125.         memcpy(buf_tmp+1, buf, length);  
  126.         buf_tmp[0] = word_addr;  
  127.         msg[0].addr = eep->client[block]->addr;  
  128.         msg[0].flags    = 0;      
  129.         msg[0].len  = length+1;  
  130.         msg[0].buf  = buf_tmp;  
  131.     } else {  
  132.         /* read data */  
  133.         msg[0].addr = eep->client[block]->addr;  
  134.         msg[0].flags    = 0;      
  135.         msg[0].len  = 1;  
  136.         msg[0].buf  = &word_addr;  
  137.   
  138.         msg[1].addr = eep->client[block]->addr;  
  139.         msg[1].flags    = I2C_M_RD;   
  140.         msg[1].len  = length;  
  141.         msg[1].buf  = buf;  
  142.     }  
  143.     msg_num = rw?1:2;  
  144.   
  145.     #ifdef DEBUG_EEP  
  146.     printk(KERN_ALERT "msg_num = %d, msg[0]: addr = 0x%02X, flags = %d, len = %d, buf[0~3] = %02X,%02X,%02X,%02X\n",  
  147.             msg_num, msg[0].addr, msg[0].flags, msg[0].len,  
  148.             msg[0].buf[0], msg[0].buf[1], msg[0].buf[2], msg[0].buf[3]);  
  149.     #endif  
  150.   
  151.     ret =  i2c_transfer(adap, msg, msg_num);  
  152.     if (ret<0) {  
  153.         #ifdef DEBUG_EEP  
  154.         printk(KERN_ALERT "i2c_transfer() err %d\n", ret);  
  155.         #endif  
  156.         err = ret;  
  157.         goto exit;  
  158.     } else if (ret<(rw?1:2)) {  
  159.         printk(KERN_ERR "__rw_page(): %s: error, actual write i2c_msg number %d, desire i2c_msg number %d\n",  
  160.                 (rw?"write":"read"), ret, (rw?1:2));  
  161.         err = -EIO;  
  162.         goto exit;  
  163.     }  
  164.   
  165. exit:  
  166.     if (rw)  
  167.         kfree(buf_tmp);  
  168.     return (err?err:length);  
  169. }  
  170.   
  171. static int rw_page(char *buf, int length, int rw)  
  172. {  
  173.     int i;  
  174.     int ret,err=0;  
  175.     char *buf_tmp;  
  176.   
  177.     /* alloc memory for buf_tmp */  
  178.     buf_tmp = kmalloc(length, GFP_KERNEL);  
  179.     if (!buf_tmp) {  
  180.         printk(KERN_ALERT "EEPROM kmalloc %d failed\n", length);  
  181.         return -ENOMEM;  
  182.     }  
  183.   
  184.     for (i=0;i<MAX_RETRYS;i++) {  
  185.         ret = __rw_page(buf, length, rw);  
  186.         if (ret<0)  
  187.             continue;  
  188.         ret = __rw_page(buf_tmp, length, 0);  
  189.         if (ret<0)  
  190.             continue;  
  191.         ret = memcmp(buf, buf_tmp, length);  
  192.         if (ret == 0)     
  193.             break;  
  194.         else {  
  195.             #ifdef DEBUG_EEP  
  196.             printk(KERN_ALERT "rw_page(): %s : memcmp return %d\n", (rw?"write":"read"),  ret);  
  197.             printk(KERN_ALERT "Original buf: ");  
  198.             for (i=0;i<length;i++)  
  199.                 printk(KERN_ALERT "%02X ", buf[i]);  
  200.             printk(KERN_ALERT "\nRecheck buf: ");  
  201.             for (i=0;i<length;i++)  
  202.                 printk(KERN_ALERT "%02X ", buf_tmp[i]);  
  203.             printk(KERN_ALERT "\n");  
  204.             #endif  
  205.         }  
  206.     }  
  207.     #ifdef DEBUG_EEP_R  
  208.     if (i) {  
  209.         printk(KERN_ALERT "Retry %d times.\n", i);  
  210.         if (i > max_retrys_record)  
  211.             max_retrys_record = i;  
  212.     }         
  213.     #endif    
  214.     if (i == MAX_RETRYS) {  
  215.         printk(KERN_ALERT "Reach MAX_RETRYS(%d times) limit.\n", MAX_RETRYS);  
  216.         err = -EAGAIN;  
  217.         goto exit;  
  218.     }  
  219.       
  220. exit:  
  221.     kfree(buf_tmp);  
  222.     return (err?err:length);  
  223. }  
  224.   
  225. static ssize_t eep_rw (char *buf, size_t count, int rw)  
  226. {  
  227.     int ret,err=0;  
  228.     int length = count;  
  229.     int seg;  
  230.     char *buf_tmp=NULL, *buf_cur;  
  231.       
  232.     #ifdef DEBUG_EEP  
  233.     printk(KERN_ALERT "###### eep_rw(), buf=%p, count=%d, rw=%d ######\n",  
  234.             buf, count, rw);  
  235.     #endif  
  236.   
  237.     /* Check param */  
  238.     if (eep->cur_ptr + count > BNK_SIZE) {  
  239.         printk(KERN_ALERT "EEPROM Try to %s over BNK_SIZE: \n"  
  240.                 "\tcur_ptr = %d, count = %d, cur_ptr+count = %d\n",  
  241.                 (rw?"write":"read"), eep->cur_ptr, count, eep->cur_ptr + count);  
  242.         return -EINVAL;  
  243.     }  
  244.     if (rw != 0 && rw != 1) {  
  245.         printk(KERN_ALERT "eep_rw() error, rw param value %d invalid.\n", rw);  
  246.         return -EINVAL;  
  247.     }  
  248.   
  249.     /* alloc memory for buf_tmp */  
  250.     buf_tmp = kmalloc(count, GFP_KERNEL);  
  251.     if (!buf_tmp) {  
  252.         printk(KERN_ALERT "EEPROM kmalloc %d failed\n", count);  
  253.         return -ENOMEM;  
  254.     }  
  255.     buf_cur = buf_tmp;  
  256.   
  257.     if (rw == 1)  
  258.         copy_from_user(buf_tmp, (const char *)buf, count);  
  259.   
  260.     while(length > 0) {  
  261.         seg = length>PG_SIZE? PG_SIZE: length;  
  262.         #ifdef DEBUG_EEP  
  263.         printk(KERN_ALERT "eep_rw(): %s: count = %d, cur_ptr = %d, seg = %d, length = %d\n",  
  264.             (rw?"write":"read"), count, eep->cur_ptr, seg, length);  
  265.         #endif  
  266.         ret = rw_page(buf_cur, seg, rw);  
  267.         if (ret<0) {  
  268.             printk(KERN_ALERT "EEPROM %s error %d\n", (rw?"write":"read"), ret);  
  269.             err = ret;  
  270.             goto exit;  
  271.         }  
  272.         buf_cur += seg;  
  273.         length -= seg;  
  274.         eep->cur_ptr += seg;  
  275.     }  
  276.   
  277.     if (rw == 0)  
  278.         copy_to_user(buf, (const char *)buf_tmp, count);  
  279.   
  280.     #ifdef DEBUG_EEP_R  
  281.     printk(KERN_ALERT "Max retrys record is %d\n", max_retrys_record);  
  282.     #endif  
  283.   
  284. exit:  
  285.     kfree(buf_tmp);  
  286.     return (err?err:count);  
  287. }  
  288.   
  289. static ssize_t eep_read (struct file *file, char __user *buf, size_t count, loff_t *ppos)  
  290. {  
  291.     return eep_rw(buf, count, 0);  
  292. }  
  293.   
  294. static ssize_t eep_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)  
  295. {  
  296.     return eep_rw(buf, count, 1);  
  297. }  
  298.   
  299.   
  300. static struct file_operations eep_fops = {  
  301.     .owner      = THIS_MODULE,  
  302.     .open       = eep_open,  
  303.     .release    = eep_release,  
  304.     .llseek     = eep_llseek,  
  305.     .read       = eep_read,  
  306.     .write      = eep_write,  
  307. };  
  308.   
  309. static const unsigned short normal[] =   
  310.     { EEPROM_SLAVE_ADDR0, EEPROM_SLAVE_ADDR1,   
  311.       EEPROM_SLAVE_ADDR2, EEPROM_SLAVE_ADDR3,   
  312.       I2C_CLIENT_END };  
  313. static const unsigned short ignore[] = { I2C_CLIENT_END };  
  314. static const struct i2c_client_address_data eep_addr_data = {  
  315.         .normal_i2c = normal,  
  316.         .forces     = NULL,  
  317.         .probe      = ignore,  
  318.         .ignore     = ignore,  
  319. };  
  320. /* The higher version of Linux kernel is much more simple. */  
  321.   
  322. /* The device name this driver supported. 
  323.  */  
  324. static const struct i2c_device_id eep_24c08_id[] = {  
  325.     { "eeprom-blk0", EEPROM_SLAVE_ADDR0 },  
  326.     { "eeprom-blk1", EEPROM_SLAVE_ADDR1 },  
  327.     { "eeprom-blk2", EEPROM_SLAVE_ADDR2 },  
  328.     { "eeprom-blk3", EEPROM_SLAVE_ADDR3 },  
  329.     { }  
  330. };  
  331. /* Well, there is some necessary to take a explaination. 
  332.  * Because of the device 24C08 has 8K bits in it, it need 4 addresses. 
  333.  * In the I2C protocal, the SLAVE_ADDR data has only 8 bit, which could only address 256 Bytes(2048 bits). 
  334.  * So 24C08 has 4 different SLAVE_ADDR addresses: 0x50, 0x51, 0x52, 0x53.  
  335.  * Each address is a part that has 2048 bits. Totally, 4 parts have 8192 bits(8K bits). 
  336. */  
  337.   
  338. MODULE_DEVICE_TABLE(i2c, eep_24c08_id);  
  339.   
  340. /* eep_probe - probe method for new-style driver model. 
  341.  * @client: the i2c_client which already been register.  
  342.  * @id:     the i2c_device_id which matchs. 
  343.  
  344.  * When dev and driver are both create and matched. This func will be called to init some specfic data. 
  345.  * Usually, the device's initial step will be done here. 
  346.  * Note: When a driver has N devices, the probe will be called N times. 
  347.  *       For different device, different i2c_device_id will be provided for use in the probe function. 
  348. */  
  349. static int __devinit eep_probe(struct i2c_client *client,  
  350.                   const struct i2c_device_id *id)  
  351. {  
  352.     int i=0;      
  353.       
  354.     #ifdef DEBUG_EEP  
  355.     printk(KERN_ALERT "EEPROM probe\n");  
  356.     #endif  
  357.       
  358.     while (eep_24c08_id[i].driver_data) {  
  359.         if (client->addr == (unsigned short)eep_24c08_id[i].driver_data) {  
  360.             #ifdef DEBUG_EEP  
  361.             printk(KERN_ALERT "probe(): client->addr = 0x%02X, i = %d, eep_24c08_id[%d].driver_data = 0x%02X, eep_24c08_id[%d].name = %s\n",  
  362.                 client->addr, i, i, (unsigned int)eep_24c08_id[i].driver_data, i, eep_24c08_id[i].name);  
  363.             #endif  
  364.             eep->client[i] = client; /* Store the client into eep for further use. */  
  365.                 /* client can also be stored in file->p when open(). */  
  366.         }  
  367.         i++;  
  368.     }  
  369.   
  370.     return 0;  
  371. }  
  372.   
  373. static int __devexit eep_remove(struct i2c_client *client)  
  374. {  
  375.     #ifdef DEBUG_EEP  
  376.     printk(KERN_ALERT "EEPROM remove\n");  
  377.     #endif  
  378.       
  379.     return 0;  
  380. }  
  381.   
  382. /* eep_detect - detect method is called when there is really some device on '@kind' address.  
  383.  @i2c_client:   the temp client device which is given to detect func's use.  
  384.             It is only temp which has not been register. 
  385.  @kind:  indicate the number in i2c_client_address_data for each possible member.  
  386.         only for forces device. Others condition is -1. 
  387.  @i2c_board_info:   the specific infomation's structure to store device's info. 
  388.  
  389.  * This function was called before the real i2c_client is create.  
  390.  * Some special device need a initializion before read/write it, do the init here. 
  391.  * Init the client's infomation, and it need to fill at least the name  
  392.  * of i2c_board_info param for registering which is also the name of client device. 
  393.  * Notice: Its addr member has already beed set. 
  394.  */  
  395. int eep_detect(struct i2c_client *client, int kind, struct i2c_board_info *bd_info)  
  396. {  
  397.     int i=0;  
  398.   
  399.     #ifdef DEBUG_EEP  
  400.     printk(KERN_ALERT "EEPROM detect\n");  
  401.     #endif  
  402.       
  403.     /* There is no need to take action of detect on I2C bus. */  
  404.   
  405.     while (eep_24c08_id[i].driver_data) {  
  406.         if (client->addr == (unsigned short)eep_24c08_id[i].driver_data) {  
  407.             strlcpy(bd_info->type, eep_24c08_id[i].name, I2C_NAME_SIZE);   
  408.                 /* In fact, giving the name is the only thing need to do. */  
  409.             bd_info->flags = 0;  
  410.             #ifdef DEBUG_EEP  
  411.             printk(KERN_ALERT "detect(): i = %d, client->addr = 0x%02X, bd_info->type = %s\n",  
  412.                 i, client->addr, bd_info->type);  
  413.             #endif  
  414.         }  
  415.         i++;  
  416.     }  
  417.   
  418.     /* platform_data should be study later */  
  419.   
  420.     return 0;  
  421. }  
  422.   
  423. static struct i2c_driver eep_driver = {  
  424.     .driver = {  
  425.         .name   = "eeprom-driver",  /* Name */  
  426.         .owner  = THIS_MODULE,  
  427.     },  
  428.     .class          = 1,  
  429.     .probe          = eep_probe,  
  430.     .remove         = __devexit_p(eep_remove),  
  431.     .id_table       = eep_24c08_id,  
  432.     .detect         = eep_detect,  
  433.     .address_data       = &eep_addr_data,  
  434. };  
  435.   
  436. static int __init eeprom_init(void)  
  437. {  
  438.     int err=0;  
  439.       
  440.     eep = kmalloc(sizeof(struct eep_24c08), GFP_KERNEL);  
  441.     if (!eep) {  
  442.         err = -ENOMEM;  
  443.         goto exit;  
  444.     }  
  445.   
  446.     /* Get and register the cdev for eeprom */  
  447.     eep->dev_num = MKDEV(EEP_MAJOR,0);  
  448.     if (register_chrdev_region(eep->dev_num, 1, "eeprom") <0 ) {  
  449.         printk(KERN_ALERT "Can't register device\n");  
  450.         goto exit_free;  
  451.     }  
  452.       
  453.     cdev_init(&eep->eep_cdev, &eep_fops);  
  454.     eep->eep_cdev.owner = THIS_MODULE;  
  455.     eep->eep_cdev.ops = &eep_fops;  
  456.     if (cdev_add(&eep->eep_cdev, eep->dev_num, 1)) {  
  457.         printk(KERN_ALERT "Failed to add cdev of EEPROM\n");  
  458.         goto exit_unregister;  
  459.     }  
  460.   
  461.     /* Register i2c_driver to i2c core */  
  462.     err = i2c_add_driver(&eep_driver);  
  463.     if (err) {  
  464.         printk(KERN_ALERT "Registering I2C driver of EEPROM failed, errno is %d\n", err);  
  465.         goto exit_del_cdev;  
  466.     }  
  467.   
  468.     #ifdef DEBUG_EEP  
  469.     printk(KERN_ALERT "EEPROM Driver Initialized.\n");  
  470.     #endif  
  471.       
  472.     return 0;  
  473.   
  474. exit_del_cdev:  
  475.     cdev_del(&eep->eep_cdev);  
  476. exit_unregister:  
  477.     unregister_chrdev_region(eep->dev_num, 1);  
  478. exit_free:  
  479.     kfree(eep);  
  480. exit:  
  481.     return err;   
  482. }  
  483.   
  484. static void __exit eeprom_exit(void)  
  485. {  
  486.     i2c_del_driver(&eep_driver);  
  487.     cdev_del(&eep->eep_cdev);  
  488.     unregister_chrdev_region(eep->dev_num, 1);  
  489.     kfree(eep);  
  490.   
  491.     #ifdef DEBUG_EEP  
  492.     printk(KERN_ALERT "EEPROM Driver Removed.\n");  
  493.     #endif  
  494. }  
  495.   
  496. module_init(eeprom_init);  
  497. module_exit(eeprom_exit);  
  498.   
  499. MODULE_DESCRIPTION("EEPROM driver for 24C08 and similar chips");  
  500. MODULE_LICENSE("GPL");    

编写客户驱动的方法

在内核中有两种方式的i2c客户驱动的编写方法,一种叫legacy传统方式,另一种是newstyle方式. 前

一种legacy是一种旧式的方法,在2.6内核以后的标准驱动模型编写中逐渐被newstyle方式取代。本文编程实例是基于newstyle方式的来实现at24c02的驱

动。

客户驱动程序开发的一般步骤

(1)注册板载i2c设备信息

 

(2)定义i2c驱动设备id

 

(3)定义i2c_driver结构并完成其相应函数

 

(4)模块初始化时添加/撤销时删除i2c_driver

 

(5)/dev  entry 访问方法 /sysfs访问方法

 

客户设备驱动开发实例

内核为linux-2.6.30.4

基于arm9 S3c2440平台

开发一个at24c02 eeprom的客户驱动

开发一个应用程序访问I2C设备

[cpp]  view plain copy
  1. #include <linux/kernel.h>  
  2. #include <linux/module.h>  
  3. #include <linux/fs.h>  
  4. #include <linux/slab.h>  
  5. #include <linux/init.h>  
  6. #include <linux/list.h>  
  7. #include <linux/i2c.h>  
  8. #include <linux/i2c-dev.h>  
  9. #include <linux/smp_lock.h>  
  10. #include <linux/jiffies.h>  
  11. #include <asm/uaccess.h>  
  12. #include <linux/delay.h>  
  13.   
  14.   
  15. #define DEBUG 1  
  16. #ifdef DEBUG  
  17. #define dbg(x...) printk(x)  
  18. #else   
  19. #define dbg(x...) (void)(0)  
  20. #endif  
  21.   
  22. #define I2C_MAJOR 89  
  23. #define DEVICE_NAME "at24c02"  
  24. static struct class *my_dev_class;  
  25. static struct i2c_client *my_client;  
  26. static struct i2c_driver my_i2c_driver;  
  27.   
  28.   
  29. static struct i2c_device_id my_ids[] = {  
  30.     {"24c01",0x50},  
  31.     {"24c02",0x50},  
  32.     {"24c08",0x50},  
  33.     {}  
  34. };  
  35.   
  36. MODULE_DEVICE_TABLE(i2c,my_ids);  
  37.   
  38. static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  39. {  
  40.     int res;  
  41.     struct device *dev;  
  42.   
  43.     dbg("probe:name = %s,flag =%d,addr = %d,adapter = %d,driver = %s\n",client->name,  
  44.          client->flags,client->addr,client->adapter->nr,client->driver->driver.name );  
  45.   
  46.     dev = device_create(my_dev_class, &client->dev,  
  47.                      MKDEV(I2C_MAJOR, 0), NULL,  
  48.                      DEVICE_NAME);  
  49.     if (IS_ERR(dev))  
  50.     {  
  51.         dbg("device create error\n");  
  52.         goto out;  
  53.     }  
  54.     my_client = client;  
  55.       
  56.     return 0;  
  57. out:  
  58.     return -1;  
  59. }  
  60. static int  my_i2c_remove(struct i2c_client *client)  
  61. {  
  62.   
  63.     dbg("remove\n");  
  64.     return 0;  
  65. }  
  66.   
  67. static ssize_t at24c02_read(struct file *fd, char *buf, ssize_t count, loff_t *offset)  
  68. {  
  69.     char *tmp;  
  70.     int ret;  
  71.     char data_byte;  
  72.     char reg_addr = 0,i;  
  73.     struct i2c_client *client = (struct i2c_client*) fd->private_data;  
  74.     struct i2c_msg msgs[2];  
  75.   
  76.     dbg("read:count = %d,offset = %ld\n",count,*offset);  
  77.     tmp = kmalloc(count,GFP_KERNEL);  
  78.   
  79.     if (!tmp)  
  80.     {  
  81.         dbg("malloc error in read function\n");  
  82.         goto out;  
  83.     }  
  84.   
  85.     reg_addr = *offset;  
  86.     msgs[0].addr = client->addr;  
  87.     msgs[0].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC) ;  
  88.     msgs[0].len = 1;  
  89.     msgs[0].buf = (char *)®_addr;  
  90.       
  91.     msgs[1].addr= client->addr;  
  92.     msgs[1].flags = client->flags & (I2C_M_TEN|I2C_CLIENT_PEC);  
  93.     msgs[1].flags |= I2C_M_RD;  
  94.     msgs[1].len = count;  
  95.     msgs[1].buf = (char*)tmp;  
  96.   
  97.     ret = i2c_transfer(client->adapter,&msgs,2);  
  98.     if (ret != 2)  
  99.         goto out;  
  100.     if (copy_to_user(buf, tmp, count))  
  101.         goto out;  
  102.       
  103.     kfree(tmp);  
  104.     return count;  
  105. out:  
  106.     kfree(tmp);  
  107.     return -1;    
  108.       
  109. }  
  110.   
  111.   
  112. static int at24c02_ioctl(struct file *fd, unsigned int cmd, unsigned long arg)  
  113. {  
  114.     dbg("ioctl code ...\n");  
  115.     return 0;  
  116. }  
  117.   
  118. static ssize_t at24c02_write(struct file *fd, char *buf, ssize_t count, loff_t *offset)  
  119. {  
  120.     int ret,i;  
  121.     char *tmp;  
  122.     int errflg;  
  123.     struct i2c_msg msg;  
  124.     struct i2c_client *client = (struct i2c_client*) fd->private_data;  
  125.     char tmp_data[2];  
  126.   
  127.     dbg("write:count = %d,offset = %ld\n",count,*offset);  
  128.     tmp = kmalloc(count, GFP_KERNEL);  
  129.     if (!tmp)  
  130.         goto out;  
  131.     if (copy_from_user(tmp, buf, count))  
  132.         goto out;  
  133.     msg.addr = client->addr;  
  134.     msg.flags = client->flags & (I2C_M_TEN | I2C_CLIENT_PEC);  
  135.     for (i = 0; i < count; i++) {  
  136.         msg.len = 2;  
  137.         tmp_data[0] = *offset + i;  
  138.         tmp_data[1] = tmp[i];  
  139.         msg.buf = tmp_data;  
  140.         ret = i2c_transfer(client->adapter,&msg,1);  
  141.         if (ret != 1)  
  142.             goto out;  
  143.         msleep(1);  
  144.     }   
  145.     kfree(tmp);  
  146.   
  147.     return ((ret == 1) ? count:ret);  
  148. out:  
  149.     kfree(tmp);  
  150.     return -1;  
  151.       
  152. }  
  153. static int at24c02_open(struct inode *inode, struct file *fd)  
  154. {  
  155.   
  156.     fd->private_data =(void*)my_client;  
  157.     return 0;  
  158.   
  159. }  
  160.   
  161. static int at24c02_release(struct inode *inode, struct file *fd)  
  162. {  
  163.     dbg("release\n");  
  164.     fd->private_data = NULL;  
  165.       
  166.     return 0;     
  167.   
  168. }  
  169.   
  170. static const struct file_operations i2c_fops = {  
  171.     .owner = THIS_MODULE,  
  172.     .open   = at24c02_open,  
  173.     .read  = at24c02_read,  
  174.     .write = at24c02_write,  
  175.     .unlocked_ioctl = at24c02_ioctl,  
  176.     .release = at24c02_release,  
  177. };  
  178.   
  179. static struct i2c_driver my_i2c_driver = {  
  180.     .driver = {  
  181.         .name = "i2c_demo",  
  182.         .owner = THIS_MODULE,  
  183.     },  
  184.     .probe = my_i2c_probe,  
  185.     .remove = my_i2c_remove,  
  186.     .id_table = my_ids,  
  187. };  
  188.   
  189. static int __init my_i2c_init(void)  
  190. {  
  191.     int res;  
  192.       
  193.       
  194.     res = register_chrdev(I2C_MAJOR,DEVICE_NAME,&i2c_fops);  
  195.     if (res)  
  196.     {  
  197.         dbg("register_chrdev error\n");  
  198.         return -1;  
  199.     }  
  200.     my_dev_class = class_create(THIS_MODULE, DEVICE_NAME);  
  201.     if (IS_ERR(my_dev_class))  
  202.     {  
  203.         dbg("create class error\n");  
  204.         unregister_chrdev(I2C_MAJOR, DEVICE_NAME);  
  205.         return -1;  
  206.     }  
  207.     return i2c_add_driver(&my_i2c_driver);  
  208. }  
  209.   
  210. static void __exit my_i2c_exit(void)  
  211. {  
  212.     unregister_chrdev(I2C_MAJOR, DEVICE_NAME);  
  213.     class_destroy(my_dev_class);  
  214.     i2c_del_driver(&my_i2c_driver);  
  215.       
  216. }  
  217.   
  218. MODULE_AUTHOR("itspy<itspy.wei@gmail.com>");  
  219. MODULE_DESCRIPTION("i2c client driver demo");  
  220. MODULE_LICENSE("GPL");  
  221. module_init(my_i2c_init);  
  222. module_exit(my_i2c_exit);  

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值