/*//http://blog.csdn.net/beyondioi/article/details/6914935
分析:S3C2410的I2C为主设备,EEPROM的I2C为从设备,进行的操作为主设备写、和主设备读。
(1)设置I2C控制寄存器
1)收发传输:IICCON=0b 1 0 1 0 1111 = 0xAF
含义:应答使能、时钟分频为IICCLK = PCLK /16 、中断使能、清除中断标志、预分频值取15。
2)接收结束传输:IICCON=0b 0 0 1 0 1111 = 0x2F
含义:禁止应答(非应答)、时钟分频为IICCLK = PCLK /16 、中断使能、清除中断标志、预分频值取15。
(2)I2C控制状态寄存器
1)主模式发送、启动传输
IICSTAT=0b 11 1 1 0 0 0 0 = 0xF0
2)主模式发送、结束传输
IICSTAT=0b 11 0 1 0 0 0 0 = 0xD0
3)主模式接收、启动传输
IICSTAT=0b 10 1 1 0 0 0 0 = 0xB0
4)主模式接收、结束传输
IICSTAT=0b 10 0 1 0 0 0 0 = 0x90*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <asm/hardware.h>
#include <asm/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 <linux/device.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 <asm/arch/regs-adc.h>
#include <asm/arch/map.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-clock.h>
//#include <asm/arch/regs-iic.h>
#define I2C_MAGIC 'k'
#define I2C_set _IO(I2C_MAGIC,1)
#define I2C_MAJOR 259
#define DEVICE_NAME "s3c2410_I2C"
volatile int f_nGetACK;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("XIAOLEI");
MODULE_DESCRIPTION("S3C2410_IC");
char data[128]="\0";
#define rGPFCON *(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
static int i2c_major=I2C_MAJOR;
static volatile unsigned int *clkcon;
#define CLKCON 0x4C00000C;
static struct cdev *I2C_cdev;
static irqreturn_t iic_int_24c04(int irq,void *dev_id,struct pt_regs *regs)
{
f_nGetACK=1;
return IRQ_HANDLED;
}
static iic_write_24c04(unsigned int unslaveaddr,unsigned int unaddr,unsigned int ucdata)
{
f_nGetACK=0;
rIICDS=unslaveaddr;//地址0XA0
rIICSTAT=0xf0;
//rIICCON&=~0x10;//清中断标志,特别注意这条语句的位置,不能放到上条的前面
while(f_nGetACK==0);
f_nGetACK=0;
rIICDS=unaddr;
rIICCON=0xaf;//义:应答使能、时钟分频为IICCLK = PCLK /16 、中断使能、清除中断标志、预分频值取15。
//rIICCON&=~0x10;
while(f_nGetACK==0);
f_nGetACK=0;
rIICDS=ucdata;
rIICCON=0xaf;
//rIICCON&=~0x10;
while(f_nGetACK==0)
f_nGetACK=0;
rIICSTAT=0xd0;
rIICCON=0xaf;
mdelay(10);
}
/*void wr24c02(u32 slvaddr,u32 addr,u8 data)
{
flag=1;
rIICDS=slvaddr;
rIICSTAT=0XF0;//主设备启动
rIICCON&=~0x10;
while(flag==1);//当发送从地址完成之后会收到ACK信号,在中断处理函数中将该标志置为0
delay(1);
flag=1;
rIICDS=addr;
rIICCON&=~0x10;
while(flag==1);
delay(1);
flag=1;
rIICDS=data;
rIICCON&=~0x10;
while(flag==1);//当发送从地址完成之后会收到ACK信号,在中断处理函数中将该标志置为
delay(1);
rIICSTAT=0xd0;
rIICCON=0xaf;
delay(1);
}*/
void iic_read_24c02(unsigned int slvaddr,unsigned int addr,unsigned char *pdata)
{
char temp;
f_nGetACK=0;
rIICDS=slvaddr;
rIICSTAT=0xf0;//TX
//rIICCON&=~0x10;
while(f_nGetACK==0);
f_nGetACK=0;
rIICDS=addr;
rIICCON=0xaf;
//rIICCON&=~0x10;
while(f_nGetACK==0);
f_nGetACK=0;
rIICDS=slvaddr;
rIICSTAT=0xb0;//RX
rIICCON=0xaf;
mdelay(100);
while(f_nGetACK==0);
f_nGetACK=0;
rIICCON=0x2F;
mdelay(1);
temp=rIICDS;
rIICSTAT=0x90;
rIICCON=0xaf;
mdelay(10);
*pdata=temp;
}
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;
for(i=0;i<count;i++)
{
iic_read_24c02(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;
if (count>127) return -ENOMEM;
if (count<0) return -EINVAL;
if (copy_from_user (data, buf, count)) //注意 copy_from_user
{
ret = -EFAULT;
}
else
{
data[127]='\0';
for(i=0;i<count;i++)
{
iic_write_24c04(0xa0,i,data[i]);
}
ret=count;
}
return ret;
}
static int I2C_open(struct inode *inode,struct file *filp)
{
int result;
rIICADD=0x10;//2440 slave address = [7:1]
rIICCON=0xaf;
rIICSTAT=0x10;//IIC bus data output enable(Rx/Tx)
rGPFCON=(rGPFCON&(~0xf)<<28)+(0xa<<28);
printk("init i2c/n");
result=request_irq(IRQ_IIC,iic_int_24c04,SA_INTERRUPT,DEVICE_NAME,NULL);
if(result)
{
printk(KERN_INFO "I2C CANOT get irq\n");
}
return 0;
}
static int I2C_release(struct inode *inode,struct file *filp)
{
free_irq(IRQ_IIC,NULL);
return 0;
}
static int I2C_ioctl(struct inode *inode,struct file *filp,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(KER_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);//通过mkdev获得32位设备驱动号
if(i2c_major)
{
result=register_chrdev_region(dev,1,DEVICE_NAME);
//int register_chrdev_region(dev_t first,unsigned int count,char *name)
}
else
{
result=alloc_chrdev_region(&dev,0,1,DEVICE_NAME);//起始设备号未指定,就要动态申请
i2c_major=MAJOR(dev);
}
if(result<0)
{
printk(KER_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);
#include <stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<time.h>
#include<sysy/ioctl.h>
#define WATCHDOG_MAGIC 'k'
#define FEED_DOG _IO(WATCHDOG_MAGIC,1)
int main(int argc,char **argv)
{
int fd;
char buff[]="farsight";
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",buff);
close(fd);
return 0;
} |