这篇博客分析i2c的普通设备驱动,像往常的字符驱动一样,先module_init(),和module_exit(),来完成模块的加载与卸载,然后在初始化函数中注册设备号和关联文件结构体file_operaion,最后再去实现file_operation中的read,write,open,release等操作,在操作read,write,open,release时,直接控制s3c2440的i2c相关的寄存器来与i2c设备进行通信,而没有记住linux2.6.32.2内核提供的i2c-core.c文件里面的i2c_transfer方法来实现数据通信。
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/sched.h> #include <mach/hardware.h> #include <linux/semaphore.h> #include <asm/uaccess.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/types.h> /* size_t */ #include <linux/mm.h> #include <linux/kdev_t.h> #include <linux/cdev.h> #include <linux/delay.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/init.h> #include <linux/serio.h> #include <asm/irq.h> #include <mach/map.h> #include <mach/regs-gpio.h> #include <mach/regs-irq.h> #include <mach/regs-clock.h> #include <asm/signal.h> volatile int f_nGetACK; #define UINT unsigned int #define I2C_MAGIC 'k' #define I2C_set _IO(I2C_MAGIC,1) #define I2C_MAJOR 259 #define DEVICE_NAME "s3c2410_I2C" MODULE_LICENSE("GPL"); MODULE_AUTHOR("farsight"); MODULE_DESCRIPTION("s3c2410 I2C"); char data[128]="\0"; #define rGPECON *(volatile unsigned int *)S3C2410_GPECON #if 0 #define S3C2410_I2C(x) (S3C2410_IICREG(x)) #define S3C2410_IICCON S3C2410_I2C(0x00) #define S3C2410_IICSTAT S3C2410_I2C(0x04) #define S3C2410_IICADD S3C2410_I2C(0x08) #define S3C2410_IICDS S3C2410_I2C(0x0c) #define rIICCON *(volatile unsigned int *)S3C2410_IICCON #define rIICSTAT *(volatile unsigned int *)S3C2410_IICSTAT #define rIICADD *(volatile unsigned int *)S3C2410_IICADD #define rIICDS *(volatile unsigned int *)S3C2410_IICDS #define rGPECON *(volatile unsigned int *)S3C2410_GPECON #else #define rIICCON *(volatile unsigned int *)i2c_base #define rIICSTAT *(volatile unsigned int *)((unsigned int)i2c_base + 4) #define rIICADD *(volatile unsigned int *)((unsigned int)i2c_base + 8) #define rIICDS *(volatile unsigned int *)((unsigned int)i2c_base + 0xc) static volatile void __iomem *i2c_base; static struct resource *area = NULL; #endif #define CLKCON 0x4c00000c static volatile unsigned int *clkcon; static int I2C_major = I2C_MAJOR; static struct cdev I2C_cdev; /********************************************************************************************* * name: iic_int_24c04() * func: IIC interrupt handler * para: none * ret: none * modify: * comment: *********************************************************************************************/ static irqreturn_t iic_int_24c04(int irq,void *dev_id,struct pt_regs *regs) { f_nGetACK = 1; return IRQ_HANDLED ; } /********************************************************************************************* * name: iic_write_24c040 * func: write data to 24C040 * para: unSlaveAddr --- input, chip slave address * unAddr --- input, data address * ucData --- input, data value * ret: none * modify: * comment: *********************************************************************************************/ void iic_write_24c040(UINT unSlaveAddr,UINT unAddr,UINT ucData) { f_nGetACK = 0; // Send control byte rIICDS = unSlaveAddr; // 0xa0 rIICSTAT = 0xf0; // Master Tx,Start while(f_nGetACK == 0);// Wait ACK f_nGetACK = 0; //Send address rIICDS = unAddr; rIICCON = 0xaf; // Resumes IIC operation. while(f_nGetACK == 0);// Wait ACK f_nGetACK = 0; // Send data rIICDS = ucData; rIICCON = 0xaf; // Resumes IIC operation. while(f_nGetACK == 0);// Wait ACK f_nGetACK = 0; // End send rIICSTAT = 0xd0; // Stop Master Tx condition rIICCON = 0xaf; // Resumes IIC operation. mdelay(10); // Wait until stop condtion is in effect. } /********************************************************************************************* * name: iic_read_24c040 * func: read data from 24C040 * para: unSlaveAddr --- input, chip slave address * unAddr --- input, data address * pData --- output, data pointer * ret: none * modify: * comment: *********************************************************************************************/ void iic_read_24c040(UINT unSlaveAddr,UINT unAddr,unsigned char *pData) { char cRecvByte; f_nGetACK = 0; //Send control byte rIICDS = unSlaveAddr; // 0xa0 rIICSTAT = 0xf0; // Master Tx,Start while(f_nGetACK == 0);// Wait ACK f_nGetACK = 0; // Send address rIICDS = unAddr; rIICCON = 0xaf; // Resumes IIC operation. while(f_nGetACK == 0);// Wait ACK f_nGetACK = 0; //Send control byte rIICDS = unSlaveAddr; // 0xa0 rIICSTAT = 0xb0; // Master Rx,Start rIICCON = 0xaf; // Resumes IIC operation. mdelay(100); while(f_nGetACK == 0);// Wait ACK f_nGetACK = 0; //Get data rIICCON = 0x2f; mdelay(1); // Get data cRecvByte = rIICDS; // End receive rIICSTAT = 0x90; // Stop Master Rx condition rIICCON = 0xaf; // Resumes IIC operation. mdelay(10); // Wait until stop condtion is in effect. *pData = cRecvByte; } ssize_t I2C_read (struct file *filp, char *buff, size_t count, loff_t *offp) { ssize_t result = 0; int i; for(i=0; i<count; i++) data[i]=0; // Read 16 byte from 24C04 for(i=0; i<count; i++) { iic_read_24c040(0xa0, i, &(data[i])); } data[count]='\0'; if (copy_to_user (buff, data, count)) result = -EFAULT; result=count; return result; } ssize_t I2C_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { int i; ssize_t ret = 0; //printk ("Writing %d bytes\n", count); if (count>127) return -ENOMEM; if (count<0) return -EINVAL; if (copy_from_user (data, buf, count)) { ret = -EFAULT; } else { data[127]='\0'; //printk ("Received: %s\n", data); // Write 0 - 16 to 24C04 for(i=0; i<count; i++) { iic_write_24c040(0xa0, i, data[i]); //mdelay(100); } //printk("write end\n"); ret = count; } return ret; } static int I2C_open(struct inode *inode ,struct file *file) { int result; // Initialize iic rIICADD = 0x10; // S3C2410X slave address rIICCON = 0xaf; // Enable ACK, interrupt, SET IICCLK=MCLK/16 rIICSTAT = 0x10; // Enable TX/RX rGPECON =(rGPECON&((~0xf)<<28))+(0xa<<28); //printk("rGPECON=%x\n",rGPECON); result = request_irq (IRQ_IIC, iic_int_24c04, IRQF_DISABLED, DEVICE_NAME, NULL); if (result) { printk(KERN_INFO "I2C: can't get assigned irq\n"); } //printk(KERN_NOTICE"open the I2C now!\n"); return 0; } static int I2C_release(struct inode *inode,struct file *file) { free_irq(IRQ_IIC, NULL);//ÊÍ·ÅÖжÏ×ÊÔŽ //printk("I2C closed\n"); return 0; } static int I2C_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg) { return 0; } //œ«É豞ע²áµœÏµÍ³Ö®ÖÐ static void I2C_setup_dev(struct cdev *dev,int minor,struct file_operations *fops) { int err; int devno=MKDEV(I2C_major,minor); cdev_init(dev,fops); dev->owner=THIS_MODULE; dev->ops=fops; err=cdev_add(dev,devno,1); if(err) printk(KERN_INFO"Error %d adding I2C %d\n",err,minor); } static struct file_operations I2C_remap_ops={ .owner=THIS_MODULE, .open=I2C_open, .write = I2C_write, .read = I2C_read, .release=I2C_release, .ioctl=I2C_ioctl, }; //×¢²áÉ豞Çý¶¯³ÌÐò£¬Ö÷ÒªÍê³ÉÖ÷É豞ºÅµÄ×¢²á static int __init s3c2410_I2C_init(void) { int result; dev_t dev = MKDEV(I2C_major,0); if(I2C_major) result = register_chrdev_region(dev,1,DEVICE_NAME); else { result = alloc_chrdev_region(&dev,0,1,DEVICE_NAME); I2C_major = MAJOR(dev); } if(result<0) { printk(KERN_WARNING"I2C:unable to get major %d\n",I2C_major); return result; } if(I2C_major == 0) I2C_major = result; printk(KERN_NOTICE"[DEBUG] I2C device major is %d\n",I2C_major); __raw_writel( (__raw_readl(S3C2410_CLKCON) | (1 << 16)), S3C2410_CLKCON); #if 0 printk("\n S3C2410_CLKCON = %x \n", __raw_readl(S3C2410_CLKCON)); area = request_mem_region(0x54000000, 16,"I2C"); #endif i2c_base = ioremap(0x54000000, 16); clkcon = ioremap(CLKCON, 0x4); printk(KERN_INFO"i2c clock = %d\n", *clkcon & (0x1 << 16)); *clkcon |= 0x1 << 16; I2C_setup_dev(&I2C_cdev,0,&I2C_remap_ops); return 0; } //Çý¶¯Ä£¿éжÔØ static void s3c2410_I2C_exit(void) { #if 0 if (area) { release_resource(area); kfree(area); } #endif cdev_del(&I2C_cdev); unregister_chrdev_region(MKDEV(I2C_major,0),1); printk("I2C device uninstalled\n"); } module_init(s3c2410_I2C_init); module_exit(s3c2410_I2C_exit);在编译驱动的时候提示出错:I2C_drv.c:7:26: error: asm/hardware.h: No such file or directory
测试应用程序
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <time.h> #include <sys/ioctl.h> #define WATCHDOG_MAGIC 'k' #define FEED_DOG _IO(WATCHDOG_MAGIC,1) int main(int argc,char **argv) { int fd; char buff[]="farsight"; //Žò¿ªI2C fd=open("/dev/i2c",O_RDWR); if(fd<0) { printf("cannot open the I2C device\n"); return -1; } sleep(1); printf("buff_write=%s\n",buff); write (fd, buff, sizeof(buff)); //printf(" read now!\n"); memset (buff, '\0', sizeof(buff)); //printf ("Read returns %d\n", read (fd, buff, sizeof(buff))); read (fd, buff, sizeof(buff)); //read (fd, buff, 3); printf ("buff_read = %s\n", buff); close(fd); // while(1); // printf("end\n"); return 0; }