i 2 c駆動の一般機器駆動1

10613 ワード

このブログはi 2 cの普通のデバイス駆動を分析して、いつもの文字駆動のように、先にmodule_init()、module_exit()は、モジュールのロードとアンインストールを完了し、初期化関数にデバイス番号と関連ファイル構造体file_を登録します.operaion、最後にfileを実現しますoperationにおけるread,write,open,releaseなどの操作は、read,write,open,releaseを操作する際に、linux 2を記憶することなくs 3 c 2440のi 2 c関連レジスタを直接制御i 2 cデバイスと通信する.6.32.2カーネルが提供するi 2 c-core.cファイルのi 2 c_transfer法はデータ通信を実現する.
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <mach/hardware.h>
#include <linux/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 <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 <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/regs-irq.h>
#include <mach/regs-clock.h>
#include <asm/signal.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)

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)
{
	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
	while(f_nGetACK == 0);// Wait ACK					
	f_nGetACK = 0;
	//Send address
	rIICDS = unAddr;
	rIICCON = 0xaf;				// Resumes IIC operation.
	while(f_nGetACK == 0);// Wait ACK
	f_nGetACK = 0;

	// Send data 
	rIICDS = ucData;
	rIICCON = 0xaf;				// Resumes IIC operation.
	while(f_nGetACK == 0);// 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
	while(f_nGetACK == 0);// Wait ACK
	f_nGetACK = 0;

	// Send address
	rIICDS = unAddr;
	rIICCON = 0xaf;					// Resumes IIC operation.
	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
	f_nGetACK = 0;

	//Get data 
	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';

	if (copy_to_user (buff, data, count)) 
		result = -EFAULT;
	
	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
", count); if (count>127) return -ENOMEM; if (count<0) return -EINVAL; if (copy_from_user (data, buf, count)) { ret = -EFAULT; } else { data[127]='\0'; //printk ("Received: %s
", data); // Write 0 - 16 to 24C04 for(i=0; i<count; i++) { iic_write_24c040(0xa0, i, data[i]); //mdelay(100); } //printk("write end
"); ret = count; } return ret; } static int I2C_open(struct inode *inode ,struct file *file) { int result; // Initialize iic rIICADD = 0x10; // S3C2410X slave address rIICCON = 0xaf; // Enable ACK, interrupt, SET IICCLK=MCLK/16 rIICSTAT = 0x10; // Enable TX/RX rGPECON =(rGPECON&((~0xf)<<28))+(0xa<<28); //printk("rGPECON=%x
",rGPECON); result = request_irq (IRQ_IIC, iic_int_24c04, IRQF_DISABLED, DEVICE_NAME, NULL); if (result) { printk(KERN_INFO "I2C: can't get assigned irq
"); } //printk(KERN_NOTICE"open the I2C now!
"); return 0; } static int I2C_release(struct inode *inode,struct file *file) { free_irq(IRQ_IIC, NULL);//ÊÍ·ÅÖжÏ×ÊÔŽ //printk("I2C closed
"); 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
",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
",I2C_major); return result; } if(I2C_major == 0) I2C_major = result; printk(KERN_NOTICE"[DEBUG] I2C device major is %d
",I2C_major); __raw_writel( (__raw_readl(S3C2410_CLKCON) | (1 << 16)), S3C2410_CLKCON); #if 0 printk("
S3C2410_CLKCON = %x
", __raw_readl(S3C2410_CLKCON)); area = request_mem_region(0x54000000, 16,"I2C"); #endif i2c_base = ioremap(0x54000000, 16); clkcon = ioremap(CLKCON, 0x4); printk(KERN_INFO"i2c clock = %d
", *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
"); } module_init(s3c2410_I2C_init); module_exit(s3c2410_I2C_exit);

ドライバのコンパイル中にエラーが発生しました:I 2 C_drv.c:7:26: error: asm/hardware.h:No such file or directoryは、以前のバージョンのヘッダファイルで、そのバージョンの場所が変更されたためです.解決策はfind-name「xxx.h」を使用してヘッダファイルの対応する場所を検索し、ヘッダファイルを追加することです.もう1つのエラー:2410_I2C/I2C_drv.c:285: error: 'SA_INTERUPT'undeclared(first use in this function解決策は、SA_INTERUPTが以前のバージョンで定義したカーネルであり、現在のカーネルはこの変数を定義していないが、上記の代わりにIRQF_DISABLEを採用するのは結局バージョンの問題である.
アプリケーションのテスト
#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
"); return -1; } sleep(1); printf("buff_write=%s
",buff); write (fd, buff, sizeof(buff)); //printf(" read now!
"); memset (buff, '\0', sizeof(buff)); //printf ("Read returns %d
", read (fd, buff, sizeof(buff))); read (fd, buff, sizeof(buff)); //read (fd, buff, 3); printf ("buff_read = %s
", buff); close(fd); // while(1); // printf("end
"); return 0; }