简单的IIC驱动实例

来源:互联网 发布:淘宝买原味胖次 编辑:程序博客网 时间:2024/05/22 15:34
 

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/sched.h>

#include <asm/hardware.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>   /* printk() */
#include <linux/slab.h>   /* kmalloc() */
#include <linux/fs.h>       /* everything... */
#include <linux/errno.h>    /* error codes */
#include <linux/types.h>    /* size_t */
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/delay.h>
//#include <linux/device.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <asm/irq.h>
//#include <asm/arch/regs-adc.h>

#include <asm/arch/map.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/arch/regs-clock.h>
//#include <asm/arch/regs-iic.h>


volatile int f_nGetACK;
#define UINT unsigned int

#define I2C_MAGIC 'k' 
#define I2C_set _IO(I2C_MAGIC,1)

#define I2C_MAJOR 259
#define DEVICE_NAME "s3c2410_I2C"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("farsight");
MODULE_DESCRIPTION("s3c2410 I2C");

char data[128]="\0";


#define rGPECON  *(volatile unsigned int *)S3C2410_GPECON

#if 0
#define S3C2410_I2C(x) (S3C2410_IICREG(x))

#define S3C2410_IICCON    S3C2410_I2C(0x00)
#define S3C2410_IICSTAT    S3C2410_I2C(0x04)
#define S3C2410_IICADD    S3C2410_I2C(0x08)
#define S3C2410_IICDS    S3C2410_I2C(0x0c)

#define rIICCON  *(volatile unsigned int *)S3C2410_IICCON
#define rIICSTAT *(volatile unsigned int *)S3C2410_IICSTAT
#define rIICADD  *(volatile unsigned int *)S3C2410_IICADD
#define rIICDS   *(volatile unsigned int *)S3C2410_IICDS
#define rGPECON  *(volatile unsigned int *)S3C2410_GPECON
#else

#define rIICCON  *(volatile unsigned int *)i2c_base
#define rIICSTAT *(volatile unsigned int *)((unsigned int)i2c_base + 4)
#define rIICADD *(volatile unsigned int *)((unsigned int)i2c_base + 8)
#define rIICDS *(volatile unsigned int *)((unsigned int)i2c_base + 0xc)?/IICDS寄存器

static volatile void __iomem *i2c_base;
static struct resource *area = NULL;
#endif

#define CLKCON 0x4c00000c  //一般时钟控制寄存器

static volatile unsigned int *clkcon;

static int I2C_major = I2C_MAJOR;

static struct cdev I2C_cdev;

/*********************************************************************************************
 * name:  iic_int_24c04()
 * func:  IIC interrupt handler
 * para:  none
 * ret:  none
 * modify:
 * comment:  
 *********************************************************************************************/
static irqreturn_t  iic_int_24c04(int irq,void *dev_id,struct pt_regs *regs)
{
 //ClearPending(BIT_IIC);
 //printk("in I2C irq\n");
 f_nGetACK = 1;
 return IRQ_HANDLED ; //返回中断
}
/*********************************************************************************************
 * name:  iic_write_24c040
 * func:  write data to 24C040
 * para:  unSlaveAddr --- input, chip slave address
 *   unAddr  --- input, data address
 *   ucData     --- input, data value
 * ret:  none
 * modify:
 * comment:  
 *********************************************************************************************/
void iic_write_24c040(UINT unSlaveAddr,UINT unAddr,UINT ucData)
{
 f_nGetACK = 0;

 // Send control byte
 rIICDS = unSlaveAddr;   //地址结构  0xa0
 rIICSTAT = 0xf0;           // Master Tx,Start
 //   mdelay(100);
 //mdelay(100);
 while(f_nGetACK == 0);// Wait ACK     
 f_nGetACK = 0;
 //Send address
 rIICDS = unAddr;  //地址结构
 rIICCON = 0xaf;            // Resumes IIC operation.
 //   printk("22222\n");
 while(f_nGetACK == 0);// Wait ACK
 //mdelay(100);
 //printk("333333\n");
 f_nGetACK = 0;
 // printk("2\n");
 // Send data
 rIICDS = ucData;
 rIICCON = 0xaf; // Resumes IIC operation.
 // printk("4444444\n");
 while(f_nGetACK == 0);// Wait ACK
 //mdelay(100);
 // printk("66666\n");         // Wait ACK
 f_nGetACK = 0;

 // End send
 rIICSTAT = 0xd0; // Stop Master Tx condition
 rIICCON = 0xaf; // Resumes IIC operation.
 mdelay(10);  // Wait until stop condtion is in effect.
}

/*********************************************************************************************
 * name:  iic_read_24c040
 * func:  read data from 24C040
 * para:  unSlaveAddr --- input, chip slave address
 *   unAddr  --- input, data address
 *   pData     --- output, data pointer
 * ret:  none
 * modify:
 * comment:  
 *********************************************************************************************/
void iic_read_24c040(UINT unSlaveAddr,UINT unAddr,unsigned char *pData)
{
 char cRecvByte;

 f_nGetACK = 0;

 //Send control byte
 rIICDS = unSlaveAddr;          // 0xa0
 rIICSTAT = 0xf0;            // Master Tx,Start

 //mdelay(100);
 while(f_nGetACK == 0);// Wait ACK
 f_nGetACK = 0;

 // Send address
 rIICDS = unAddr;
 rIICCON = 0xaf;            // Resumes IIC operation.

 //mdelay(100);
 while(f_nGetACK == 0);// Wait ACK
 f_nGetACK = 0;

 //Send control byte
 rIICDS = unSlaveAddr;          // 0xa0
 rIICSTAT = 0xb0;            // Master Rx,Start
 rIICCON = 0xaf;            // Resumes IIC operation.  
 mdelay(100);
 //while(f_nGetACK == 0);// Wait ACK
 while(f_nGetACK == 0);// Wait ACK
 f_nGetACK = 0;

 //Get data
 // cRecvByte = rIICDS;
 rIICCON = 0x2f;
 mdelay(1);

 // Get data
 cRecvByte = rIICDS;

 // End receive
 rIICSTAT = 0x90;           // Stop Master Rx condition
 rIICCON = 0xaf;            // Resumes IIC operation.
 mdelay(10);             // Wait until stop condtion is in effect.

 *pData = cRecvByte;
}

ssize_t I2C_read (struct file *filp, char *buff, size_t count, loff_t *offp)
{
 ssize_t result = 0;
 int i;


 for(i=0; i<count; i++)
  data[i]=0;  
 // Read 16 byte from 24C04
 for(i=0; i<count; i++)
 {
  iic_read_24c040(0xa0, i, &(data[i])); //读数据
 }
 data[count]='\0';
 // printk("rev=%s\n",data);

 if (copy_to_user (buff, data, count))
  result = -EFAULT;
 //else
 //printk (KERN_INFO "wrote %d bytes\n", count);

 result=count;

 return result;
}

 


ssize_t I2C_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
 int i;
 ssize_t ret = 0;
 //printk ("Writing %d bytes\n", count);
 if (count>127) return -ENOMEM;
 if (count<0) return -EINVAL;
 if (copy_from_user (data, buf, count))
 {
  ret = -EFAULT;
 }
 else {
  data[127]='\0';

  for(i=0; i<count; i++)
  {
   iic_write_24c040(0xa0, i, data[i]); //写数据
  }

  ret = count;
 }
 return ret;
}

 

static int I2C_open(struct inode *inode ,struct file *file) 
{
 int result;
 // Initialize iic
 rIICADD = 0x10; //IICADD寄存器 S3C2410X slave address
 rIICCON = 0xaf; //IICCON寄存器 Enable ACK, interrupt, SET IICCLK=MCLK/16
 rIICSTAT = 0x10; //IICSTAT寄存器 Enable TX/RX

 rGPECON =(rGPECON&((~0xf)<<28))+(0xa<<28);
 //printk("rGPECON=%x\n",rGPECON);

 result = request_irq (IRQ_IIC, iic_int_24c04, SA_INTERRUPT, DEVICE_NAME, NULL);//申请中断
 if (result) {
  printk(KERN_INFO "I2C: can't get assigned irq\n");
 }

 //printk(KERN_NOTICE"open the I2C now!\n");
 return 0;
}


static int I2C_release(struct inode *inode,struct file *file)
{
 free_irq(IRQ_IIC, NULL);//释放中断资源
 //printk("I2C closed\n");
 return 0;
}

static int I2C_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)


 return 0; 
}
//将设备注册到系统之中
static void I2C_setup_dev(struct cdev *dev,int minor,struct file_operations *fops)
{
 int err;
 int devno=MKDEV(I2C_major,minor);
 cdev_init(dev,fops);
 dev->owner=THIS_MODULE;
 dev->ops=fops;
 err=cdev_add(dev,devno,1);
 if(err)
  printk(KERN_INFO"Error %d adding I2C %d\n",err,minor);
}

static struct file_operations I2C_remap_ops={
 .owner=THIS_MODULE,
 .open=I2C_open,
 .write = I2C_write,
 .read = I2C_read,
 .release=I2C_release,
 .ioctl=I2C_ioctl,
};

//注册设备驱动程序,主要完成主设备号的注册
static int __init s3c2410_I2C_init(void)
{
 int result;

 dev_t dev = MKDEV(I2C_major,0);

 if(I2C_major)
  result = register_chrdev_region(dev,1,DEVICE_NAME);
 else
 { 
  result = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);
  I2C_major = MAJOR(dev);
 }

 if(result<0)
 {
  printk(KERN_WARNING"I2C:unable to get major %d\n",I2C_major);  
  return result;
 }

 if(I2C_major == 0)
  I2C_major = result;

 printk(KERN_NOTICE"[DEBUG] I2C device major is %d\n",I2C_major);

 __raw_writel( (__raw_readl(S3C2410_CLKCON) | (1 << 16)), S3C2410_CLKCON);

#if 0
 printk("\n  S3C2410_CLKCON = %x \n", __raw_readl(S3C2410_CLKCON));
 area = request_mem_region(0x54000000, 16,"I2C");
#endif

 i2c_base = ioremap(0x54000000, 16);//(IICCON寄存器)
 clkcon = ioremap(CLKCON, 0x4);

 printk(KERN_INFO"i2c clock = %d\n", *clkcon & (0x1 << 16));
 *clkcon |= 0x1 << 16;

 I2C_setup_dev(&I2C_cdev,0,&I2C_remap_ops);

 return 0;
}
//驱动模块卸载
static void s3c2410_I2C_exit(void)
{
#if 0
 if (area) {
  release_resource(area);
  kfree(area);
 }
#endif
 cdev_del(&I2C_cdev);
 unregister_chrdev_region(MKDEV(I2C_major,0),1);
 printk("I2C device uninstalled\n");
}

module_init(s3c2410_I2C_init);
module_exit(s3c2410_I2C_exit);

 

测试程序:

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

#define WATCHDOG_MAGIC 'k'
#define FEED_DOG _IO(WATCHDOG_MAGIC,1)

int main(int argc,char **argv)
{
 int fd;
 char buff[]="farsight";
 //打开I2C
 fd=open("/dev/i2c",O_RDWR);
 
 if(fd<0)
 {
  printf("cannot open the I2C device\n");
  return -1;
 }
 
   sleep(1);
 printf("buff_write=%s\n",buff);
   write (fd, buff, sizeof(buff));

 memset (buff, '\0', sizeof(buff));

   read (fd, buff, sizeof(buff));

 printf ("buff_read = %s\n", buff);
 
 close(fd);

 return 0;

}


 

原创粉丝点击