各位大侠好,小弟恳请大侠帮我指点一下S3C2410的IIC驱动程序,驱动的是AT24C02芯片,主要就是芯片的读写操作,目前的状态就是读写数据一直进不了中断,
小弟对驱动不是很懂,但是对这个感兴趣,驱动源代码如下:
一些头文件:
#ifndef IIC_H
#define IIC_H
#define READ_EEPROM 0xA1 //读EEPROM
#define WRITE_EEPROM 0xA0 //写EEPROM
#define GPIO_REGISTER_BASE 0x56000000
#define GPECON 0x40
#define GPEUP 0x48
#define IICSDA 2 << 30
#define IICSCL 2 << 28
#define IIC_REGISTER_BASE 0x54000000
#define IICCON 0
#define IICCON_ACK 1 << 7 //应答使能
#define IICCON_Tx_CLK 1 << 6 // 1 Fpclk/512 0 Fpclk/16
#define IICCON_INTERRUP 1 << 5
#define IICCON_INT_PENDING_FLAG 0 << 4
#define IICCON_TX_CLK_VALUE 0 << 3
#define IICSTAT 0x4
#define IICSTAT_MASTER_RECV 2 << 6 //主接收模式
#define IICSTAT_MASTER_TRAN 3 << 6 //主发送模式
#define IICSTAT_BUSY_FLAG 1 << 5 //当发送数据的时候,为起始信号
#define IICSTAT_ABLE_RX_AND_TX 1 << 4 //使能 RX/TX
#define WRITE_ENABLE_IICADD 0 << 4 //使能 RX/TX
#define IICSTAT_ARB_SUCCES 0 << 3
#define IICSTAT_ADD_MATCH 1 << 2
#define IICSTAT_ADD_IS_0 1 << 1 //接收从地址为0 Flag
#define IICSTAT_RECV_ACK 1
#define IICADD 0x8
#define IICDS 0xC
#define CLK_REGISTER_BASE 0x4C000000
#define CLKCLOCKTIME 0x0
#define CLKMPLLCON 0x4
#define CLKUPLLCON 0x8
#define CLKCON 0xC
#define CLKCON_IIC 1 << 16
#define CLKCON_NANDFLAS 1 << 4
#define CLKSLOW 0x10
#define CLKSLOW_UCLK_ON 0 << 7
#define CLKSLOW_MPLL_OFF 1 << 5
#define CLKSLOW_SLOW_BIT 0 << 4
#define INT_REGISTER_BASE 0x4A000000
#define SRCPND 0 //中断源寄存器
#define INTMOD 0x4//中断模式寄存器
#define INT_IIC_IRQ 0 << 27
#define INTMSK 0x8//中断屏蔽寄存器
#define INT_IIC_MSK 0 << 27
#define INTPND 0x10
#endif
/*****************************************************
** 版权所有:
** 文 件 名:
** 创建日期:
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
******************************************************/
//S3C2410定义的一些头文件在linux-2.6.26\include\asm-arm\arch-s3c2410
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <asm/arch-s3c2410/regs-gpio.h>
#include <asm/arch-s3c2410/regs-iic.h>
#include <asm/arch-s3c2410/irqs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/arch/gpio.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include "iic.h"
#define IIC_ID 60 //申请中断号
#define write_iic_reg(reg, val) __raw_writeb(val, IIC_BASE + reg)
#define read_iic_reg(reg) __raw_readb(IIC_BASE + reg)
#define write_clk_reg(reg, val) __raw_writel(val, CLK_BASE + reg)
#define read_clk_reg(reg) __raw_readl(CLK_BASE + reg)
#define write_gpio_reg(reg,val) __raw_writel(val, GPIO_BASE + reg)
#define read_gpio_reg(reg) __raw_readl(GPIO_BASE + reg)
#define write_int_reg(reg, val) __raw_writel(val, INT_BASE + reg)
#define read_int_reg(reg) __raw_readl(INT_BASE + reg)
#define MAX_SIZE 20
#define READ 0
#define WRITE 1
#define DEVICE_NAME "my_iic"
#define SUCCESS 0
#define ERR -1
void *IIC_BASE;
void *INT_BASE;
void *CLK_BASE;
void *GPIO_BASE;
int iic_major = 250; //主设备号
int iic_minor = 0;
unsigned char count = 0;
volatile int ack = 0;
//struct cdev *iic_cdev;
struct char_cdev{
char read_buffer[MAX_SIZE];
char write_buffer[MAX_SIZE];
struct cdev *cdev;
dev_t devno; //dev_t 是一个unsigned int
};
struct char_cdev *iic_cdev;
ssize_t iic_read(struct file *filp, void *buf, size_t size, loff_t *off);
ssize_t iic_write(struct file *filp, const char *buf, size_t size, loff_t *off);
int iic_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg);
int iic_open (struct inode *inode, struct file *filp);
int iic_close (struct inode *inode, struct file *filp);
void iic_stop(char cmd);
void delay(unsigned char n);
irqreturn_t iic_interrupt(int irq, void *dev_id);
struct file_operations iic_fops ={
.owner = THIS_MODULE,
.read = iic_read,
.write = iic_write,
.ioctl = iic_ioctl,
.open = iic_open,
.release = iic_close,
};
/*************************************************
** 函 数 名:iic_init
** 功能描述:iic 设备初始化
** 输入参数:无
** 输出参数:无
** 返 回 值:无
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
int iic_init(void)
{
int result = 0;
int err = 0;
int readtemp = 0;
int ret = 0;
iic_cdev = kmalloc(sizeof(struct char_cdev), GFP_KERNEL);
if (!iic_cdev)
{
printk(KERN_WARNING "kmalloc error\n");
return ERR;
}
if (iic_major)
{
result = register_chrdev_region(iic_cdev->devno, 1, DEVICE_NAME);
}
else
{
result = alloc_chrdev_region(&iic_cdev->devno, iic_minor,1, DEVICE_NAME);
iic_major = MAJOR(iic_cdev->devno);
iic_minor = MINOR(iic_cdev->devno);
}
if (result < 0)
{
printk(KERN_WARNING "IIC can not get major %d\n",iic_major);
goto free_iic_cdev;
}
iic_cdev->cdev = cdev_alloc();
if (NULL == iic_cdev->cdev)
{
printk(KERN_WARNING "Can not request the memory\n");
goto free_iic_cdev;
}
cdev_init(iic_cdev->cdev, &iic_fops);
iic_cdev->cdev->ops = &iic_fops;
iic_cdev->cdev->owner = THIS_MODULE;
err = cdev_add(iic_cdev->cdev, iic_cdev->devno, 1);
if (err)
{
printk(KERN_NOTICE "Error to add iic_cdev\n");
}
IIC_BASE = ioremap(IIC_REGISTER_BASE, 0x100);
if(NULL == IIC_BASE)
{
printk("IIC_BASE ioremap error\n");
goto fail;
}
CLK_BASE = ioremap(CLK_REGISTER_BASE, 0x100);
if(NULL == CLK_BASE)
{
printk("CLK_BASE ioremap error\n");
goto fail;
}
GPIO_BASE = ioremap(GPIO_REGISTER_BASE,0x100);
if(NULL == GPIO_BASE)
{
printk("GPIO_BASE ioremap error\n");
goto fail;
}
INT_BASE = ioremap(INT_REGISTER_BASE, 0x100);
if(NULL == INT_BASE)
{
printk("INT_BASE ioremap error\n");
goto fail;
}
readtemp = read_gpio_reg(GPECON);
write_gpio_reg(GPECON, readtemp | IICSCL | IICSDA); //设置GPIO引脚为IIC
write_gpio_reg(GPEUP,0xFFFF);//The pull-up function is disabled
//时序
write_clk_reg(CLKCLOCKTIME,0xFFFFFF);
//write_clk_reg(CLKMPLLCON,0x5c080);
//printk(KERN_NOTICE "CLKMPLLCON is 0x%X\n",read_clk_reg(CLKMPLLCON));
write_clk_reg(CLKUPLLCON,0x28080);
printk(KERN_NOTICE "CLKUPLLCON is 0x%X\n",read_clk_reg(CLKUPLLCON));
readtemp = read_clk_reg(CLKCON);
write_clk_reg(CLKCON, readtemp | CLKCON_IIC); //使能IIC时钟
printk(KERN_NOTICE "CLKCON is 0x%X\n",read_clk_reg(CLKCON));
write_int_reg(SRCPND, 0xFFFFFFFF);
write_int_reg(INTPND, 0xFFFFFFFF);
printk(KERN_NOTICE "SRCPND is 0x%X\n",read_clk_reg(SRCPND));
ret = request_irq(IIC_ID, iic_interrupt,0, DEVICE_NAME,NULL);
if (ret)
{
printk(KERN_NOTICE"iic can not get irq : %d\n",ret);
goto fail;
}
write_iic_reg(IICCON,0xAF);//使能应答和中断
write_iic_reg(IICADD,0x10);
write_iic_reg(IICSTAT,0x10);
printk(KERN_NOTICE"IICCON is 0x%X\n",read_iic_reg(IICCON));
printk(KERN_ALERT "iic init success\n");
return SUCCESS;
fail:
// 以相反的顺序清除
//free_irq(IIC_ID, NULL);
iounmap(IIC_BASE);
iounmap(CLK_BASE);
iounmap(GPIO_BASE);
iounmap(INT_BASE);
//iounmap(INT_BASE);
cdev_del(iic_cdev->cdev);
unregister_chrdev_region(iic_cdev->cdev,(unsigned int)1);
free_iic_cdev:
kfree(iic_cdev);
return ERR;
}
/*************************************************
** 函 数 名:read_eeprom
** 功能描述:读AT24C256
** 输入参数:addr 要读取eepROM的地址
** 输出参数:无
** 返 回 值:读取的字节数
** 创建日期:
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
int read_eeprom(unsigned char addr)
{
ack = 0;
write_iic_reg(IICSTAT, IICSTAT_MASTER_TRAN);
write_iic_reg(IICDS ,READ_EEPROM);
//向数据寄存器里面写入从设备的读操作指令
write_iic_reg(IICSTAT,0xF0);
delay(10);
while (0 == ack);
ack = 0;
// 向数据寄存器里面写入要从Slave设备地址读数据的具体地址
write_iic_reg(IICDS ,addr);
write_iic_reg(IICCON,0xAF);//清除中断,重新开始写数据
while (0 == ack);
ack = 0;
write_iic_reg(IICSTAT, IICSTAT_MASTER_RECV);
write_iic_reg(IICSTAT,0xb0);
write_iic_reg(IICCON,0x2F);//清除中断
iic_cdev->read_buffer[count++] = read_iic_reg(IICDS);
delay(10);
iic_stop(0x90);
write_iic_reg(IICCON,0xAF);//清除中断
delay(10);
return count;
}
/*************************************************
** 函 数 名:write_eeprom
** 功能描述:写AT24C256
** 输入参数:addr 要写入eepROM的地址
** 输出参数:无
** 返 回 值:写入的字节数
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
int write_eeprom(unsigned char addr)
{
ack = 0;
write_iic_reg(IICSTAT, IICSTAT_MASTER_TRAN);
write_iic_reg(IICDS ,WRITE_EEPROM);
//write_iic_reg(IICCON,0xAF);//清除中断flag
// 向数据寄存器里面写入从设备的读操作指令
write_iic_reg(IICSTAT,0xF0);
//while (read_iic_reg(IICSTAT) & IICSTAT_RECV_ACK);
while (0 == ack); //运行测试程序后,程序一直在这里死循环,就是说没有产生中断,很郁闷
ack = 0;
// 向数据寄存器里面写入要从Slave设备地址读数据的具体地址
write_iic_reg(IICDS ,addr);
write_iic_reg(IICCON,0xAF);//清除中断
while (0 == ack);
ack = 0;
//写入数据到EEPROM
write_iic_reg(IICDS ,iic_cdev->write_buffer[count++]);
write_iic_reg(IICCON,0xAF);//清除中断
while (0 == ack);
ack = 0;
iic_stop(0xD0);
write_iic_reg(IICCON,0xAF);//清除中断
delay(10);
return count;
}
/*************************************************
** 函 数 名:iic_open
** 功能描述:iic设备打开函数
** 输入参数:inode 设备节点结构体
:filp
** 输出参数:设备关闭是否成功
** 返 回 值:0
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
int iic_open (struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "iic_open\r\n");
return 0;
}
/*************************************************
** 函 数 名:iic_close
** 功能描述:iic设备关闭函数
** 输入参数:inode filp
** 输出参数:无
** 返 回 值:0
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
int iic_close (struct inode *inode, struct file *filp)
{
printk(KERN_ALERT "iic_close\r\n");
return 0;
}
/*************************************************
** 函 数 名:iic_interrupt
** 功能描述:iic中断函数
** 输入参数:irq dev_id
** 输出参数:无
** 返 回 值:无
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:暂时还不知道如何判断是读中断还是写中断
**************************************************/
irqreturn_t iic_interrupt(int irq, void *dev_id)
{
ack = 1;
printk("***********I am in interrupt fun\n"); //中断函数一般不能有打印,我这里是为了测试用,看有没有进入中断
return IRQ_HANDLED ;
}
/*************************************************
** 函 数 名:delay
** 功能描述:延时函数
** 输入参数:n,延时时间,
** 输出参数:无
** 返 回 值:无
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
void delay(unsigned char n)
{
int i = 0;
int j = 0;
for (i = 0; i < n; i++)
for(j = 0; j < 1000; j++);
}
/*************************************************
** 函 数 名:iic_stop
** 功能描述:停止IIC操作命令符
** 输入参数:cmd。停止TX操作,cmd = 0xDO,停止RX操作,cmd = 0x90
** 输出参数:无
** 返 回 值:无
** 创建日期:2012-07-11
** 作 者:SorinLee
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
void iic_stop(char cmd)
{
write_iic_reg(IICSTAT,cmd);
delay(10);
}
/*************************************************
** 函 数 名:iic_read
** 功能描述:用户数据read系统调用函数
** 输入参数:filp buf size off
** 输出参数:无
** 返 回 值:读取的字节数
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
ssize_t iic_read(struct file *filp, void *buf, size_t size, loff_t *off)
{
unsigned int ret;
unsigned int i = 0;
for (i = 0; i < size; i++)
{
read_eeprom(i);
}
count = 0;
ret = copy_to_user(buf, iic_cdev->read_buffer, size);
return ret;
}
/*************************************************
** 函 数 名:iic_write
** 功能描述:用户调用write系统调用函数
** 输入参数:filp buf size off
** 输出参数:无
** 返 回 值:写的字节数
** 创建日期:2012-07-11
** 作 者:SorinLee
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
ssize_t iic_write(struct file *filp, const char *buf, size_t size, loff_t *off)
{ unsigned int ret;
unsigned int i = 0;
ret = copy_from_user(iic_cdev->write_buffer, buf, size);
for (i = 0; i < size; i++)
{
write_eeprom(i);
}
count = 0;
return ret;
}
/*************************************************
** 函 数 名:iic_ioctl
** 功能描述:用户调用ioctl函数的系统调用函数
** 输入参数:inodep filp cmd arg
** 输出参数:无
** 返 回 值:0
** 创建日期:2012-07-11
** 作 者:SorinLee
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
int iic_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg)
{
return 0;
}
/*************************************************
** 函 数 名:iic_exit
** 功能描述:iic驱动退出函数,释放分配的资源,释放的顺序与分配的顺序相反
** 输入参数:无
** 输出参数:无
** 返 回 值:无
** 创建日期:2012-07-11
** 作 者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
void iic_exit(void)
{
free_irq(IIC_ID, NULL);
iounmap(IIC_BASE);
iounmap(CLK_BASE);
iounmap(GPIO_BASE);
iounmap(INT_BASE);
cdev_del(iic_cdev->cdev);
unregister_chrdev_region(iic_cdev->cdev,1);
kfree(iic_cdev);
printk(KERN_ALERT "iic exit successful\n");
}
module_init(iic_init);
module_exit(iic_exit);
MODULE_AUTHOR("lanjim");
MODULE_DESCRIPTION("S3C2410 IIC EEPROM Driver");
MODULE_LICENSE("GPL");
应用测试程序如下:
#include <stdio.h>
#include <fcntl.h> //open()
#include <unistd.h> //read() write()
#define DECEIVE_NAME "/dev/my_iic"
#define MAX_SIZE 20
int main()
{
int fd = 0;
char i = 0;
ssize_t read_count = 0;
ssize_t write_count = 0;
unsigned char readbuf[MAX_SIZE] = {0,};
unsigned char writebuf[MAX_SIZE] = {0xAA,0xBB,0xCC,0xDD,0x11,0x22,0x33,0x44,0x55,0x66,0,};
fd = open(DECEIVE_NAME, O_RDWR);
if(-1 == fd)
{
printf("open iic fail\n");
return 0;
}
write_count = write(fd, writebuf,5);
if(-1 == write_count)
{
printf("IIC write fail\n");
}
printf("write_count = %d\n",write_count);
read_count = read(fd, readbuf, 5);
if(-1 == read_count)
{
printf("IIC read fail\n");
}
printf("read_count = %d\n",read_count);
printf("*******************\n");
for(i = 0; i < 5; i++)
{
printf("readbuf[%d] = 0x%02X\n",i,readbuf[i]);
}
close(fd);
return 0;
}
请各位大侠,高手,老手,老师,教授帮小弟看看,希望能趁早把这个问题解决掉,谢谢各位 |
|