打印

小弟请求大侠帮忙看看S3C2410 的 IIC 的AT24C02的驱动程序

[复制链接]
1772|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lanejim|  楼主 | 2012-8-15 21:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位大侠好,小弟恳请大侠帮我指点一下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;
}
请各位大侠,高手,老手,老师,教授帮小弟看看,希望能趁早把这个问题解决掉,谢谢各位

相关帖子

沙发
lanejim|  楼主 | 2012-8-16 22:24 | 只看该作者
自己先顶一下

使用特权

评论回复
板凳
lanejim|  楼主 | 2012-8-26 15:19 | 只看该作者
没人帮我一下吗?55555

使用特权

评论回复
地板
阿南| | 2012-8-30 20:30 | 只看该作者
呵呵,这么长的代码,大部分网友没有精力看下去的,望楼主见谅!
你可以把问题精减,提出重点和线索,期望有更多的网友给你指明些思路,不过解决问题还是需要你自己,祝好。

使用特权

评论回复
5
Dick00| | 2012-8-30 21:06 | 只看该作者
太长了,估计一步一步看完都得好久。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

9

帖子

1

粉丝