#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
//#include
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)?/IICDS寄存器
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)
{
//ClearPending(BIT_IIC);
//printk("in I2C irq\n");
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
// mdelay(100);
//mdelay(100);
while(f_nGetACK == 0);// Wait ACK
f_nGetACK = 0;
//Send address
rIICDS = unAddr; //地址结构
rIICCON = 0xaf; // Resumes IIC operation.
// printk("22222\n");
while(f_nGetACK == 0);// Wait ACK
//mdelay(100);
//printk("333333\n");
f_nGetACK = 0;
// printk("2\n");
// Send data
rIICDS = ucData;
rIICCON = 0xaf; // Resumes IIC operation.
// printk("4444444\n");
while(f_nGetACK == 0);// Wait ACK
//mdelay(100);
// printk("66666\n"); // 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
//mdelay(100);
while(f_nGetACK == 0);// Wait ACK
f_nGetACK = 0;
// Send address
rIICDS = unAddr;
rIICCON = 0xaf; // Resumes IIC operation.
//mdelay(100);
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
while(f_nGetACK == 0);// Wait ACK
f_nGetACK = 0;
//Get data
// cRecvByte = rIICDS;
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
// Read 16 byte from 24C04
for(i=0; i
iic_read_24c040(0xa0, i, &(data[i])); //读数据
}
data[count]='\0';
// printk("rev=%s\n",data);
if (copy_to_user (buff, data, count))
result = -EFAULT;
//else
//printk (KERN_INFO "wrote %d bytes\n", count);
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';
for(i=0; i
iic_write_24c040(0xa0, i, data[i]); //写数据
}
ret = count;
}
return ret;
}
static int I2C_open(struct inode *inode ,struct file *file)
{
int result;
// Initialize iic
rIICADD = 0x10; //IICADD寄存器 S3C2410X slave address
rIICCON = 0xaf; //IICCON寄存器 Enable ACK, interrupt, SET IICCLK=MCLK/16
rIICSTAT = 0x10; //IICSTAT寄存器 Enable TX/RX
rGPECON =(rGPECON&((~0xf)<<28))+(0xa<<28);
//printk("rGPECON=%x\n",rGPECON);
result = request_irq (IRQ_IIC, iic_int_24c04, SA_INTERRUPT, 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);//(IICCON寄存器)
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);
测试程序:
#include
#include
#include
#include
#include
#include
#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));
memset (buff, '\0', sizeof(buff));
read (fd, buff, sizeof(buff));
printf ("buff_read = %s\n", buff);
close(fd);
return 0;
}