因2440自带的IIC控制器本人用它作为从机使用,所以用GPIO模拟了IIC总线的主机模式。以下列出驱动代码和应用试验程序
总线模拟读写EEPROM
1.底层驱动
/*********************************
** EEPROM模拟IIC总线 驱动程序 **
** 日期:2012.8.30 **
** 版本:V1_0 **
*********************************/
#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 <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include "s3c24xx-adc.h"
static void __iomem *base_addr;
#define GPJCON (*(volatile unsigned long *)(base_addr + 0))
#define GPJDAT (*(volatile unsigned long *)(base_addr + 0x04))
#define GPJUP (*(volatile unsigned long *)(base_addr + 0x08))
#define GPJCON (*(volatile unsigned long *)(base_addr + 0))
#define GPJDAT (*(volatile unsigned long *)(base_addr + 0x04))
#define GPJUP (*(volatile unsigned long *)(base_addr + 0x08))
#define DEVICE_NAME "eeprom_micro2440_drv"
static struct semaphore lock;
#define I2CSDA_HIGH (GPJDAT=GPJDAT|(0x01<<4))
#define I2CSDA_LOW (GPJDAT=GPJDAT&(~(0x01<<4)))
#define I2CSCL_HIGH (GPJDAT=GPJDAT|(0x01<<3))
#define I2CSCL_LOW (GPJDAT=GPJDAT&(~(0x01<<3)))
#define delay_data 200
#define write_at24c32_addr 0xa0
#define read_at24c32_addr 0xa1
#define I2CSDA_LOW (GPJDAT=GPJDAT&(~(0x01<<4)))
#define I2CSCL_HIGH (GPJDAT=GPJDAT|(0x01<<3))
#define I2CSCL_LOW (GPJDAT=GPJDAT&(~(0x01<<3)))
#define delay_data 200
#define write_at24c32_addr 0xa0
#define read_at24c32_addr 0xa1
static void iicstart(void)
{
I2CSDA_HIGH;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSDA_LOW;
__udelay(delay_data);
}
{
I2CSDA_HIGH;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSDA_LOW;
__udelay(delay_data);
}
static void iicstop(void)
{
I2CSDA_LOW;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSDA_HIGH;
__udelay(delay_data);
}
static unsigned char waitack(void)
{ //将SDA改为输入
GPJCON=GPJCON&(~(0x03<<8));
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
while((GPJDAT&(0x01<<4))!=0);
I2CSCL_LOW;
__udelay(delay_data);
GPJCON=GPJCON|(0x01<<8);
I2CSDA_HIGH;
__udelay(delay_data);
return 1;
}
static void sendack(void)
{
I2CSDA_LOW;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSCL_LOW;
__udelay(delay_data);
}
static void sendnotack(void)
{
I2CSDA_HIGH;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSCL_LOW;
__udelay(delay_data);
I2CSDA_LOW;
__udelay(delay_data);
}
static void iicsendbyte(unsigned char ch)
{
unsigned char i=8;
while(i--)
{
I2CSCL_LOW;
__udelay(delay_data);
if((ch&0x80)==0)
{
I2CSDA_LOW;
}
else
{
I2CSDA_HIGH;
}
ch=ch<<1;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
}
I2CSCL_LOW;
__udelay(delay_data);
I2CSDA_HIGH;
__udelay(delay_data);
}
static unsigned char iicreceivebyte(void)
{
unsigned char i=8;
unsigned char ddata=0;
I2CSDA_HIGH;
//将数据线改为输入
GPJCON=GPJCON&(~(0x03<<8));
__udelay(delay_data);
while(i--)
{
ddata<<=1;
I2CSCL_LOW;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
if((GPJDAT&(0x01<<4))==0)
{
ddata|=0;
printk("%d=0\n",i);
}
else
{
ddata|=1;
printk("%d=1\n",i);
}
}
__udelay(delay_data);
I2CSCL_LOW;
__udelay(delay_data);
GPJCON=GPJCON|(0x01<<8);
GPJDAT=GPJDAT|(0x01<<4);
__udelay(delay_data);
return ddata;
}
static void write_at24c32(unsigned int addr,unsigned char dat)
{
iicstart();
__udelay(delay_data);
iicsendbyte(write_at24c32_addr);
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr>>8));
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr&0x00ff));
__udelay(delay_data);
waitack();
iicsendbyte(dat);
__udelay(delay_data);
waitack();
iicstop();
__udelay(delay_data);
}
{
I2CSDA_LOW;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSDA_HIGH;
__udelay(delay_data);
}
static unsigned char waitack(void)
{ //将SDA改为输入
GPJCON=GPJCON&(~(0x03<<8));
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
while((GPJDAT&(0x01<<4))!=0);
I2CSCL_LOW;
__udelay(delay_data);
GPJCON=GPJCON|(0x01<<8);
I2CSDA_HIGH;
__udelay(delay_data);
return 1;
}
static void sendack(void)
{
I2CSDA_LOW;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSCL_LOW;
__udelay(delay_data);
}
static void sendnotack(void)
{
I2CSDA_HIGH;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
I2CSCL_LOW;
__udelay(delay_data);
I2CSDA_LOW;
__udelay(delay_data);
}
static void iicsendbyte(unsigned char ch)
{
unsigned char i=8;
while(i--)
{
I2CSCL_LOW;
__udelay(delay_data);
if((ch&0x80)==0)
{
I2CSDA_LOW;
}
else
{
I2CSDA_HIGH;
}
ch=ch<<1;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
}
I2CSCL_LOW;
__udelay(delay_data);
I2CSDA_HIGH;
__udelay(delay_data);
}
static unsigned char iicreceivebyte(void)
{
unsigned char i=8;
unsigned char ddata=0;
I2CSDA_HIGH;
//将数据线改为输入
GPJCON=GPJCON&(~(0x03<<8));
__udelay(delay_data);
while(i--)
{
ddata<<=1;
I2CSCL_LOW;
__udelay(delay_data);
I2CSCL_HIGH;
__udelay(delay_data);
if((GPJDAT&(0x01<<4))==0)
{
ddata|=0;
printk("%d=0\n",i);
}
else
{
ddata|=1;
printk("%d=1\n",i);
}
}
__udelay(delay_data);
I2CSCL_LOW;
__udelay(delay_data);
GPJCON=GPJCON|(0x01<<8);
GPJDAT=GPJDAT|(0x01<<4);
__udelay(delay_data);
return ddata;
}
static void write_at24c32(unsigned int addr,unsigned char dat)
{
iicstart();
__udelay(delay_data);
iicsendbyte(write_at24c32_addr);
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr>>8));
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr&0x00ff));
__udelay(delay_data);
waitack();
iicsendbyte(dat);
__udelay(delay_data);
waitack();
iicstop();
__udelay(delay_data);
}
static unsigned char read_at24c32(unsigned int addr)
{
unsigned char dat=0;
iicstart();
__udelay(delay_data);
iicsendbyte(write_at24c32_addr);
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr>>8));
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr&0x00ff));
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicstart();
__udelay(delay_data);
iicsendbyte(read_at24c32_addr);
__udelay(delay_data);
waitack();
__udelay(delay_data);
dat=iicreceivebyte();
__udelay(delay_data);
sendnotack();
__udelay(delay_data);
iicstop();
__udelay(delay_data);
return dat;
}
static ssize_t eeprom_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
unsigned char data_temp=0;
unsigned long ret=0;
data_temp=read_at24c32((unsigned int)count);
printk("read data_temp=%d",data_temp);
ret=copy_to_user(buffer, &data_temp, 1);
return ret;
}
static ssize_t eeprom_write(struct file *file,char *buf,size_t count,loff_t *ppos)
{
unsigned long ret=0;
unsigned char data_temp=0;
ret=copy_from_user(&data_temp,buf,1);
printk("write data_temp=%d",data_temp);
write_at24c32((unsigned int)count,data_temp);
return ret;
}
static int eeprom_open(struct inode *inode,struct file *file)
{
//尝试打开互斥锁
int ret;
ret=down_trylock(&lock);
if(ret!=0)
return -EBUSY;
//映射IO口
base_addr=ioremap(0x560000d0,0x1c);
//初始化IO口
GPJCON=GPJCON&(~(0x0f<<6));
GPJCON=GPJCON|(0x05<<6);
GPJDAT=GPJDAT|(0x01<<4)|(0x01<<3);
printk("eeprom init ok!\n");
return 0;
}
{
unsigned char dat=0;
iicstart();
__udelay(delay_data);
iicsendbyte(write_at24c32_addr);
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr>>8));
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicsendbyte((unsigned char)(addr&0x00ff));
__udelay(delay_data);
waitack();
__udelay(delay_data);
iicstart();
__udelay(delay_data);
iicsendbyte(read_at24c32_addr);
__udelay(delay_data);
waitack();
__udelay(delay_data);
dat=iicreceivebyte();
__udelay(delay_data);
sendnotack();
__udelay(delay_data);
iicstop();
__udelay(delay_data);
return dat;
}
static ssize_t eeprom_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
unsigned char data_temp=0;
unsigned long ret=0;
data_temp=read_at24c32((unsigned int)count);
printk("read data_temp=%d",data_temp);
ret=copy_to_user(buffer, &data_temp, 1);
return ret;
}
static ssize_t eeprom_write(struct file *file,char *buf,size_t count,loff_t *ppos)
{
unsigned long ret=0;
unsigned char data_temp=0;
ret=copy_from_user(&data_temp,buf,1);
printk("write data_temp=%d",data_temp);
write_at24c32((unsigned int)count,data_temp);
return ret;
}
static int eeprom_open(struct inode *inode,struct file *file)
{
//尝试打开互斥锁
int ret;
ret=down_trylock(&lock);
if(ret!=0)
return -EBUSY;
//映射IO口
base_addr=ioremap(0x560000d0,0x1c);
//初始化IO口
GPJCON=GPJCON&(~(0x0f<<6));
GPJCON=GPJCON|(0x05<<6);
GPJDAT=GPJDAT|(0x01<<4)|(0x01<<3);
printk("eeprom init ok!\n");
return 0;
}
static int eeprom_close(struct inode *inodep,struct file *file)
{
up(&lock);//释放互斥锁
return 0;
}
{
up(&lock);//释放互斥锁
return 0;
}
static struct file_operations dev_fops={
.owner=THIS_MODULE,
.open=eeprom_open,
.release=eeprom_close,
.write=eeprom_write,
.read=eeprom_read,
};
static struct miscdevice misc={
.name=DEVICE_NAME,
.minor=MISC_DYNAMIC_MINOR,
.fops=&dev_fops,
};
static int __init eeprom_micro2440_init(void)
{
int ret;
//初始化锁
init_MUTEX(&lock);
//注册混杂设备
ret=misc_register(&misc);
return ret;
}
void __exit eeprom_micro2440_exit(void)
{
.owner=THIS_MODULE,
.open=eeprom_open,
.release=eeprom_close,
.write=eeprom_write,
.read=eeprom_read,
};
static struct miscdevice misc={
.name=DEVICE_NAME,
.minor=MISC_DYNAMIC_MINOR,
.fops=&dev_fops,
};
static int __init eeprom_micro2440_init(void)
{
int ret;
//初始化锁
init_MUTEX(&lock);
//注册混杂设备
ret=misc_register(&misc);
return ret;
}
void __exit eeprom_micro2440_exit(void)
{
//1.取消寄存器映射
iounmap(base_addr);
//2.注销混杂设备
misc_deregister(&misc);//注销混杂设备
}
iounmap(base_addr);
//2.注销混杂设备
misc_deregister(&misc);//注销混杂设备
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xubin");
module_init(eeprom_micro2440_init);
module_exit(eeprom_micro2440_exit);
MODULE_AUTHOR("xubin");
module_init(eeprom_micro2440_init);
module_exit(eeprom_micro2440_exit);
2.应用程序
#include <stdio.h>
#include <fcntl.h>
#include <linux/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
int i;
unsigned char value[512];
int fd;
value[0]=0x01;
fd=open("/dev/eeprom_micro2440_drv",O_RDWR);
if(fd<0)
{
printf("error\n");
exit(1);
}
while(1)
{
write(fd,value,1);
printf("write reg[0]data:%x to at24lc04\n",value[0]);
sleep(1);
value[0]=0;
read(fd,value,1);
printf("read reg[0]data:%x to at24lc04\n",value[0]);
value[0]+=1;
}
return 0;
}
{
int i;
unsigned char value[512];
int fd;
value[0]=0x01;
fd=open("/dev/eeprom_micro2440_drv",O_RDWR);
if(fd<0)
{
printf("error\n");
exit(1);
}
while(1)
{
write(fd,value,1);
printf("write reg[0]data:%x to at24lc04\n",value[0]);
sleep(1);
value[0]=0;
read(fd,value,1);
printf("read reg[0]data:%x to at24lc04\n",value[0]);
value[0]+=1;
}
return 0;
}