下面是我写的I2C的软驱动,希望对你们有帮助

 

#include <linux/mm.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <mach/at91_pio.h>
#include <mach/gpio.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/version.h>
/*通过测试也是可以的*/
#define DEV_NAME     "iic"    /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
//#define DEV_MAJOR   231              /* 主设备号 */
#define DEV_MAJOR 0    
#define DEV_MINOR 0
///
#define I2C_SCL_H        (at91_set_gpio_value(AT91_PIN_PA24, 1))
#define I2C_SCL_Low      (at91_set_gpio_value(AT91_PIN_PA24, 0))
#define I2C_SDA_OUT       (at91_set_gpio_output(AT91_PIN_PA23,1))   /* SDA OUT*/
#define I2C_SDA_IN        (at91_set_gpio_input(AT91_PIN_PA23, 1))   /* SDA IN*/
#define I2C_SDA_Low       (at91_set_gpio_value(AT91_PIN_PA23, 0))   /* SDA Low*/
#define I2C_SDA_H         (at91_set_gpio_value(AT91_PIN_PA23, 1))   /* SDA H*/
#define I2C_SDA_Value     (at91_get_gpio_value(AT91_PIN_PA23))      /* SDA H*/
//if(at91_get_gpio_value(AT91_PIN_PA0)==1)//读I/O就可以了 真他妈的搞不懂
///
//#define SPI_READ_MODE          _IOR('D', 1, long)
//#define SPI_WRITE_MODE  _IOW('D', 1, long)
#define TWD_CLOCK_H          _IOW('D', 2, int)
#define TWD_CLOCK_L          _IOW('D', 3, int)
//#define SPI_READ_DATA          _IOR('D', 4, long)
//#define SPI_WRITE_DATA  _IOW('D', 4, long)

struct i2c_dev
{
 dev_t devno; //变量是设备号
 int major;
 int minor;
 struct class_device *class_dev;
 struct class *class;
 struct cdev cdev;
};
struct i2c_dev *at91_i2c;
static void __iomem *pio_base;
/* 应用程序对设备文件/dev/led执行open(...)时, * 就会调用led_open函数 */
delay()
/**********************************************************************
**函数原型:    i2c_delay(int num)
**入口参数:      num
**出口参数: 无
**返 回 值: 无     
**说    明:   I2C的延迟函数
************************************************************************/
void i2c_delay(int num)
{
  int i;
  while(num--)
  {
     for(i = 0;i<100;i++);
  }
}
///*********************************************************************
///**函数原型:    void I2CStart()
///**入口参数:     无
///**出口参数:    无
///**返 回 值:    无     
///**说    明:    启动I2C总线
///**********************************************************************
void  I2cStart()
{
 I2C_SDA_OUT;                          //SDA输出
 I2C_SDA_H;                            //SDA=1;
 i2c_delay(50);                       //延时>1us
        I2C_SCL_H;                            //SCL=1;
 i2c_delay(250);                       //延时>4.7us
 I2C_SDA_Low;                          //SDA=0
 i2c_delay(250);                       //延时>4us
 I2C_SCL_Low ;                         //SCL=0;
 i2c_delay(50);                       //延时>1us
}
///**********************************************************************
///**函数原型:      void I2cSendByte(int data)
///**入口参数:       data
///**出口参数:      无
///**返 回 值:      无     
///**说    明:           向I2C写入数据
///************************************************************************
void I2cSendByte(unsigned char data)

 unsigned char flag, sz;                 //定义局部寄存器
 I2C_SDA_OUT;                            //SDA输出
 for(flag=0x0080; flag!=0x00;flag=flag/2)
 {
  sz=data&flag;
  if(sz==0)
  {
   I2C_SDA_Low;             //SDA=0 
   i2c_delay(50);          //1us
   I2C_SCL_H;               //SCL=1;
   i2c_delay(250);          //5us
          I2C_SCL_Low ;            //SCL=0;
  }
  else
  {
   I2C_SDA_H;               //SDA=1
   i2c_delay(50);          //1us
   I2C_SCL_H;               //SCL=1;
   i2c_delay(250);          //5us
   I2C_SCL_Low ;            //SCL=0;
  }

 }
}
/**********************************************************************
**函数原型:    I2cRecak()
**入口参数:    无
**出口参数:    无
**返 回 值:   应答值     
**说    明:   检查应答位子程序(返回0表示有应答)
************************************************************************/
int I2cRecak()
{
 unsigned char Ack=1;
 unsigned char m=1;
 I2C_SDA_OUT;                              //SDA输出
 I2C_SDA_H;                                //SDA=1
 i2c_delay(50);                           //2us
 I2C_SDA_IN;                               //SDA输入
 I2C_SCL_H;                                //SCL=1;
 i2c_delay(50);                           //3us
 if(I2C_SDA_Value == 1)                    //表示无应答
 {
  i2c_delay(50);
         I2C_SCL_Low ;   //SCL=0;
  i2c_delay(50);                   //1us......
 }
 else
 {
  Ack=0;
  i2c_delay(50);
  I2C_SCL_Low ;   //SCL=0;
  i2c_delay(50);                   //1us......
 }
 return(Ack);
}
///**********************************************************************
///**函数原型:      void I2cRecByte()
///**入口参数:     无
///**出口参数:    无
///**返 回 值:    数据   
///**说    明:         从I2C中读取数据
///************************************************************************/
int  I2cReadByte()
{
 unsigned char M=0;
 int flag;
 I2C_SDA_OUT;                              //SDA输出
 I2C_SDA_H;                                //SDA=1
 I2C_SDA_IN;                               //SDA输入
 for(flag=7;flag>=0;flag--)
 {
  I2C_SCL_H;                        //SCL=1
  i2c_delay(100);                   //2us...
  M=M|(I2C_SDA_Value << flag);      //保留读取的那位
  i2c_delay(250);                   //5us...
  I2C_SCL_Low ;                     //SCL=0
  i2c_delay(100);                   //3us
 }
 return(M);
}
///**********************************************************************
///**函数原型:   void I2cAck()
///**入口参数:    无
///**出口参数: 无
///**返 回 值: 无     
///**说    明:       对I2C总线中产生应答
///***********************************************************************
void I2cAck( )
{  
 I2C_SDA_OUT;                              //SDA输出
 I2C_SDA_Low;                              //SDA=0
 i2c_delay(50);                           //2us.....                          
 I2C_SCL_H;                                //SCL=1
 i2c_delay(250);                           //5us......
 I2C_SCL_Low ;                             //SCL=0
 i2c_delay(50);                           //2us......
}
/**********************************************************************
**函数原型:   void I2cNoAck()
**入口参数:     无
**出口参数:  无
**返 回 值: 无     
**说    明:不对I2C总线中产生应答
************************************************************************/
void I2cNoAck()
{  
 I2C_SDA_OUT;                              //SDA输出 
 I2C_SDA_H;                                //SDA=1
 i2c_delay(50);                           //2us.....
 I2C_SCL_H;                                //SCL=1;
 i2c_delay(250);                           //5us....
        I2C_SCL_Low ;                             //SCL=0;
 i2c_delay(50);                           //2us......
}
/**********************************************************************
**函数原型:   void I2CStop()
**入口参数:     无
**出口参数:     无
**返 回 值:          无     
**说    明:          停止IC总线
************************************************************************/
void I2cStop()
{
 I2C_SDA_OUT;                              //SDA输出 
 I2C_SDA_Low;                              //SDA=0
 i2c_delay(50);                           //2us........
 I2C_SCL_H;                                //SCL=1;
 i2c_delay(250);                           //5us........//延时
 I2C_SDA_H;                                //SDA=1
 i2c_delay(250);                           //5us......
}
static int i2c_open(struct inode *inode,
    struct file *file)
 {   
 /*pio_base = ioremap(0xFFFFF400,512);      //PIOA开始的地址 以及空间512字节               
 writel(0x01800000, pio_base + PIO_PER);  //PIO的使能寄存器  表示向该寄存器写入0x00000040的数据      
 writel(0x01800000, pio_base + PIO_PUER); //pull—up 使能寄存器  表示向该寄存器写入0x00000040的数据         
 writel(0x01000000, pio_base + PIO_ODSR); //输出数据状态寄存器  表示向该寄存器写入0x00000040的数据       
 writel(0x01000000, pio_base + PIO_OER);  //输出使能寄存器  表示向该寄存器写入0x00000040的数据
 */
        at91_set_A_periph(AT91_PIN_PA23, 1);  //TWD
 at91_set_A_periph(AT91_PIN_PA24, 1);  //TWD CLOCK
 
        at91_set_gpio_output(AT91_PIN_PA24, 1);  //I/O 口设置 clock
        at91_set_deglitch(AT91_PIN_PA24, 1);
             
        printk(KERN_INFO "::open_iic\n");
 return 0;
 }
static int i2c_ioctl( struct inode *inode,
    struct file *filp,
    unsigned int cmd,
    unsigned long arg)
{       
 //long   mode=0x01000000;         
 switch(cmd){     
  case TWD_CLOCK_H:
    I2C_SCL_H;
                         printk(KERN_INFO "::I2C_CLK_H\n");
    break;     
  case TWD_CLOCK_L:
    I2C_SCL_Low;
    printk(KERN_INFO "::I2C_CLK_L\n");
    break;               
  default: return -EINVAL;
                  break;        
 }            
 return 0;
}


/**********************************************************************
**函数原型:   i2c_read(struct file *file, const char __user *buf, size_t count)
**入口参数:    
**出口参数:  无
**返 回 值: 无    
**说    明: 通用的读24LC256的子程序((指针是8字节的读操作已经成功)
************************************************************************/
static int i2c_read(struct file *file, const char __user *buf, size_t count)
{
       unsigned char dat,i;
       unsigned char *buffer;
       unsigned char missing;
       unsigned char counter=count;
       ssize_t      status = 0;
       buffer=kmalloc(count * sizeof(char),GFP_KERNEL);
 LABLE: I2cStart();
        dat=0xA2;                             //设置I2c的开始状态
 I2cSendByte(dat);                     //送出器件地址字0xA3
 printk("read_dat0=0x%02X\n",dat);
 dat=I2cRecak();                       //检查应答位
 if(dat==0)
 {      
  dat=0x00;                      //dat=24LC256的块内地址的高字节 (因为每次只能送8位)
  printk("read_dat1=0x%02X\n",dat);
  I2cSendByte(dat);             //送出24LC256的块内地址的高字节
  dat=I2cRecak();               //检查应答位
  if(dat==0)
  {
          I2cStart();
   dat=0xA3;
          I2cSendByte(dat);     //送出24LC256的读指令 
          //printk("read_dat2=0x%02X\n",dat);
   dat=I2cRecak();       //检查应答位
   if(dat==1)
   {
      goto LABLE;//无则重新开始
      printk("read FUCK\n");
   }
   else
   {
           //printk("read FUCK_in\n");
           //printk("read_count2=0x%02X\n",counter);
    for(;counter!=1;counter--)
    {
         dat=I2cReadByte();   //读取一个字节的数据  
         *(buffer++)=dat;     //把读取的数据存入数组
         printk("read_dat3=0x%02X\n",*(buffer-1));
         I2cAck();          //产生应答信号
    }
    //printk("read_count4=0x%02X\n",counter);
    dat=I2cReadByte();        //接收最后一个数据
    I2cNoAck();                //发出应答
    *buffer=dat;               //把读取的数据放入数组
    //printk("read_dat5=0x%02X\n",*(buffer)); 
     }
   }
 }
      // printk("read_count=0x%02X\n",count);
       buffer=buffer-(count-1);
       missing=copy_to_user(buf,buffer, count);//boy
       if(missing != 0)
       {
          kfree(buffer);
          status = -EFAULT;
       }
       for(i=0;i<4;i++)printk("read_dat6=0x%02X\n",*(buf+i));
 printk("read FUCK_out\n");
 I2cStop();
        return 0;
}
/********************************************************
**函数原型:    void  Write(uint8 * array, uint16 address,uint16 control,uint16 n)
**入参数:     array  addres  control  n
**出口参数: 无
**返 回 值: 无   
**说    明?   通用的写24LC256的子程序(指针是8字节的写操作已经成功)
************************************************************************/
/通用的读写24LC256的程序,ARRAY=缓冲区首地址 address=块内地址,
/control=控制字节
/n=读写的字节数adders=N*64+M
/N=第几页,
/M=第几个字节
static int i2c_write(struct file *file, const char __user *buf, size_t count)
{
     unsigned char  dat,i;
     unsigned char  missing;
        unsigned char  *buff;
        unsigned char  counter=count-2;
        ssize_t        status = 0;
        printk(KERN_INFO "i2c_write\n");
        buff = kmalloc(count*sizeof(char), GFP_KERNEL); 
        missing=copy_from_user(buff,buf, count);
        if(missing != 0)
        {
          kfree(buff);
          status = -EFAULT;
        }
 //LCM_SPA_Low;                         //WP=0;设置写允许
  LOOP: I2cStart();                            //设置I2c的开始状态
 I2cSendByte(*buff);                  //送出器件地址字0xA2
 printk("buff=0x%02X\n",*buff);
 dat=I2cRecak();                        //检查应答位
 if(dat==0)
 {
  dat=*(buff+1);               //0x00;
  printk("write_dat=0x%02X\n",dat);
  I2cSendByte(dat);               //送出24LC256的块内地址的高字节
  dat=I2cRecak();                 //检查应答位
  if(dat==0)
  {
   
      // dat=*(buff+2);            //送出24LC256的低地址
      //I2cSendByte(dat);           //送出24LC256的低地址
      // dat=I2cRecak();            //检查应答位
      // if(dat==0)                 //如果有应答位
      // {
      for(i=0;i<counter;i++)
      {
           //buff++;
    I2cSendByte(*(buff+2+i));            //写出一个字节的数据0x23
    printk("write_dat1=0x%02X\n",*(buff+2+i));
    dat=I2cRecak();                  //检查应答位  dat==0,表明写成功
    if(dat==1)  goto LOOP;           //如果无应答位,写操作失败,重新开始

       }
       // }
          }
 }
 I2cStop();                                     //返回一个状态字,以确操作是否成功
 //LCM_SPA_H;                                   //WP=1;写操作完成,设置写保护  
    return 0;
}
static int i2c_close(
    struct inode *inode,
    struct file *file)
{   
        /*
 int i;       
 for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
 {       
  free_irq(button_irqs[i].irq, NULL);  
 } 
 */ 
 return 0;
}
static struct file_operations i2c_fops =
{     
 .owner   =   THIS_MODULE,     
        .open     =   i2c_open,
        .ioctl    =   i2c_ioctl,
        .read     =   i2c_read,
        .write    =   i2c_write,
        .release  =   i2c_close,
};

static int i2c_init(void)
{     
 int result,err;
 printk(DEV_NAME "::i2c_init\n");
 at91_i2c = kmalloc(sizeof(struct i2c_dev), GFP_KERNEL); 
 
 if( DEV_MAJOR != 0){      /*静态申请设置号*/
  at91_i2c->devno = MKDEV(DEV_MAJOR,DEV_MINOR);
  result = register_chrdev_region(at91_i2c->devno,1,DEV_NAME);
  at91_i2c->major = DEV_MAJOR;
  at91_i2c->minor = DEV_MINOR;
 }else {
  result = alloc_chrdev_region(&at91_i2c->devno,DEV_MINOR,1,DEV_NAME); /*动态申请设置号*/
  at91_i2c->major = MAJOR(at91_i2c->devno);
  at91_i2c->minor = DEV_MINOR;
 }
 if(result < 0){
  printk(KERN_ERR"i2c::can't get major\n");
  kfree(at91_i2c);
  return result;
 }

 cdev_init(&at91_i2c->cdev,&i2c_fops);      /*设置注册 初始化设备*/
 at91_i2c->cdev.owner = THIS_MODULE;
 at91_i2c->cdev.ops = &i2c_fops;
 err = cdev_add(&at91_i2c->cdev,at91_i2c->devno,1);
 if(err){
  printk(KERN_INFO"::error %d adding led\n",err);
 }

 at91_i2c->class = class_create(THIS_MODULE, DEV_NAME);  /*创建一个类*/
 if( IS_ERR(at91_i2c->class) ){              /*IS_ERR() PTR_ERR()等函数是专门用来处理CLASS之类的返回错误代码 */
  return PTR_ERR(at91_i2c->class);
 }

 at91_i2c->class_dev = device_create(at91_i2c->class, NULL,/*创建在/dev目录下创建相应的设备节点。这样,加载模块的时候,*/
                                                           /* 用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。*/
                 //   第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是设备名称,第五个参数是从设备号

          at91_i2c->devno,
          NULL,DEV_NAME);
 if( IS_ERR(at91_i2c->class_dev) ){
  return PTR_ERR(at91_i2c->class_dev);
 }  
 return 0;
}
static void __exit i2c_exit(void)
{     
 device_destroy(at91_i2c->class, at91_i2c->devno);
 class_destroy(at91_i2c->class);                          还定义了class_destroy(…)函数,用于在模块卸载时删除类。
 cdev_del(&at91_i2c->cdev);
 unregister_chrdev_region(at91_i2c->devno,1);
 kfree(at91_i2c);    
 printk(DEV_NAME ":: led_exit\n");
}

module_init(i2c_init);
module_exit(i2c_exit);

MODULE_AUTHOR("zhd wangyulu");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("at91sam9g20 led");
/*****Kconfig*******************************
config baite_LED
 tristate "baite_led"
 default m
******************************************/

/****Makeflie********************************
obj-$(CONFIG_baite_LED)  +=baite_led.o
******************************************/

以上是我的AT91的iic的软件驱动,其实只要稍加改动就可以应用在其他的上面。

 

下面是我的应用代码,就是用来测试该驱动的,以上都是通过我的测试,可以用的

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

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
//IIC Define the command constant
//#define SPI_READ_MODE          _IOR('D', 1, long)
//#define SPI_WRITE_MODE  _IOW('D', 1, long)
#define TWD_CLOCK_H          _IOW('D', 2, int)
#define TWD_CLOCK_L          _IOW('D', 3, int)
//#define SPI_READ_DATA          _IOR('D', 4, long)
//#define SPI_WRITE_DATA  _IOW('D', 4, long)
unsigned char Tx_buffer[6]={0xA2,0x00,0x89,0x12,0x23,0x34};
unsigned char Rx_buffer[4]={0};
/***********主程序***********/
int main(int argc, char **argv)
{
      int fd,ret,i;
      fd=open("/dev/iic",O_RDWR);
      if(fd<0)
      {
            perror("open error");
       }
       else printf("open iic success\n");
       //while(1)
       //{
          if(write(fd,Tx_buffer,sizeof(Tx_buffer)/sizeof(Tx_buffer[0]))<0) //注意fd?
          {
             perror("read wrong::");
             exit(1);
          }
          if(read(fd,Rx_buffer,sizeof(Rx_buffer)/sizeof(Rx_buffer[0]))<0) //注意fd?
          {
             perror("read wrong::");
             exit(1);
          }
          printf("Rx_buffer=::0x%02X\n",Rx_buffer[0]);
          printf("Rx_buffer=::0x%02X\n",Rx_buffer[1]);
          printf("Rx_buffer=::0x%02X\n",Rx_buffer[2]);
          printf("Rx_buffer=::0x%02X\n",Rx_buffer[3]);
         
        //}
        //sleep(1);
        close(fd);
        return 0;
}

 希望有帮助!

 


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值