Linux i2c驱动(eeprom 读写)
来源:互联网 发布:淘宝上为什么没有熙然 编辑:程序博客网 时间:2024/05/17 01:55
一、M24256简介
1、256 Kbit Serial I²C Bus EEPROM
2、Compatible with I2C Extended Addressing
3、Two Wire I2C Serial Interface
4、Supports 400 kHz Protocol
5、 Hardware Write Control
6、 BYTE and PAGE WRITE (up to 64 Bytes)
7、 RANDOM and SEQUENTIAL READ Modes
8、 Automatic Address Incrementing
9、管脚定义
二、M24256读写时序
1、写page时序
2、读page时序
三、i2c驱动
#include <linux/kernel.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/i2c.h>#include <linux/i2c-dev.h>#include <linux/platform_device.h>#include <asm/uaccess.h>#include <asm/atomic.h>#define EEPROM_MAJOR 247#define EEPROM_I2C_MINORS 1#define EEPROM_NAME "eeprom"#define I2C_EEPROM_ADDR (0x54 << 1)#define I2C_EEPROM_ID 777#define EEPROM_BANK_SIZE 64#define I2C_NAME(x) (x)->name#define SET_EEPROM_PAGE_ADDR 1#define EEPROM_MAX_ADDR 0x7fff /* 256Kbit = 32Kbyte */static DEFINE_SPINLOCK(i2c_dev_array_lock);static struct i2c_driver eeprom_driver;static struct i2c_dev *i2c_dev_array[EEPROM_I2C_MINORS]= {NULL};struct i2c_dev{ int minor; struct i2c_adapter *adap; struct i2c_client *client; atomic_t busy; unsigned short page_address;};static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap){ struct i2c_dev *i2c_dev = NULL; if(adap == NULL) { printk("invalid parameter,adap == NULL\n"); return NULL; } if( adap->nr >= EEPROM_I2C_MINORS) { printk("invalid parameter,adap->nr = %d\n",adap->nr); return NULL; } i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL); if(i2c_dev == NULL) { printk("kzalloc i2c_dev error \n"); return NULL; } spin_lock(&i2c_dev_array_lock); if (i2c_dev_array[adap->nr] != NULL) { spin_unlock(&i2c_dev_array_lock); printk("eeprom already has a device assigned to this adapter\n"); goto exit; } i2c_dev->minor = adap->nr; i2c_dev_array[adap->nr] = i2c_dev; spin_unlock(&i2c_dev_array_lock); return i2c_dev;exit: kfree(i2c_dev); return NULL;}static int eeprom_detect_client(struct i2c_adapter *adapter, int address,int kind){ struct i2c_client *client = NULL; struct i2c_dev *i2c_dev = NULL; char *dname = NULL; int ret = -1; printk("detecte eeprom client on address 0x%x\n",address << 1); if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) { printk("i2c check functionality failed\n"); return -1; } client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); if (client == 0) { return -ENOMEM; } client->addr = address; client->adapter = adapter; client->driver = &eeprom_driver; client->flags = 0; if (client->addr == (I2C_EEPROM_ADDR >> 1)) { dname = EEPROM_NAME; } else { printk(" detect client: i2c addr error addr = 0x%X \n",client->addr); kfree(client); return -1; } strlcpy(I2C_NAME(client), dname, sizeof(I2C_NAME(client))); ret = i2c_attach_client(client); if (ret != 0) { printk(" detect client: i2c_attach_client(),ret = %d \n",ret); kfree(client); return ret; } i2c_dev = get_free_i2c_dev(adapter); if (i2c_dev == NULL) { kfree(client); return -1; } printk("eeprom adapter [%s] registered as minor %d\n",adapter->name, i2c_dev->minor); i2c_dev->adap = adapter; i2c_dev->client = client; atomic_set(&(i2c_dev->busy),1); return 0;}static unsigned short normal_i2c[] = {I2C_EEPROM_ADDR >> 1, I2C_CLIENT_END};static unsigned short ignore = I2C_CLIENT_END;static struct i2c_client_address_data addr_data ={ .normal_i2c = normal_i2c, .probe = &ignore, .ignore = &ignore,};static int return_i2c_dev(struct i2c_dev *i2c_dev){ if(i2c_dev == NULL) { printk("invalid parameter,i2c_dev == NULL\n"); return -1; } if(i2c_dev->minor >= EEPROM_I2C_MINORS) { printk("invalid parameter,i2c_dev->minor = %d\n",i2c_dev->minor); return -1; } spin_lock(&i2c_dev_array_lock); i2c_dev_array[i2c_dev->minor] = NULL; spin_unlock(&i2c_dev_array_lock); kfree(i2c_dev); return 0;}static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap){ struct i2c_dev *i2c_dev = NULL; if(adap == NULL) { printk("invalid parameter,adap == NULL\n"); return NULL; } if(adap->nr >= EEPROM_I2C_MINORS) { printk("invalid parameter,adap->nr = %d\n",adap->nr); return NULL; } spin_lock(&i2c_dev_array_lock); if ((i2c_dev_array[adap->nr] != NULL) && (i2c_dev_array[adap->nr]->adap == adap)) { i2c_dev = i2c_dev_array[adap->nr]; } spin_unlock(&i2c_dev_array_lock); return i2c_dev;}static int eeprom_attach_adapter(struct i2c_adapter *adap){ printk("start probe for adapter %s (0x%x)\n",I2C_NAME(adap), adap->nr); return i2c_probe(adap, &addr_data, &eeprom_detect_client);}static int eeprom_detach_client(struct i2c_client *client){ struct i2c_dev *i2c_dev = NULL; int ret = -1; if(client == NULL) { printk("invalid parameter,client == NULL\n"); return -1; } i2c_dev = i2c_dev_get_by_adapter(client->adapter); if(i2c_dev == NULL) { printk("invalid parameter,i2c_dev == NULL\n"); return -1; } return_i2c_dev(i2c_dev); ret = i2c_detach_client(client); if (ret != 0) { printk("i2c_detach_client() error,ret == %d\n",ret); return ret; } kfree(client); printk("eeprom detach client success\n"); return 0;}static struct i2c_driver eeprom_driver ={ .driver = { .name = "eeprom_driver", }, .id = I2C_EEPROM_ID, .attach_adapter= eeprom_attach_adapter, .detach_client= eeprom_detach_client,};static struct i2c_dev *i2c_dev_get_by_minor(unsigned index){ struct i2c_dev *i2c_dev = NULL; if(index >= EEPROM_I2C_MINORS) { printk("invalid parameter,index = %d\n",index); return NULL; } spin_lock(&i2c_dev_array_lock); i2c_dev = i2c_dev_array[index]; spin_unlock(&i2c_dev_array_lock); return i2c_dev;}static inline int eeprom_read_byte(struct i2c_client *client, u8 reg){ if (client == NULL) { printk("invalid parameter,client == NULL\n"); return -1; } return i2c_smbus_read_byte_data(client, reg);}static inline int eeprom_write_byte(struct i2c_client *client, u8 reg, u8 value){ int ret = -1; if (client == NULL) { printk("invalid parameter,client == NULL\n"); return -1; } ret = i2c_smbus_write_byte_data(client, reg, value); if(ret != 0) { printk("eeprom write addr:0x%x,name:%s,reg:0x%x,value0x%x\n",client->addr,client->name,reg,value); } return ret;}static int eeprom_open(struct inode *node,struct file *file){ unsigned int minor = iminor(node); struct i2c_dev *i2c_dev = NULL;printk("eeprom open\n"); i2c_dev = i2c_dev_get_by_minor(minor); i2c_dev->page_address = 0; set_wc_bit_high(); /* 写保护信号拉高 */ file->private_data = i2c_dev; if (atomic_dec_and_test(&i2c_dev->busy) == 0) { atomic_inc(&i2c_dev->busy); return -EBUSY; /* already open */ }return 0;}static int eeprom_release(struct inode *node,struct file *file){ struct i2c_dev * i2c_dev = (struct i2c_dev *)file->private_data; if(i2c_dev == NULL) { printk("invalid parameter,i2c_dev == NULL\n"); return -1; } atomic_inc(&i2c_dev->busy); file->private_data = NULL; printk("eeprom release\n"); return 0;}static ssize_t eeprom_read(struct file *filp,char *buf, size_t count, loff_t *offset){ struct i2c_dev *i2c_dev = (struct i2c_dev *)filp->private_data; struct i2c_client *client = i2c_dev->client; int ret = -1; char my_buf[EEPROM_BANK_SIZE] = {0,}; char message[2] = {0,}; if(i2c_dev->page_address + count > EEPROM_MAX_ADDR) { printk("eeprom read address range beyond\n"); i2c_dev->page_address = 0; return -1; } set_wc_bit_low(); /* 写保护信号拉低 */ mdelay(1); message[0] = (u8)(i2c_dev->page_address >> 8); message[1] = (u8)(i2c_dev->page_address); i2c_master_send(client, message, 2); i2c_master_recv(client, my_buf, count); set_wc_bit_high(); /* 写保护信号拉高 */ copy_to_user(buf, (void *)my_buf, count); return count;}static ssize_t eeprom_write(struct file *file, const char __user *buf, size_t count, loff_t *offset){ struct i2c_dev *i2c_dev = (struct i2c_dev *)file->private_data; struct i2c_client *client = i2c_dev->client; int ret = -1; char message[EEPROM_BANK_SIZE + 2] = {0,}; if(i2c_dev->page_address + count > EEPROM_MAX_ADDR) { printk("eeprom write address range beyond\n"); i2c_dev->page_address = 0; return -1; } if(count > EEPROM_BANK_SIZE) { count = EEPROM_BANK_SIZE; } message[0] = (u8)(i2c_dev->page_address >> 8); message[1] = (u8)(i2c_dev->page_address); ret = copy_from_user(&message[2], (void *)buf, count); if(ret != 0) { printk("eeprom write copy_from_user failed\n"); return -1; } set_wc_bit_high(); /* 写保护信号拉低 */ mdelay(1); i2c_master_send(client, message, count + 2); mdelay(1); set_wc_bit_high(); /* 写保护信号拉高 */ return count;}static int eeprom_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg){ struct i2c_dev * i2c_dev = (struct i2c_dev *)file->private_data; if(i2c_dev == NULL) { printk("invalid parameter,i2c_dev == NULL\n"); return -1; } switch(cmd) { case SET_EEPROM_PAGE_ADDR: if(arg > EEPROM_MAX_ADDR) { printk("eeprom address range beyond\n"); i2c_dev->page_address = 0; return -1; } else { i2c_dev->page_address = (unsigned short)arg; } break; default: printk("eeprom cmd error!\n"); return -1; } return 0;}static struct file_operations eeprom_fops ={ .owner = THIS_MODULE, .open = eeprom_open, .release = eeprom_release, .read = eeprom_read, .write = eeprom_write, .ioctl = eeprom_ioctl,};static int __init eeprom_init(void){ int ret = -1; ret = register_chrdev(EEPROM_MAJOR, EEPROM_NAME, &eeprom_fops); if (ret != 0) { printk("%s: can't get major %d", EEPROM_NAME, EEPROM_MAJOR); goto exit; } memset(i2c_dev_array, 0 ,sizeof(i2c_dev_array)); ret = i2c_add_driver(&eeprom_driver); if (ret != 0) { printk("i2c add eeprom_driver error!\n"); goto unregister_chrdev; } return 0;unregister_chrdev: unregister_chrdev(EEPROM_MAJOR, EEPROM_NAME);exit: return ret;}static void __exit eeprom_exit(void){ i2c_del_driver(&eeprom_driver); unregister_chrdev(EEPROM_MAJOR, EEPROM_NAME);}MODULE_DESCRIPTION("eeprom driver");MODULE_LICENSE("GPL");module_init(eeprom_init);module_exit(eeprom_exit);
- Linux i2c驱动(eeprom 读写)
- Linux i2c驱动(eeprom 读写)
- linux I2C读写EEPROM
- S3C2440 Linux下的I2C驱动以及I2C体系下对EEPROM进行读写操作。
- Linux下使用I2C总线读写 EEPROM(读写i2c从设备通用程序)
- Linux下使用I2C总线读写 EEPROM(读写i2c从设备通用程序)
- Linux下使用I2C总线读写 EEPROM(读写i2c从设备通用程序)
- Linux下使用I2C总线读写 EEPROM(读写i2c从设备通用程序)
- I2C总线的EEPROM(24C08)Linux驱动
- TQ2440 linux i2c驱动——at24c02(eeprom)
- I2C总线的EEPROM(24C08)Linux驱动
- Zynq平台下linux的I2C驱动(RTC+EEPROM)
- Zynq平台下linux的I2C驱动(RTC+EEPROM)
- linux下通过i2c总线读写EEPROM
- linux i2c-eeprom-at24c02字符驱动问题
- Linux驱动之eeprom,I2C,SPI
- 58 linux i2c设备驱动之eeprom驱动
- STM32F10x_模拟I2C读写EEPROM
- matlab 最基础的数字图像处理
- PropertyGrid 中 类属性定义
- Jmockit实用技巧
- [宏]_IO, _IOR, _IOW, _IOWR 宏的用法与解析
- 关于Eclipse 安装ADT时出现Duplicate的解决
- Linux i2c驱动(eeprom 读写)
- MYSQL 常识系统回顾和整理【建表、索引、数据同步、高效查询、排错原则】
- 如何有效的利用时间
- 常用转义字符
- Happy团精彩博文汇总(不断更新)
- WebSocket(5)-- WebSocket Server
- SDP协议详细介绍
- IOS编译选项GCC_THUMB_SUPPORT
- 高性能Web服务器Nginx的配置与部署研究(2)Nginx入门级配置、部署与“Hello World”