⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iic.c.txt

📁 初学者的福音. 代码易懂! 通过IO模拟实现的arm2410的iic总线驱动程序 可进行读写操作
💻 TXT
字号:

/*
**********************************************************

			s3c2410 gpio linux driver program

**********************************************************
*/
#ifndef __KERNEL__
	#define __KERNEL__
#endif

#ifndef MODULE
	#define MODULE
#endif

#ifdef CONFIG_SMP
	#define __SMP__
#endif

#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>

#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <linux/vmalloc.h>

#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/io.h>

#include "iic_drv.h"

#undef DEBUG	
//#define DEBUG
// define tracy function
#ifdef DEBUG
	#define DPRINTK( x... )	printk("iic_drv:" ##x)
#else
	#define DPRINTK( x... )
#endif

#define DEVICE_NAME 	"iic_drv"
#define EMPLED_MINOR	1

static int  iic_drv_major = 0;	/* Define major device number -- auto allocate!*/

/*
static ssize_t d11_arm_write(struct file * file, const char * buffer, size_t count, loff_t ppos)
{
	copy_from_user(&d11_gpiostatus,buffer,sizeof(d11_gpiostatus));
	update_d11_gpio();

	DPRINTK("write: d11_gpio=0x%x,count=%d\n",d11_gpiostatus,count);
	return sizeof(d11_gpiostatus);
}
*/



#define  clrsda  GPEDAT &=(~(0x1<<15))  
#define  setsda	 GPEDAT |=(0x1<<15)
#define  clrscl  GPEDAT &= (~(0x1<<14))
#define  setscl  GPEDAT |= (0x1<<14)
#define  setio1  GPECON = (GPECON & (~(0xf<<28))) | (0x1<<28)
#define  setio2  GPECON = (GPECON & (~(0xf<<28))) | (0x5<<28)


/*改变sda电平*/
void Change_Sda( int data)
{  
	if(data==0)
			clrsda ;   //向sda寄存器写
 	else
			setsda ;       //向sda寄存器写1
}
/*改变scl电平*/   	
void  Change_Scl( int data)
{
	if(data==0)
			clrscl ;	//向scl寄存器写0
	else 
			setscl ;		//向scl寄存器写1

}
/*改变数据传输方向*/    
void	Sda_Io( int sda)
{   
	if(sda==1)
			setio1 ;     //scl输出,sda输入
	else
			setio2 ;	  //scl输出,sda输出
}
/*延时函数*/
void  Delay( long int time)
{
	udelay(1 * time);
}
/*读一个比特数据*/
unsigned int Bit_Read(unsigned int var,int bit)
{
	unsigned int value,number;
	value=1<<bit;					//bit+1位置1
	number=(value&var)/value;		//number为0/1
	return(number);
}
/*写一个字节数据*/
void  Write_Byte(unsigned char data)
{
	unsigned  int j,k;
	Change_Scl(0);				//scl为低电平
	Sda_Io(0);                  //sda输出   scl输出
	for(j=0;j<8;)				//写8位数据
	{
		Change_Scl(0);		//scl为低电平
		k=Bit_Read(data,j); //k=0/1=number
		Change_Sda(k);		
		Delay(4);
		Change_Scl(1);			//scl=1
		Delay(2);
		j++;
  }
}
/*读一个字节数据*/
unsigned  char Read_Byte()
{
	unsigned int j;
	unsigned char data=0x00,i;
	Change_Scl(0);        //scl为低电平
	Sda_Io(1);     //scl输出   sda输入
	Delay(4);
	for(j=0;j<8;)
	{
		Change_Scl(1);     //scl为高电平
		i=Bit_Read(GPEDAT,15);    //读sda寄存器的值
		data=(data<<1)|i;         //左移是因为有八位数据读入
		Delay(2);
		Change_Scl(0);        //scl为低电平
		Delay(4);
		j++;
	}
 	return(data);         //返回的data为读入的八位数据
}
/*总线开始信号*/		
void	Iic_Start()
{
	Sda_Io(0);	             //scl输出sda 输入
	Change_Sda(1);          //sda线为高电平
	Change_Scl(1);         //scl线为高电平
	Delay(4);
	Change_Sda(0);        //sda线为低电平
	Delay(2); 
	Change_Scl(0);     //scl线为低电平
}
/*总线结束信号*/
void  Iic_Stop()
{
	Sda_Io(0);
	Change_Sda(0);
	Change_Scl(1);
	Delay(4);
	Change_Sda(1);
	Delay(2);
}

  /*接收端返回的确认信号*/
 void   Ack_In(void)
{
	Change_Scl(0);                    //scl线为低电平
	Change_Sda(0);
	Delay(4);
	Sda_Io(1);                        //scl输出  sda输入 
	Change_Scl(1);                    //scl线为高电平 
	Delay(2);
	Change_Scl(0);                     //线为低电平   
} 
/*发送端的确认信号*/
void   Ack_Out(void)
{
	Change_Scl(0);                      //为低电平
	Change_Sda(0);                     //sda为低电平  
	Sda_Io(0);                        //scl输出sda输出
	Delay(4);
	Change_Scl(1);                    
	Delay(2);
	Change_Scl(0);
}
/*调用该函数实现向从机写n字节的数据,slvaddr为从机地址,regaddr为寄存器地址,d为发送的数据数组*/
int Write_Iic(unsigned char slvaddr, unsigned char* pdata, unsigned char size)
{
  int i=0;
  unsigned char data=0x00,m=0x00,addr=0;
  unsigned int j,f,k;
  if(size <= 0)
	return -1;

	addr=((slvaddr<<1) & 0xfe);	              //将slvaddr的高低位顺序换过来
	//printk("The slvaddr of Writ_Byte is:%d\n ",addr);
	for(i=0;i<8;)
	{
		j=Bit_Read(addr,i);
		data=(data<<1)|j;
		i++;	
	}
	addr=data;
	//printk("The change slvaddr is :%d\n",addr);
	
	Iic_Start();           
	Write_Byte(addr);          
	Ack_In();
	for(i = 0; i < size;i++)             
	{
		for(f=0;f<8;)                         //将pdata[i]的高低位按顺序换过来 
		{
			k=Bit_Read(pdata[i],f);
			m=(m<<1)|k;
			f++	;
		}
		pdata[i]=m;
	//	printk("The pdata[i] is :%d\n",pdata[i]);
		m=0;
		Write_Byte(pdata[i]);		
		Ack_In();
	}	
	Iic_Stop();
	Delay(100);
	return 0;
}
/*调用该函数实现由从机读n字节的数据(无须提供寄存器地址),slvaddr为从机地址,regaddr为寄存器地址,(*d)为接受数据指针*/
int Read_noaddr_Iic(unsigned char slvaddr, unsigned char* pdata, unsigned char size)
{ 
	int i,l,j;
	unsigned char addr=0,data=0x00;
	addr=((slvaddr<<1) | 0x01);
	for(l=0;l<8;)                        //将slvaddr的高低位按顺序换过来,发送时先发高位
	{
		j=Bit_Read(addr,l);
		data=(data<<1)|j;
		l++;	
	}
	addr=data;
	
	//printk("The slvaddr is :%d\n",addr);
	Iic_Start();
	Write_Byte(addr);
	Ack_In();
	for(i = 0; i < size; i++)
	{
		*pdata = Read_Byte();
	//	printk("read byte is:%d\n",*pdata);
		return(*pdata);
		pdata++;
		if(i == (size - 1))
			break;
		else
			Ack_Out	();
	}
	Iic_Stop();
	Delay(100);
	return 0 ;
}

/*调用该函数实现由从机读n字节的数据(须提供寄存器地址),slvaddr为从机地址*/
int Read_addr_Iic(unsigned char slvaddr, unsigned char* pdata, unsigned char size)
{ 
	int i;
  unsigned char addr=0,data=0x00,l,j;
	
	//printk("slvaddr is :0x%x\n",slvaddr);
	addr=((slvaddr<<1)&0xfe);	                          //change   send  order
	for(l=0;l<8;)
	{
		j=Bit_Read(addr,l);
		data=(data<<1)|j;
		l++;	
	}
	addr=data;
	//printk("The first time send slvaddr is :0x%x\n",addr);
	Iic_Start();
	Write_Byte(addr);
	Ack_In();
		
	//printk("The send regaddr is :0x%x\n",pdata[0]);
	data=0;
	for(l=0;l<8;)
	{
		j=Bit_Read(pdata[0],l);
		data=(data<<1)|j;
		l++;	
	}
	pdata[0]=data;
	//printk("The send regaddr is:%d\n",pdata[0]);
	Write_Byte(pdata[0]);	                         
	Ack_In();
	Iic_Start();
	addr=addr|0x80;
	//printk("The slvaddr is :%d\n",slvaddr);
	/*addr=((slvaddr<<1)|0x01);	
	data=0x00;                            //change send order
	for(l=0;l<8;)
	{
		j=Bit_Read(addr,l);
		data=(data<<1)|j;
		l++;	
	}
	slvaddr=data;
	*/
	Write_Byte(addr);
	//printk("The second time send slvaddr is:%d\n",addr);
	Ack_In();
	pdata++;
	//printk("*pdata is :%d\n",*pdata);
	for(i = 0; i < size; i++)
	{
		*pdata = Read_Byte();
	//	printk("The read_byte  is:0x%x\n",*pdata);
		return(*pdata);
		pdata++;                                  
		if(i == (size - 1))                
			break;
		else
			Ack_Out	();	
	}
	Iic_Stop();
	Delay(100);
	return 0;
}
/*********************************************************/
static int iic_drv_open(struct inode * inode, struct file * filp)
{
	MOD_INC_USE_COUNT;
	DPRINTK("open\n");
	return 0;
}

static int iic_drv_release(struct inode * inode, struct file * filp)
{
	MOD_DEC_USE_COUNT;
	DPRINTK("releas\n");
	return 0;
}


int iic_drv_ioctl(struct inode * inode, struct file * filp, unsigned int command, unsigned long arg)
{
	int err = 0;	
	struct iic_drv_tag iic_data;
	
	switch(command)
	{		
		case READ_NADD_IIC:
		{
			copy_from_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(struct iic_drv_tag));				
			Read_noaddr_Iic(iic_data.addr, iic_data.pdata, iic_data.size);
			copy_to_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(iic_data));
			copy_to_user(iic_data.pdata, ((struct iic_drv_tag *)(arg))->pdata, iic_data.size);
			break;	    
	  }
    
	    case READ_ADD_IIC:
		{
			copy_from_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(struct iic_drv_tag));			
			Read_addr_Iic(iic_data.addr, iic_data.pdata, iic_data.size);
			copy_to_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(iic_data));
		  //copy_to_user(iic_data.pdata, ((struct iic_drv_tag *)(arg))->pdata, iic_data.size);
			break;	    
	  }
		
		case WRITE_IIC:			
		{
			copy_from_user(&iic_data, (struct iic_drv_tag *)(arg), sizeof(struct iic_drv_tag));
			copy_from_user(iic_data.pdata, ((struct iic_drv_tag *)(arg))->pdata, iic_data.size);		  	
			Write_Iic(iic_data.addr, iic_data.pdata, iic_data.size);	
		}
		
		default:
			return -ENOTTY;
		break;	
	}

	return err;
}

static struct file_operations iic_drv_fops = {

	owner:	  THIS_MODULE,
	ioctl:	  iic_drv_ioctl,
	open:	  iic_drv_open,
	release:  iic_drv_release,
};

#ifdef CONFIG_DEVFS_FS
	static devfs_handle_t devfs_iic_drv_dir, devfs_iic_drv;
#endif

static int __init iic_drv_init(void)
{
	int ret;	
	ret = register_chrdev(0, DEVICE_NAME, &iic_drv_fops);
	if(ret < 0)
	{
		printk("iic_drv:Cant't get major number!\n");
		return ret;
	}
	iic_drv_major = ret;	

	#ifdef CONFIG_DEVFS_FS
		devfs_iic_drv_dir = devfs_mk_dir(NULL, "iic_drv", NULL);
		if(!devfs_iic_drv_dir) return -EBUSY;	/* ERROR */
		
			devfs_iic_drv = devfs_register(devfs_iic_drv_dir, "0", 
			DEVFS_FL_DEFAULT, iic_drv_major, EMPLED_MINOR, 
		S_IFCHR | S_IRUSR | S_IWUSR, &iic_drv_fops, NULL);
	#endif

	printk("iic_drv:Initialized!\n");
	printk("iic_drv:Major device no. -> %d\n",iic_drv_major);
	
	return 0;
}


static void __exit  iic_drv_exit(void)
{
	#ifdef CONFIG_DEVFS_FS
		devfs_unregister(devfs_iic_drv);
		devfs_unregister(devfs_iic_drv_dir);
	#endif
	
	printk("iic_drv:release!\n");
	unregister_chrdev(iic_drv_major, DEVICE_NAME);
	
}

module_init(iic_drv_init);
module_exit(iic_drv_exit);

MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -