天嵌 ARM开发社区

 找回密码
 注册
查看: 2299|回复: 3

TQ2440的eeprom驱动的编写

[复制链接]
aguei 发表于 2012-11-15 17:05:18 | 显示全部楼层 |阅读模式
一直想写一个程序驱动板上的24C02,限于linux-I2C总线的架构比较复杂,于是想尝试按自己的想法写一个简单的驱动。在网上查找了一些资料,也参考了相关的程序,花了2天时间终于把驱动是编写完成了,可是加载一运行发现始终进不了I2C中断程序,我仔细的检查了程序,并把相关的寄存器值打印出来,也没发现什么错误。我把程序贴出来,希望大侠们能指点迷津
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/device.h>

#define DEVICE_NAME  "eeprom"  
static dev_t devno;
static struct cdev *eeprom_cdev;
static struct class *eeprom_class;
  
/*****************************************************/
  
static int eeprom_open(struct inode *,struct file *);
static int eeprom_release(struct inode *,struct file *);
static ssize_t eeprom_write(struct file *filp,const char *buf,size_t count,loff_t *f_ops);
static ssize_t eeprom_read(struct file *filp,char *buf,size_t count,loff_t *f_ops);
static ssize_t eeprom_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long data);
  
volatile static int *GPECON=NULL;//GPE Part define
volatile static int *GPEDAT=NULL;
volatile static int *GPEUP=NULL;
  
volatile static int *S3C2440_CLKCON=NULL; // 控制i2c的时钟
volatile static int *IICCON=NULL;//SPI Part define
volatile static int *IICADD=NULL;
volatile static int *IICSTAT=NULL;
volatile static int *IICDS=NULL;
volatile static int *IICLC=NULL;

volatile static int *INTMASK=NULL;
volatile static int *SRCPND=NULL;
volatile static int *INTPND=NULL;
volatile static int *INTMODE=NULL;

#define EEPROM_ADDR         0X00
#define START_ADDR            0X00

#define WRDATA      (1)
#define RDDATA      (2)

typedef struct S3C24xx_I2C {
    unsigned char *pData;   /* 数据缓冲区 */
    volatile int DataCount; /* 等待传输的数据长度 */
    volatile int Status;    /* 状态 */
    volatile int Mode;      /* 模式:读/写 */
    volatile int Pt;        /* pData中待传输数据的位置 */
}S3C24xx_I2C_t, *pS3C24xx_I2C;

static S3C24xx_I2C_t g_S3C24xx_I2C;

static DECLARE_WAIT_QUEUE_HEAD(eeprom_waitq);
/**********************************************************/
static const struct file_operations eeprom_fops =  
{
    .owner=THIS_MODULE,
    .open=eeprom_open,
    .read=eeprom_read,
    .ioctl=eeprom_ioctl,
    .release=eeprom_release,
    .write=eeprom_write,
};
  
/********************************************************/
/*
* 主机发送
* slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度
*/
static int S3C24xx_i2c_write(unsigned int slvAddr, unsigned char *buf, int len)
{
 楼主| aguei 发表于 2012-11-15 17:06:29 | 显示全部楼层
/********************************************************/
/*
* 主机发送
* slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度
*/
static int S3C24xx_i2c_write(unsigned int slvAddr, unsigned char *buf, int len)
{       
    g_S3C24xx_I2C.Mode = WRDATA;   // 写操作
    g_S3C24xx_I2C.Pt   = 0;        // 索引值初始为0
    g_S3C24xx_I2C.pData = buf;     // 保存缓冲区地址
    g_S3C24xx_I2C.DataCount = len; // 传输长度
   
    *IICDS   = slvAddr;
    *IICSTAT = 0xf0;         // 主机发送,启动

    printk("SRCPND=%08X, INTMODE=%08X, INTMASK=%08X, INTPND=%08X \n",    \
                *SRCPND, *INTMODE, *INTMASK, *INTPND);
    printk("IICCON=%02X  IICADD=%02X  IICDS=%02X  IICSTAT=%02X\n",    \
                *IICCON, *IICADD, *IICDS, *IICSTAT);
    /* 等待直至数据传输完毕 */   
    //while (g_S3C24xx_I2C.DataCount != -1);
    interruptible_sleep_on(&eeprom_waitq);
       
   return 0;
}
        
/*
* 主机接收
* slvAddr : 从机地址,buf : 数据存放的缓冲区,len : 数据长度
*/
static int S3C24xx_i2c_read(unsigned int slvAddr, unsigned char *buf, int len)
{
       
    g_S3C24xx_I2C.Mode = RDDATA;   // 读操作
    g_S3C24xx_I2C.Pt   = -1;       // 索引值初始化为-1,表示第1个中断时不接收数据(地址中断)
    g_S3C24xx_I2C.pData = buf;     // 保存缓冲区地址
    g_S3C24xx_I2C.DataCount = len; // 传输长度
   
    *IICDS        = slvAddr;
    *IICSTAT      = 0xb0;    // 主机接收,启动
   
    /* 等待直至数据传输完毕 */   
    //while (g_S3C24xx_I2C.DataCount != -1);
    interruptible_sleep_on(&eeprom_waitq);
       
   return 0;
}

/*
* I2C中断服务程序
* 根据剩余的数据长度选择继续传输或者结束
*/
//void S3C24xx_I2CIntHandle(void)
static irqreturn_t S3C24xx_I2CIntHandle(int irq, void *dev_id)
{
    unsigned int iicSt,i;

    printk("S3C24xx_I2CIntHandle\n");
    iicSt  = *IICSTAT;
    if(iicSt & 0x8){ printk("Bus arbitration failed\n\r"); }

    switch (g_S3C24xx_I2C.Mode)
    {   
        case WRDATA:
        {
            if((g_S3C24xx_I2C.DataCount--) == 0)
            {
                // 下面两行用来恢复I2C操作,发出P信号
                *IICSTAT = 0xd0;
                *IICCON  = 0xaf;
                udelay(10);  // 等待一段时间以便P信号已经发出
                wake_up_interruptible(&eeprom_waitq);
                break;   
            }

            *IICDS = g_S3C24xx_I2C.pData[g_S3C24xx_I2C.Pt++];
            
            // 将数据写入IICDS后,需要一段时间才能出现在SDA线上
            for (i = 0; i < 10; i++);   

            *IICCON = 0xaf;      // 恢复I2C传输
            break;
        }

        case RDDATA:
        {
            if (g_S3C24xx_I2C.Pt == -1)
            {
                // 这次中断是发送I2C设备地址后发生的,没有数据
                // 只接收一个数据时,不要发出ACK信号
                g_S3C24xx_I2C.Pt = 0;
                if(g_S3C24xx_I2C.DataCount == 1)
                   *IICCON = 0x2f;   // 恢复I2C传输,开始接收数据,接收到数据时不发出ACK
                else
                   *IICCON = 0xaf;   // 恢复I2C传输,开始接收数据
                break;
            }
            
            if ((g_S3C24xx_I2C.DataCount--) == 0)
            {
                g_S3C24xx_I2C.pData[g_S3C24xx_I2C.Pt++] = *IICDS;

                // 下面两行恢复I2C操作,发出P信号
                *IICSTAT = 0x90;
                *IICCON  = 0xaf;
                udelay(10);  // 等待一段时间以便P信号已经发出
                wake_up_interruptible(&eeprom_waitq);
                break;   
            }      
           
           g_S3C24xx_I2C.pData[g_S3C24xx_I2C.Pt++] = *IICDS;

           // 接收最后一个数据时,不要发出ACK信号
           if(g_S3C24xx_I2C.DataCount == 0)
               *IICCON = 0x2f;   // 恢复I2C传输,接收到下一数据时无ACK
           else
               *IICCON = 0xaf;   // 恢复I2C传输,接收到下一数据时发出ACK
           break;
        }
      
        default:
            break;      
    }
    return IRQ_RETVAL(IRQ_HANDLED);
}
 楼主| aguei 发表于 2012-11-15 17:07:06 | 显示全部楼层
/********************************************************/
static int eeprom_open(struct inode *inode,struct file *filp)
{
        int ret;

        printk("eeprom_open!\n");
        filp->private_data =&eeprom_cdev;     
        /***********************************************
        *PCLK CONFIG
        ************************************************/
        /*control PCLK into i2c block*/
        *S3C2440_CLKCON |= 1<<16;
        printk("S3C2440_CLKCON=%X\n",*S3C2440_CLKCON);
        /***********************************************
        *GPE PORTS CONFIG
        ************************************************/
        *GPECON |=0xA0000000;  //引脚功能选择
        *GPEUP |=0xC000;  //禁止内部上拉
        *GPEDAT |= (1<<15) | (1<<14);
        /***********************************************
        *I2C CONFIG
        ************************************************/
        *IICCON = (1<<7) | (0<<6) | (1<<5) | (0XF);  
        *IICADD = 0X10;
        *IICSTAT = 0x10;
        *INTMASK &= ~(1<<27);
        /***********************************************
        *中断注册
        ************************************************/
         ret = request_irq(IRQ_IIC, S3C24xx_I2CIntHandle, IRQF_DISABLED, "S3c24xx_i2c", NULL);
         printk("irq_ret:%d\n", ret);
         if(ret<0){
                 printk("Register irq fail!\n");
                return ret;
        }
        //enable_irq(IRQ_IIC);
       
        return 0;
}
  
  
static int eeprom_release(struct inode *inode,struct file *filp)
{
    //free irq
    //disable_irq(IRQ_IIC);
    free_irq(IRQ_IIC, NULL);
  
    printk("<1>eeprom_release\n");
    return 0;
}

static ssize_t eeprom_read(struct file *filp,char __user *buf,size_t count,loff_t *f_ops)
{
        char *kbuf;

        printk("<1>eeprom read!\n");
        kbuf = kmalloc(count, GFP_KERNEL);
        kbuf[0]=START_ADDR;
        S3C24xx_i2c_write(EEPROM_ADDR, kbuf, 1);  //写入读取起始地址
        S3C24xx_i2c_read(EEPROM_ADDR, kbuf, count);
        if(copy_to_user(buf,kbuf,count))
                return -1;

        kfree(kbuf);
        return count;
}
  
static ssize_t eeprom_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops)
{
    char *kbuf;
    printk("<1>eeprom write!,count=%d\n",count);
    kbuf=kmalloc(count,GFP_KERNEL);
    if(copy_from_user(&kbuf[1],buf,count))
    {
        printk("no enough memory!\n");
        return -1;
    }

    kbuf[0]=START_ADDR;  //起始地址
    S3C24xx_i2c_write(EEPROM_ADDR, kbuf, count+1);
    printk("write 0x%02X!\n",*kbuf);
    kfree(kbuf);
       
    return count;
}
  
