⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 44b0-iic-drive.txt

📁 实现基于44bo嵌入式系统环境下的IIC驱动程序
💻 TXT
字号:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>

#include <linux/poll.h>
#include <asm/irq.h>
#include <asm/arch/irq.h>
#include <asm/arch/irqs.h>
#include <asm/arch/s3c44b0x.h>

#include "config.h"
#include "44b.h"

#define IIC_MAJOR 232
#define IIC_NAME "xiuiic"
#define S3C44B0X_INTERRUPT_IIC 5
#define XIUIIC_DEBUG

static DECLARE_WAIT_QUEUE_HEAD(wait);

volatile uint8 I2C_sla = 0xa0;                   //从机地址
volatile uint8 I2C_suba = 0x00;                   //子地址
volatile uint8 iic_usage = 0;
volatile uint8 ack_tag;
volatile uint8 I2cReadWrite;


#undef PDEBUG                 /* undef it, just in case */
#ifdef XIUIIC_DEBUG
#      ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
#        define PDEBUG(fmt, args...) printk( KERN_INFO "xiuiic: " fmt, ## args)
#      else
/* This one for user space */
#        define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
#      endif
#else
#      define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif


static void board_init()
{
        rPDATF = 0X0;
        rPCONF = (rPCONF&0xfffffff0)|0x0a;      //SDA,SCL
        rPUPF = rPUPF|0x3; //disable SDA and SCL pull up
        rSYSCFG=SYSCFG_8KB;
}

void vdelay(unsigned short i)
{
        ushort cm = 0;
        while(cm < i)
        {
            cm++;
        }
}

static int iic_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
   
        return(0);
}

static loff_t iic_llseek(struct file *filp,loff_t off,int whence)
{
  
        return(0);
}

static ssize_t iic_read(struct file *filp,char *buf,size_t count,loff_t *f_pos)
{

       // char ker_buf;
char *ker_buf;
        char *ptr;
int i;      //the number of data truly read

        I2cReadWrite=0;   
ack_tag = 0;
PDEBUG( "enter to read function\n");  

if ((ker_buf = kmalloc(count,GFP_KERNEL)) == NULL) //dynamic allocation
      PDEBUG("kmalloc error\n");
ptr = ker_buf;

PDEBUG( "start to transfer slave addr 0xa0\n");
rIICDS = I2C_sla;      // 0xa0
        rIICSTAT = 0xf0;       // Master Tx,Start
        wait_event_interruptible(wait, (ack_tag != 0)); //wait the trans complete
        ack_tag = 0;

        //      PDEBUG("start to transfer sub-addr 0x00\n");
        rIICDS = I2C_suba;
        rIICCON = 0xe2;         // resumes IIC operation.
        wait_event_interruptible(wait, (ack_tag != 0)); //wait the trans complete
        ack_tag = 0;

// PDEBUG("start to transfer slave addr 0xa1\n");
rIICDS = I2C_sla|0x01;      // 0xa1:Read
        rIICSTAT=0xb0;        // Master Rx,Start
        rIICCON=0xe2;         // resumes IIC operation.   
        wait_event_interruptible(wait, (ack_tag != 0)); //wait the trans complete
        ack_tag = 0;

   
        *ptr = rIICDS;      //ack from slave device

//begin to loop???????????应该把ack清零吗?

PDEBUG("start to transfer data\n");
for (i = 1; i < count; i++)      //only read count-1 data
{
      rIICCON = 0xe2; //????????????????rIICCON = 0xe2 & (~0x80)
      wait_event_interruptible(wait, (ack_tag != 0));
      ack_tag = 0;
      *ptr = rIICDS;
      PDEBUG("readbuf[%d] = %c\n", i, *ptr);
            ptr++;
}

        //PDEBUG("the first data in buf is %d\n", user_buf[0]);   
      rIICCON = 0xe2 & (~0x80) ;//disable ack,the last data disable ack
wait_event_interruptible(wait, (ack_tag != 0)); //wait the trans complete
        ack_tag = 0;

        PDEBUG("the last data in rIICDS is %c\n", rIICDS);
        *ptr = rIICDS; //read the last data
   
rIICSTAT = 0x90;//write this register,so send stop signal
        rIICCON =      0xe2;//resume IIC operation
        vdelay(100);
        copy_to_user(buf, ker_buf, i);      //if i=1 < count means not read a part of data
        rI_ISPC = rI_ISPC | BIT_IIC;//CLEAR PENDING BIT OF IIC TO MEAN IT IS FREE
        kfree(ptr);

return(i);
}

static int iic_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos)
{
char *ker_buf;
        char *ptr;
int i;      //the data

        //char ker_buf;
        PDEBUG("entering write function\n");
if ((ker_buf = kmalloc(count,GFP_KERNEL)) == NULL) //dynamic allocation
      PDEBUG("kmalloc error\n");
        copy_from_user(ker_buf, buf, count);
ptr = ker_buf;
ack_tag = 0;
I2cReadWrite=1;
//rIICSTAT=0x10;      // enbale TX/RX 
        rIICDS = I2C_sla;      // 0xa0
        rIICSTAT=0xf0;        // Master Tx,Start

PDEBUG("start to transfer the addr of slave device\n");
        wait_event_interruptible(wait, (ack_tag != 0)); //wait the trans complete
        ack_tag = 0;

        PDEBUG("start to transfer the sub-addr\n");
        rIICDS = I2C_suba;
        rIICCON = 0xe2;         // resumes IIC operation.
        wait_event_interruptible(wait, (ack_tag != 0)); //wait the trans complete
        ack_tag = 0;
// begin to write
PDEBUG("start to transfer data\n");
for (i = 0; i <count; i++)
{
         rIICDS = *ptr;     
         rIICCON = 0xe2;         // resumes IIC operation.
         wait_event_interruptible(wait, (ack_tag != 0)); //wait the trans complete
         ack_tag = 0;
      PDEBUG("buf[%d] = %c\n", i, rIICDS);
      ptr ++;
}

PDEBUG("begin to end\n");
        rIICSTAT = 0xd0;      // stop Master Tx condition
        rIICCON = 0xe2;       // resumes IIC operation.

        PDEBUG("we have write %d numbers in to epprom\n", i);
        rI_ISPC = rI_ISPC | BIT_IIC;//CLEAR PENDING BIT OF IIC TO MEAN IT IS FREE
        vdelay(100);
        kfree(ptr);
        return(i);
}

static void iic_irq(int irq, void *dev_id,struct pt_regs *regs)
{
ack_tag = 1;
        wake_up_interruptible(&wait);
rI_ISPC = rI_ISPC | BIT_IIC;
}

static int iic_open(struct inode *inode,struct file *filp)
{
int ret;
unsigned long flag = 0;
   
if (iic_usage == 0)
{
            ret = request_irq(S3C44B0X_INTERRUPT_IIC,iic_irq,SA_INTERRUPT,IIC_NAME,NULL);
      if (ret)
      {
       PDEBUG("%s: iic driver irq request failed.\n",IIC_NAME);
       free_irq(S3C44B0X_INTERRUPT_IIC,NULL);
       return(ret);
      }
} 
   
        PDEBUG("%s: request irq success.\n", IIC_NAME);

        local_irq_save(flag);
        board_init();
        rIICADD = 0x10;//slave addr 
        //IIC operation configure
        rIICCON=0xe2;      //Enable ACK,interrupt, IICCLK=MCLK/512, Enable ACK//64Mhz/512/(9+1) = 12.5Khz 
        rIICSTAT = 0x10;      // enbale TX/RX 

        PDEBUG("before INTPND = %d\n", rINTPND);
        rI_ISPC = rI_ISPC | BIT_IIC;//CLEAR PENDING BIT OF IIC TO MEAN IT IS FREE
        PDEBUG("after INTPND = %d\n", rINTPND);
        //init_waitqueue_head(&wait);
    
        PDEBUG("before mask = %d\n", rINTMSK);
rINTMSK = rINTMSK & ~BIT_IIC;// & ~BIT_GLOBAL;//ENABLE IIC AND GLOBAL INTERRUPT
        PDEBUG("after mask = %d\n", rINTMSK);
    
        local_irq_restore(flag);
        iic_usage ++;
PDEBUG("iic_usage is %d\n",iic_usage);
MOD_INC_USE_COUNT;
       return(0);
}

static int iic_release(struct inode *inode,struct file *filp)
{
      unsigned long flag = 0;
        vdelay(100);
        MOD_DEC_USE_COUNT;

        if(iic_usage)iic_usage --;
       if(iic_usage==0)
        {
            local_irq_save(flag);          
            //PDEBUG("INTPND = %d\n", rINTPND);
            //rI_ISPC = rI_ISPC | BIT_IIC;//CLEAR PENDING BIT OF IIC TO MEAN IT IS FREE
            //PDEBUG("INTPND = %d\n", rINTPND);
            //rINTMSK = rINTMSK | BIT_IIC;
            local_irq_restore(flag);
            free_irq(S3C44B0X_INTERRUPT_IIC,NULL);
            PDEBUG("enter release\n");
        }

        return(0);
}

static struct file_operations iic_fops={
        //       owner:THIS_MODULE,
llseek:iic_llseek,
read:      iic_read,
write: iic_write,
open:      iic_open,
release:iic_release,
ioctl:iic_ioctl,
};

static int __init myiic_init(void)
{
        int result;

        result=register_chrdev(IIC_MAJOR,IIC_NAME,&iic_fops);
        if(result==0){
            PDEBUG("%s: iic driver installed.\n", "myiic");
            return 0;
        }
        PDEBUG("%s:IIC driver install fail.\n","myiic");
        return(result);
}

static void __exit myiic_exit(void)
{
        int ret;
        ret = unregister_chrdev(IIC_MAJOR,IIC_NAME);
        if (ret < 0)
        {
            PDEBUG( KERN_ALERT "unregister fail\n");
            return;
        }
        PDEBUG(KERN_ALERT "leddrv:good_bye!\n");
}

module_init(myiic_init);
module_exit(myiic_exit);

/******************************************************************************************

测试程序

********************************************************************************************/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ioctl.h>


int
main(int argc, char **argv)
{
        int fd;
        int count = 16;
        char wbuf[16] = "mingming shi zhu";
        char rbuf[16];
char *ptr;
        int i;
        // printf("enter main\n");
        // printf("\n");
   
        if ((fd = open("/var/tmp/ming/driver/IIC_test/xiuiic", O_RDWR)) == -1)
        {
            perror("open error\n");
            exit(1);
        }
        printf("open ok\n");
        printf("fd = %d\n",fd);

   
        // printf("%s\n", wbuf);
        // fflush((void *)STDOUT_FILENO);
         if (write(fd, wbuf, count) != count)
         {
            perror("write error\n");
            exit(1);
         }
         printf("we have write %d characters\n", count);

         //test write by reading
         if (read(fd, &rbuf, count) != count)
         {
             perror("read error\n");
             exit(1);
         }
      ptr = rbuf;
for ( i = 0; i < count; i++)
{
      printf("read[%d] = %c\n", i, *ptr);
      ptr ++;
}
        printf("\n");
        close(fd);
        return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -