lanejim 发表于 2012-08-15 21:18

小弟请求大侠帮忙看看S3C2410 的 IIC 的AT24C02的驱动程序,郁闷我一个月了

本帖最后由 lanejim 于 2012-09-01 20:31 编辑

各位大侠好,小弟恳请大侠帮我指点一下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/5120Fpclk/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

#defineCLK_REGISTER_BASE                  0x4C000000
#defineCLKCLOCKTIME                           0x0
#defineCLKMPLLCON                              0x4
#defineCLKUPLLCON                              0x8
#defineCLKCON                                     0xC
#define       CLKCON_IIC                        1 << 16
#define       CLKCON_NANDFLAS            1 << 4

#defineCLKSLOW                                 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/irqs.h>

#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/arch/gpio.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include "iic.h"


#define IIC_ID    60//申请中断号

#if 0
#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)
#endif

#define write_iic_reg(reg, val)   iowrite8(val, IIC_BASE + reg)
#define read_iic_reg(reg)         ioread8(IIC_BASE + reg)

#define write_clk_reg(reg, val)   iowrite32(val, CLK_BASE + reg)
#define read_clk_reg(reg)         ioread32(CLK_BASE + reg)

#define write_gpio_reg(reg, val)    iowrite32(val, GPIO_BASE + reg)
#define read_gpio_reg(reg)          ioread32(GPIO_BASE + reg)

#define write_int_reg(reg, val)   iowrite32(val, INT_BASE + reg)
#define read_int_reg(reg)         ioread32(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 char ack = 0;

//struct cdev *iic_cdev;

struct char_cdev{
    char read_buffer;
    char write_buffer;
    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);
irqreturn_t iic_interrupt(int irq, void *dev_id,struct pt_regs *regs);


struct file_operations iic_fops ={    // <linux/fs.h>
    .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;
    }


    iic_cdev->devno = MKDEV(iic_major,iic_minor);

    if (iic_major)
    {   
      //向系统申请设备,用于已知设备号,注册设备号devno,1为设备的个数
      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的成员,并建立生cdev和file_operations之间连接
    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 toadd 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;
    }

    //__raw_writeb(0x10, IICADD + IIC_BASE);
    //设置GPIO引脚为iic功能引脚
    readtemp = read_gpio_reg(GPECON);
    printk(KERN_NOTICE "GPECON is 0x%X\n",readtemp);

    if (((readtemp & IICSCL) == 0) || ((readtemp & IICSDA) == 0))
    {
      write_gpio_reg(GPECON, readtemp | IICSCL | IICSDA);
    }
    write_gpio_reg(GPEUP,0xC000);//The pull-up function is disabled


    //printk(KERN_NOTICE "CLKUPLLCON is 0x%X\n",read_clk_reg(CLKUPLLCON));

    readtemp = read_clk_reg(CLKCON);
    if ((readtemp & CLKCON_IIC) == 0)
    {
      write_clk_reg(CLKCON, readtemp | CLKCON_IIC);   //使能IIC时钟
    }
    printk(KERN_NOTICE "CLKCON is 0x%X\n",read_clk_reg(CLKCON));

    //成功返回 0
    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;
    }


    printk(KERN_NOTICE "GPECON is 0x%X\n",read_clk_reg(GPECON));

    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);
    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(IICDS ,READ_EEPROM);
    write_iic_reg(IICSTAT, IICSTAT_MASTER_TRAN);
    write_iic_reg(IICCON,0xAF);//清除中断

    //向数据寄存器里面写入从设备的读操作指令
    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 (read_iic_reg(IICSTAT) & IICSTAT_RECV_ACK);
    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 = read_iic_reg(IICDS);
    udelay(1000);
    iic_stop(0x90);
    write_iic_reg(IICCON,0xAF);//清除中断
    udelay(1000);

    return count;

}

/*************************************************
** 函 数 名:write_eeprom
** 功能描述:写AT24C256
** 输入参数:addr 要写入eepROM的地址
** 输出参数:无
** 返 回 值:写入的字节数
** 创建日期:2012-07-11
** 作    者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/

int write_eeprom(unsigned char addr)
{
    ack = 0;
    write_iic_reg(IICDS ,WRITE_EEPROM);

    write_iic_reg(IICSTAT, IICSTAT_MASTER_TRAN
                         | IICSTAT_WRITE_START
                         | IICSTAT_ABLE_RX_AND_TX
                         | 0x00);   //0xF0

    //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);//清除中断
    //iic_start(0xF0);
    //while (read_iic_reg(IICSTAT) & IICSTAT_RECV_ACK);
    while (0 == ack);
    ack = 0;

    //写入数据到EEPROM
    write_iic_reg(IICDS ,iic_cdev->write_buffer);
    write_iic_reg(IICCON,0xAF);//清除中断

    //while (read_iic_reg(IICSTAT) & IICSTAT_RECV_ACK);
    while (0 == ack);
    ack = 0;
   
    iic_stop(0xD0);
    write_iic_reg(IICCON,0xAF);//清除中断
    udelay(1000);

    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设备关闭函数
** 输入参数:inodefilp
** 输出参数:无
** 返 回 值: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, struct pt_regs *regs)
{
    ack = 1;
    printk("***********I am in interrupt fun********\n");
    return IRQ_HANDLED ;

}

/*************************************************
** 函 数 名:iic_stop
** 功能描述:停止IIC操作命令符
** 输入参数:cmd。停止TX操作,cmd = 0xDO,停止RX操作,cmd = 0x90
** 输出参数:无
** 返 回 值:无
** 创建日期:2012-07-11
** 作    者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
void iic_stop(char cmd)
{
    write_iic_reg(IICSTAT,cmd);
    udelay(1000);
    //Clear pending condition & Resume the operation (when write).Resumes IIC operation.
   // write_iic_reg(IICCON,0xAF);

}
/*************************************************
** 函 数 名:iic_read
** 功能描述:用户数据read系统调用函数
** 输入参数:filpbufsizeoff
** 输出参数:无
** 返 回 值:读取的字节数
** 创建日期: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);//这个地址传入I有问题
    }
    count = 0;
    ret = copy_to_user(buf, iic_cdev->read_buffer, size);
    return ret;
}

/*************************************************
** 函 数 名:iic_write
** 功能描述:用户调用write系统调用函数
** 输入参数:filp   bufsizeoff
** 输出参数:无
** 返 回 值:写的字节数
** 创建日期:2012-07-11
** 作    者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
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);   //地址传入I有问题
    }
    count = 0;
    return ret;
}

/*************************************************
** 函 数 名:iic_ioctl
** 功能描述:用户调用ioctl函数的系统调用函数
** 输入参数:inodepfilp   cmd   arg
** 输出参数:无
** 返 回 值:0
** 创建日期:2012-07-11
** 作    者:
** 修改日期:
** 修 改 者:
** 修改说明:
** 附加说明:
**************************************************/
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("SorinLee");
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 = {0,};
    unsigned char writebuf = {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);
    }
    close(fd);
    return 0;
}
请各位大侠,高手,老手,老师,教授帮小弟看看,希望能趁早把这个问题解决掉,谢谢各位

azfa123 发表于 2012-08-15 22:37

其他没细看,帮不上忙呀,这玩意主要靠做实验测试。
提一点:你ack 知道加volatile,为什么delay里面的i,j不加呢,你不怕被优化掉?

lanejim 发表于 2012-08-16 20:22

个人认为,delay里面的i,j是局部变量,不会被优化的

lanejim 发表于 2012-08-26 15:16

没人帮助一下我这个新手吗?:dizzy:

__SevenEleven 发表于 2012-09-03 09:06

代码贴的这么乱
进不了中断,先用示波器试试硬件产生中断没
软后再看看软件问题,到网上搜搜了,无非就那几个注意的地方,在linux下好办多了
页: [1]
查看完整版本: 小弟请求大侠帮忙看看S3C2410 的 IIC 的AT24C02的驱动程序,郁闷我一个月了