static ssize_t eeprom_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long data)
{
    return 0;
}
  
  
static int __init eeprom_init(void)
{
        int ret;

        ret = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
        if(ret<0){
                printk(KERN_DEBUG "Can't apply to the device number!\n");
                return ret;
        }

        eeprom_cdev = cdev_alloc();
        cdev_init(eeprom_cdev, &eeprom_fops);
        eeprom_cdev->owner = THIS_MODULE;
        eeprom_cdev->ops = &eeprom_fops;
        ret = cdev_add(eeprom_cdev, devno, 1);
        if (ret<0) {
                printk(KERN_NOTICE "Register %s fail\n", DEVICE_NAME);
                return ret;
        }

        eeprom_class = class_create(THIS_MODULE, DEVICE_NAME);
        device_create(eeprom_class, NULL, devno, NULL, "%s",DEVICE_NAME);

        S3C2440_CLKCON = (int *)ioremap(0x4C00000c,3);

        GPECON= (int *)ioremap (0x56000040,4);
        GPEDAT= (int *)ioremap (0x56000044,2);
        GPEUP= (int *)ioremap (0x56000048,2);

        IICCON= (int *)ioremap (0x54000000,1);
        IICSTAT= (int *)ioremap (0x54000004,1);
        IICADD= (int *)ioremap (0x54000008,1);
        IICDS= (int *)ioremap(0x5400000C,1);
        IICLC= (int *)ioremap(0x54000010,1);

        SRCPND= (int *)ioremap(0x4A000000,4);
        INTMODE= (int *)ioremap(0x4A000004,4);
        INTMASK= (int *)ioremap(0x4A000008,4);
        INTPND= (int *)ioremap(0x4A000010,4);

        printk("Register %s success!\n",DEVICE_NAME);   
        return ret;
}
  
  
static void __exit eeprom_exit(void)
{
        cdev_del(eeprom_cdev);
        unregister_chrdev_region(devno, 1);
        device_destroy(eeprom_class, devno);
        class_destroy(eeprom_class);
        printk("<1>eeprom_exit!\n");
}
  
module_init(eeprom_init);
module_exit(eeprom_exit);
  
MODULE_LICENSE("GPL");
MODULE_AUTHOR("aguei");
MODULE_DESCRIPTION("eeprom driver for S3C2440");
 楼主| aguei 发表于 2012-11-15 17:08:06 | 显示全部楼层
测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
  
int main(int argc, char **argv)
{
        int fd;
        int count=0;
        int i;
        char buf[5]={0x11,0x22,0x33,0x44,0x55};
        fd = open("/dev/eeprom", O_RDWR);
        if (fd < 0) {
            perror("open device eeprom");
            exit(1);
        }
        count=write(fd,buf,sizeof(buf));
        if(count){
                memset(buf, 0, sizeof(buf));
                count = read(fd,buf,sizeof(buf));
                for(i=0;i<count;i++)
                        printf("read byte is: 0x%02X\n",buf[i]);
        }
        close(fd);
        return 0;
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-5-17 19:48 , Processed in 1.031250 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表