2440IIC驱动

TQ2440IIC驱动移植(非内核自带代码)

 

先前已经做了一个TQ2440IIC驱动的实验(是内核自带的代码),具体看我的上一篇文章,那么今天做这个实验是自己写的代码的移植(应该说是网上的模板,自己稍加修改)。说真的,自己做这个移植的时候还是比较困难的(相对于自己是一个初学者来说,虽然说它的原理来说,不是很难,但是实际的移植就会遇到比较多的细节问题),为了给自己的学习做一下总结,故把自己的移植过程简单地说一下(后面给出驱动代码和测试代码),同时希望高手们能够给我们这些初学者多多提些建议……

一、            include的路径问题:

头文件的路径不单单是顶层include下的文件,还有一些子目录下的include,当在顶层include下找不到一些文件时,我们就要在子目录下查找了。

二、            获取总线时钟问题:

我先前没有移植成功(我先前做过一次移植,是内核自带的iic移植,具体看我的上一篇博客文章),很大程度上是这个问题,我先前是直接写CLKCON这个寄存器,在调试的时候,好像是东西是写不到这个CLKCON里面去的,后来就改成用下面的方法来获取IIC总线时钟:

       iic_clock = clk_get(NULL, "i2c");

       if (!iic_clock)

       {

              printk(KERN_ERR "failed to get adc clock source\n");

              return -ENOENT;

       }

       clk_enable(iic_clock);

改了之后就真的有进展了,呵呵……

三、            等待队列问题:

如果没有等待队列,那么在运行时CPU的使用率就会是100%,所以一般有中断的地方都会用到等待队列:

       wait_event_interruptible(iic_waitq, ack);

       wake_up_interruptible(&iic_waitq);

这两个都是配套使用的。

四、            barrier函数的问题:

barrier()

barrier函数貌似是强制顺序写入,我在调试过程中先前是没有用到barrier函数的,在运行的时候有时能够正常,有时不行,用了barrier之后呢程序就运行得稳定点,但有时还是运行不下去(进入不了中断),总而言之,这个barrier函数还是有点用吧,呵呵……

五、            关于信号量的问题:

信号量是我后面才加上去的,就当是对阻塞型IO的驱动程序的完善吧……

 

下面贴出代码,程序比较乱,主要是调试时弄的,凑合着看吧……

实验环境:

硬件:TQ2440

软件:linux2.6.25.8

驱动代码:

 

///

 

#include 3c/iic.h>

#include

#include

#include

#include

//

#include

//#include

#include

#include

#include

//#include

#include

#include

#include

#include 3c2410/regs-gpio.h>

#include

#include 3c2410/irqs.h>

#include

#include

#include

/

#define S3C2410_IICCON_ACKEN (1<<7)

#define S3C2410_IICCON_TXDIV_16 (0<<6)

#define S3C2410_IICCON_IRQEN (1<<5)

#define S3C2410_IICLC_FILTER_ON (1<<2)

#define S3C2410_IICLC_SDA_DELAY5 (0x01)

/

 

 

#define  DEV_ID  110

#define  DEV_NAME  "2402_RW"

#define  IICCON  0x54000000

#define  IICSTAT 0x54000004

#define  IICDS   0x5400000c

#define  IICADD  0x54000008

#define  IICLC   0x54000010

//#define  CLKCON  0x4c00000c

 

//

 

static DECLARE_WAIT_QUEUE_HEAD(iic_waitq);

static struct clk      *iic_clock;

static void *S3C2402_IICSTAT;

static void *S3C2402_IICCON;

static void *S3C2402_IICDS;

static void *S3C2402_IICADD;

static void *S3C2402_IICLC;

//static void *S3C2440_CLKCON;

static int wr_data[5];

static int ra_data[5];

static int ack=0;

struct semaphore sem;

//wait_queue_head_t iic_waitq;

void delay(int t)

{

       int i;

        for(;t>0;t--)

        {

               for(i=0;i<20000;i++);

        }

  }

static void ioremap_2402( void )

{

        S3C2402_IICCON=ioremap(IICCON,0x00000004);                       S3C2402_IICSTAT=ioremap(IICSTAT,0x00000004);

        S3C2402_IICDS=ioremap(IICDS,0x00000004);

        S3C2402_IICADD=ioremap(IICADD,0x00000004);

        S3C2402_IICLC=ioremap(IICLC,0X00000004);

}

static void iounremap_2402( void )

{

       iounmap( S3C2402_IICCON );

       iounmap( S3C2402_IICSTAT );

       iounmap( S3C2402_IICDS );

       iounmap( S3C2402_IICADD );

       iounmap( S3C2402_IICLC );

}

static int open_2402(struct inode * inode, struct file * file)

{       

         int cmmd;

       if( down_interruptible(&sem) )

              return -ERESTARTSYS;

         writel(0xc0000,S3C2410_GPEUP);

//     barrier();

         s3c2410_gpio_cfgpin(S3C2410_GPE14,S3C2410_GPE14_IICSCL);

         s3c2410_gpio_cfgpin(S3C2410_GPE15,S3C2410_GPE15_IICSDA);         iic_clock = clk_get(NULL, "i2c");

       if (!iic_clock)

       {

              printk(KERN_ERR "failed to get adc clock source\n");

              return -ENOENT;

       }

       clk_enable(iic_clock);

 

       cmmd=((S3C2410_IICCON_ACKEN) | (S3C2410_IICCON_TXDIV_16) | (S3C2410_IICCON_IRQEN) |  (0x0f));

 

        writel(cmmd,S3C2402_IICCON);     

        writel(0x10,S3C2402_IICADD);                          

        writel(0x10,S3C2402_IICSTAT);                         

        writel((S3C2410_IICLC_FILTER_ON | S3C2410_IICLC_SDA_DELAY5) , S3C2402_IICLC);

       barrier();

        printk("open successed!!!!!!!!!!!!\n");

       return 0;

     }

 

 

 

static int  write_2402(struct file * file, const char __user * userbuf,size_t count, loff_t * off)

{ 

 

    int i;

    ack=0;

       if(copy_from_user(wr_data,userbuf,count) != 0 )   

 

        {

       printk("write is error!!\n");

        return  EFAULT;

        }

       printk("write is go on!!\n");

       writel(( 3<<6 ) | (1 <<4 ),S3C2402_IICSTAT);

       writel(0xaf,S3C2402_IICCON);

        writel(0xa0,S3C2402_IICDS);                     

        writel(0xf0,S3C2402_IICSTAT);       

       barrier();

       if (!ack)

       {

              printk("ready wait!!\n");

              if (file->f_flags & O_NONBLOCK)

                     return -EAGAIN;

              else

                     wait_event_interruptible(iic_waitq, ack);

             

       }

 

       ack = 0;

 writel(0x00,S3C2402_IICDS);                    

 writel(0xaf,S3C2402_IICCON);    

// barrier();

 udelay(100);

 //while(ack==0);

 //ack=0 ;

 for(i=0;i<5;i++)

 {

       writel(wr_data[i],S3C2402_IICDS);          

       printk("wr_data=%x\n",wr_data[i]);

       writel((readl(S3C2410_GPFDAT)|wr_data[i]),S3C2410_GPFDAT);

       writel(0xaf,S3C2402_IICCON);

       barrier();

       udelay(100);

//     while(ack==0);

       if (!ack)

       {

              if (file->f_flags & O_NONBLOCK)

                     return -EAGAIN;

              else

                     wait_event_interruptible(iic_waitq, ack);

       }

 

       ack = 0;

      printk("ack=%x\n",ack);

//    ack=0;

   }

        writel(0xd0,S3C2402_IICSTAT);                

         writel(0xaf,S3C2402_IICCON);

barrier();    

         udelay(100);

         return count;

  }

static unsigned int poll_2402( struct file *file, struct poll_table_struct *wait)

{

       unsigned int mask = 0;

       poll_wait(file, &iic_waitq, wait);

       if (ack)

              mask |= POLLIN | POLLRDNORM;

      

       return mask;

}

static int  read_2402 (struct file * file, char __user * userbuf, size_t count, loff_t * off)

{ 

    int i,a;

    ack=0;

    writel(0xa0,S3C2402_IICDS);                    

    writel(0xf0,S3C2402_IICSTAT);                 

       barrier();

    udelay(100);

while(ack==0);

// ack=0;

       if (!ack)

       {

              if (file->f_flags & O_NONBLOCK)

                     return -EAGAIN;

              else

                     wait_event_interruptible(iic_waitq, ack);

       }

 

       ack = 0;

      writel(0x00,S3C2402_IICDS);                   

      writel(0xaf,S3C2402_IICCON);

barrier();

      udelay(100);

      // while(ack==0);

      // ack=0;

       if (!ack)

       {

              if (file->f_flags & O_NONBLOCK)

                     return -EAGAIN;

              else

                     wait_event_interruptible(iic_waitq, ack);

       }

 

       ack = 0;

      writel(0xa1,S3C2402_IICDS);                    

      writel(0xb0,S3C2402_IICSTAT);                

      writel(0xaf,S3C2402_IICCON);

barrier();

      udelay(100);

      a=readl(S3C2402_IICDS);

      printk("a=%x\n",a);

      for (i=0;i<5;i++)

      {

          //while(ack==0);

          // printk("ack=%x\n",ack);

          //  ack=0;

       if (!ack)

       {

              if (file->f_flags & O_NONBLOCK)

                     return -EAGAIN;

              else

                     wait_event_interruptible(iic_waitq, ack);

       }

 

       ack = 0;

      writel(0xaf,S3C2402_IICCON);

       barrier();

      udelay(100);

      ra_data[i]=readl(S3C2402_IICDS);              

      writel((readl(S3C2410_GPFDAT)|ra_data[i]),S3C2410_GPFDAT);

barrier();

      printk("ra_data=%x\n",ra_data[i]);

    }

    writel(0x90,S3C2402_IICSTAT);               

    writel(0xaf,S3C2402_IICCON);

       barrier();

    udelay(100);

 if(copy_to_user(userbuf,ra_data,count)!=0)   

    {

        printk("read is error!!\n");

         return EFAULT;

    }

      return count;

}

static int release_2402(struct inode *inode, struct file *file)

{

       up(&sem);

       return 0;

}

static irqreturn_t iic_interrupt(int irq,void *dev_id,struct pt_regs *regs) 

{

        ack=1;      

       wake_up_interruptible(&iic_waitq); 

        return IRQ_HANDLED;

  }

static struct file_operations test_2402 =

{

       .owner      THIS_MODULE,

        .open      open_2402,

        .write      write_2402,

        .read       read_2402,

        .poll       poll_2402,

       .release     release_2402,

};

static struct class *i2c_class;

static int __init init_2402(void)

{

  int result,ret;

  init_MUTEX(&sem);

 

 ioremap_2402();

  result=register_chrdev(DEV_ID,DEV_NAME,&test_2402);

 

  if (result<0)

   {

        printk ("the derive register is fail!!!\n");

          return ENODEV;

   }

 

  else

   {

        printk ("the derive register is succss!!!\n");

         ret=request_irq(IRQ_IIC,&iic_interrupt,SA_INTERRUPT,DEV_NAME,&iic_interrupt);

 

       if(ret<0)

        {

              printk("the iic_interrupt is requestted fail\n");

          return ENODEV;

        }

 

          else

           {

             printk("the iic_interrupt is requestted sccuss!!\n");

             i2c_class = class_create(THIS_MODULE, DEV_NAME);

             if(IS_ERR(i2c_class))

             {

              printk("Err: failed in EmbedSky-leds class. \n");

              return -1;

             }

             class_device_create(i2c_class, NULL, MKDEV(DEV_ID, 0), NULL, DEV_NAME);

 

             printk(DEV_NAME " initialized\n");

             return 0;

              return ret;

         }

     return result;

     }

   }

static void __exit exit_2402(void)

{ 

         unregister_chrdev(DEV_ID,DEV_NAME);      

         disable_irq(IRQ_IIC);

        free_irq(IRQ_IIC,&iic_interrupt);

       //  devfs_remove(DEV_NAME);

       class_device_destroy(i2c_class, MKDEV(DEV_ID, 0));    

       class_destroy(i2c_class);

       if (iic_clock)

       {

              clk_disable(iic_clock);

              clk_put(iic_clock);

              iic_clock = NULL;

       }

       iounremap_2402();

        printk ("the derive is unregister\n");

   }

module_init(init_2402);

module_exit(exit_2402);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("WENJAK");

MODULE_DESCRIPTION("2402_READ_WRITE");

 

 

测试代码:

 

 

#include

#include

#include

#include

#include

#include

#include

 

#define PATH      "/dev/adc/0"          //device file

 

static struct ADC_DEV

{

       int channel;

       int prescale;

}adc_infor;

 

int main(void)

{

       int fd;

       int result, data;

       unsigned char val;

       int times = 0;

 

       fd = open(PATH, O_RDWR);

       if (fd < 0) {

              printf("Failed to open ad_driver\n");

              exit(1);

       }

      

       printf("Please select which chanel to read....\n");

         printf("0 : chanel--0\n");

       printf("1 : chanel--1\n");

         scanf("%d", &val);

 

       if((val !=0) && (val !=1))

              val = 0;                                      //by default the chanel is 0

 

       adc_infor.channel = val;                    //chanel 0 or 1

       adc_infor.prescale = 40;          

      

       do {

              result = write(fd, (void *)&adc_infor, sizeof(adc_infor)) == sizeof(struct ADC_DEV);   

              if (!result) {

                     printf("wrong when writing!\n");

                     goto failed;   

              }

             

              result = read(fd, &data, sizeof(data)) == sizeof(data);

              if (!result) {

                     printf("Wrong size!\n");

                     goto failed;   

              }

 

              printf("chanel %d --ad result=%d\n", val, data);

              sleep(1);

       }while((times++) < 10);

      

failed:

       close(fd);

      

       return 0;

}

上面的程序勉强能够运行出结果,但是总觉得有很多漏洞,希望朋友们能够多多提意见,以使我可以更加完善以上的代码……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值