⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at24c02.c

📁 at24c02驱动和测试程序
💻 C
字号:
/*
 * s3c2440 i2c   
 * Author: liu xiao ming <lxm650@163.com> 
 *  * 本程序以字符设备驱动的方式读写AT24C02,相对于linux标准的i2c驱动要简单得多, * 对于大多数嵌入式应用是比较合适的。读者也应该可以很容易的修改成适合自己需要的驱动。 * * This file is subject to the terms and conditions of the GNU General Public 
 * License.  See the file COPYING in the main directory of this archive 
 * for more details. 
 */  
 
#include <linux/module.h>
#include <linux/fs.h>           
#include <linux/cdev.h>
#include <linux/interrupt.h>    #include <linux/delay.h>#include <asm/hardware/clock.h>
#include <asm/io.h>#include <asm/uaccess.h>     #include <asm/hardware.h>  #include <asm/arch-s3c2410/regs-gpio.h>#include <asm/plat-s3c/regs-iic.h>#undef DEBUG   
#define DEBUG   
#ifdef DEBUG   
#define DPRINTK(x...) {printk(__FUNCTION__);printk("(%d): ",__LINE__);printk(x);}   
#else   
#define DPRINTK(x...) (void)(0)   
#endif   
  #define VERSION_STRING  "at24c02 driver for s3c2440"
#define DEVICE_NAME "s3c2440_i2c"   
#define S3C2440I2C_MAJOR 240    /* 预设的i2c主设备号 */#define CMD		S3C2410_IICCON_ACKEN | S3C2410_IICCON_TXDIV_16 | \				S3C2410_IICCON_IRQEN | S3C2410_IICCON_SCALE(0x0F)#define S3C2440_SLAVE_ADDR	0x10#define SLV_ADDR	0xA0#define I2C_REGS_BASE		0x54000000
static int s3c2440i2c_major = S3C2440I2C_MAJOR;volatile int get_ack;

struct s3c2440i2c_dev {  
    struct cdev cdev;		/* cdev结构体 */
//    struct semaphore lock;	/* 信号量 */
};  
struct s3c2440i2c_dev s3c2440i2c_dev;struct s3c2440i2c_dev *s3c2440i2c_devp; /* 设备结构体指针 */
static void __iomem *base_addr;         /* 物理地址映射成虚拟地址后的基地址指针 */static struct clk   *i2c_clock;         /* 时钟 */void inline clear_pending(void){	unsigned long tmp;	tmp = ioread32(base_addr + S3C2410_IICCON);		tmp &= ~S3C2410_IICCON_IRQPEND;	iowrite32(tmp, base_addr +  S3C2410_IICCON);}/*  * at24c02写函数 * 注意:write_data[0]表示要写入的地址 *		write_data[1]表示要写入的数据 * 每次只能写一个字节 **/  
static ssize_t at24c02_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){  
    char write_data[2];  	get_ack = 0;
      if(count != sizeof(write_data)){  
    /* 输入数据大小错误 */	    DPRINTK("the size of input data must be %d\n", sizeof(write_data));  
        return 0;  
    }  
  
    copy_from_user(&write_data, buffer, count);  	iowrite32(SLV_ADDR, base_addr + S3C2410_IICDS);			// 写从器件地址	iowrite32(0xF0, base_addr + S3C2410_IICSTAT);			// 设置主发送模式并产生起始条件    while(get_ack == 0);									// 等待传送完成	get_ack = 0;	 	iowrite32(write_data[0], base_addr + S3C2410_IICDS);	// 写要写入字节的地址	clear_pending();										// 清除中断pending位    while(get_ack == 0);									// 等待传送完成	get_ack = 0;	iowrite32(write_data[1], base_addr + S3C2410_IICDS);	// 写数据	clear_pending();										// 清除中断pending位    while(get_ack == 0);									// 等待传送完成	get_ack = 0;	iowrite32(0xD0, base_addr + S3C2410_IICSTAT);			// 停止主发送	clear_pending();										// 清除中断pending位	msleep(1);												// 等待停止位起作用	DPRINTK("write data = %d\n", write_data[1]);    return count - 1;  
}  

/*  * at24c02的读函数  * 注意:形参count与原来含义不同,不再表示读出的字节数,而是表示要读的数据地址 * 每次只能读一个字节 **/  
static ssize_t at24c02_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){  
 
    char read_data;	unsigned char read_addr;	read_addr = count;										// 注意count表示要读的地址!	get_ack = 0;	iowrite32(SLV_ADDR, base_addr + S3C2410_IICDS);			// 写从器件地址	iowrite32(0xF0, base_addr + S3C2410_IICSTAT);			// 设置主发送并启动传送	while(get_ack == 0);									// 等待传送完成	get_ack = 0;	 	iowrite32(read_addr, base_addr + S3C2410_IICDS);		// 写要读的地址(伪写操作)	clear_pending();										// 清除中断pending位    while(get_ack == 0);									// 等待传送完成	get_ack = 0;	iowrite32(SLV_ADDR | 0x01, base_addr + S3C2410_IICDS);	// 写从器件地址	iowrite32(0xB0, base_addr + S3C2410_IICSTAT);			// 设置主接收模式并产生起始条件	clear_pending();										// 清除中断pending位    while(get_ack == 0);									// 等待传送完成	get_ack = 0;	iowrite32(0x2F, base_addr + S3C2410_IICCON);			// 不产生应答    while(get_ack == 0);									// 等待接收数据完成	get_ack = 0;	read_data = ioread32(base_addr + S3C2410_IICDS);		// 读取数据内容	iowrite32(0x90, base_addr + S3C2410_IICSTAT);			// 主接收停止并产生停止条件	clear_pending();										// 清除中断pending位	msleep(1);												// 等待停止条件起作用    DPRINTK( "read_data = %d\n", read_data);	copy_to_user(buffer, &read_data, 1);      				// 复制到用户空间   	    return count;  
}  /*文件打开函数*/  
static int at24c02_open(struct inode *inode, struct file *filp)  
{  
//    DPRINTK( "i2c opened\n");  
    return 0;  
}  static int at24c02_release(struct inode *inode, struct file *filp)  
{  
//    DPRINTK( "i2c closed\n");  
    return 0;  
}  static struct file_operations at24c02_fops = {  
    owner:  	THIS_MODULE,  
    open:   	at24c02_open,  
    read:   	at24c02_read,     
    write:  	at24c02_write,  
    release:    at24c02_release,  
};  /* i2c中断服务函数 */static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id){	get_ack = 1;	return IRQ_HANDLED;}/*初始化并注册cdev*/
static void s3c2440i2c_setup_cdev(struct s3c2440i2c_dev *dev, int index)
{
    int err, devno = MKDEV(s3c2440i2c_major, index);
    cdev_init(&dev->cdev, &at24c02_fops);
    dev->cdev.owner = THIS_MODULE;
    dev->cdev.ops = &at24c02_fops;
    err = cdev_add(&dev->cdev, devno, 1);
    if (err)
        DPRINTK("Error %d adding devno%d", err, index);
}int __init at24c02_init(void){    int result;    dev_t devno = MKDEV(s3c2440i2c_major, 0);    /* 申请中断 */
    result = request_irq(IRQ_IIC, s3c24xx_i2c_irq, SA_INTERRUPT, DEVICE_NAME, NULL);  

    /* 中断号被占用 */
    if (result) {  
        DPRINTK("IRQ%d already in use\n", IRQ_IIC);
  	    return result;  
    }      /* 申请设备号*/
    if (s3c2440i2c_major)
        result = register_chrdev_region(devno, 1, "s3c2440i2c");
    else  /* 动态申请设备号 */
    {
        result = alloc_chrdev_region(&devno, 0, 1, "s3c2440i2c");
        s3c2440i2c_major = MAJOR(devno);
    }  
    if (result < 0)
        return result;
    
    /* 动态申请设备结构体的内存*/
    s3c2440i2c_devp = kmalloc(sizeof(struct s3c2440i2c_dev), GFP_KERNEL);
    if (!s3c2440i2c_devp)    /*申请失败*/
    {
        result = -ENOMEM;
        goto fail_malloc;
    }
    memset(s3c2440i2c_devp, 0, sizeof(struct s3c2440i2c_dev));
  
    s3c2440i2c_setup_cdev(s3c2440i2c_devp, 0);	/* 初始化 gpio */	s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);	s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL); 	i2c_clock = clk_get(NULL, "i2c");	if (!i2c_clock) {		DPRINTK("failed to get i2c clock source\n");		return -ENOENT;	}	clk_enable(i2c_clock);	base_addr = ioremap(I2C_REGS_BASE, 0x14);	/* s3c2440 器件地址 */	iowrite32(S3C2440_SLAVE_ADDR, base_addr + S3C2410_IICADD);	/* 使能ACK和中断, 50.625Mhz/16/(15+1) = 197.7Khz */	iowrite32(CMD, base_addr + S3C2410_IICCON);	/* 串行输出使能 */	iowrite32(0x10, base_addr + S3C2410_IICSTAT);    return 0;

    fail_malloc: unregister_chrdev_region(devno, 1);
    return result;
}void __exit at24c02_exit(void)  
{
	if (i2c_clock) {		clk_disable(i2c_clock);		clk_put(i2c_clock);		i2c_clock = NULL;	}    cdev_del(&s3c2440i2c_devp->cdev);                           /* 注销cdev */
    kfree(s3c2440i2c_devp);                                     /* 释放设备结构体内存 */
    unregister_chrdev_region(MKDEV(s3c2440i2c_major, 0), 1);    /* 释放设备号 */    iounmap(base_addr);                                         /* 释放申请的虚拟地址 */    free_irq(IRQ_IIC, NULL);  									/* 释放中断 */
}  
  
MODULE_AUTHOR("lxm<lxm650@163.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION(VERSION_STRING); 
module_init(at24c02_init);
module_exit(at24c02_exit);  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -