天天看點

簡單的IIC驅動執行個體

#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>  

#include <linux/slab.h>  

#include <linux/fs.h>      

#include <linux/errno.h>   

#include <linux/types.h>   

#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;

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 ; //傳回中斷

}

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.

}

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;

}