基于S5pv210--IO口模拟I2C总线Linux系统下驱动设计
来源:互联网 发布:python frozenset 编辑:程序博客网 时间:2024/05/12 11:50
驱动程序:
//////////////////////////////////////////////////////////////////////////
// FILE : e2prom.c// DATE : 09/02/2011
// DESCRIPTION : rfid-card i2c driver source
// OS : Linux 2.6.35.7
// AUTHOR : light.wu
//////////////////////////////////////////////////////////////////////////
// START: 在 SCL 线是高电平时,SDA线从高电平向低电平切换
// STOP: 当 SCL 是高电平时,SDA线由低电平向高电平切换
// 所有主机在 SCL 线上产生它们自己的时钟来传输 IIC 总线上的报文 数据只在时钟的高电平周期有效,
// (可理解为传输出去)。数据 SDA 只有在 SCL 为低电平时才可以发生改变。
// ACK 数据传输必须带响应 相关的响应时钟脉冲由主机产生 在响应的时钟脉冲期间 发送器释放 SDA
// 线为高 ,在响应的时钟脉冲期间 ,接收器必须将 SDA 线拉低 使它在这个时钟脉冲的高电平期间保持稳定的低电平。
//
//////////////////////////////////////////////////////////////////////////
#include<linux/init.h>
#include<linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <asm/io.h>
#define GPIO_IIC_SCL 0 // S5PV210_GPG3(5),
#define GPIO_IIC_SDA 1 // S5PV210_GPG3(6),
#define I2C_AT24CXX_ADDRESS 0xb0
#define I2C_AT24C02_MAXSIZE 0xff
#define SCL_H { gpio_set_value (S5PV210_GPG3(5), 1) ; }
#define SCL_L { gpio_set_value (S5PV210_GPG3(5), 0) ; }
#define SDA_H { gpio_set_value (S5PV210_GPG3(6), 1) ; }
#define SDA_L { gpio_set_value (S5PV210_GPG3(6), 0) ; }
#define SDA_IN { gpio_direction_input (S5PV210_GPG3(6)); }
#define SDA_OUT { gpio_direction_output (S5PV210_GPG3(6),1); }
#define SDA_OUT0 { gpio_direction_output (S5PV210_GPG3(6),0); }
#define WHILE_SDA_HIGH (gpio_get_value (S5PV210_GPG3(6)))
#define E2PROM_DEV_NAME "e2prom"
static int major = 239 ;
module_param( major, int, 0 ) ;
unsigned int ByteDelayTimeout = 0x700 ;
unsigned int BitDelayTimeout = 0x1000;
static void ByteDelay ( void ) ;
static void BitDelay ( void ) ;
static int e2prom_open ( struct inode *, struct file * ) ;
static int e2prom_release ( struct inode *, struct file * ) ;
static int e2prom_read ( struct file *, char *, size_t, loff_t * ) ;
static int e2prom_write ( struct file *, const char *, size_t, loff_t * ) ;
static int e2prom_ioctl ( struct inode *, struct file *, unsigned int,unsigned long ) ;
static void InterfaceInit ( void ) ;
static void I2C_Start ( void ) ;
static void I2C_Stop ( void ) ;
static void I2C_Ack ( void ) ;
static void I2C_Nack ( void ) ;
struct e2prom_private
{
spinlock_t lock ;
int ref_cnt ;
unsigned char address ;
} ;
static struct e2prom_private e2prom_priv ;
static struct file_operations e2prom_fops =
{
.owner = THIS_MODULE,
.open = e2prom_open,
.read = e2prom_read,
.write = e2prom_write,
.ioctl = e2prom_ioctl,
.release =e2prom_release,
} ;
static void I2C_Start ()
{
SDA_OUT ;
SDA_H ;
BitDelay () ;
SCL_H ;
BitDelay () ;
SDA_L ;
BitDelay () ;
}
static void I2C_Stop ()
{
SDA_OUT ;
SDA_L ;
BitDelay () ;
SCL_H ;
BitDelay () ;
SDA_H ;
BitDelay () ;
}
static void I2C_Ack()
{
SDA_OUT ;
SDA_L ;
BitDelay () ;
SCL_H ;
BitDelay () ;
SCL_L ;
BitDelay () ;
SDA_IN ;
BitDelay () ;
}
static void I2C_Ack1()
{
int i;
SCL_H ;
BitDelay () ;
SDA_IN ;
while((WHILE_SDA_HIGH)&&(i<255))i++; //无应答延时一段时间后默认已经收到
SCL_L ;
BitDelay () ;
SDA_OUT;
BitDelay () ;
}
static void I2C_Nack ()
{
SDA_OUT ;
SDA_H ;
BitDelay () ;
SCL_H ;
BitDelay () ;
SCL_L ;
BitDelay () ;
SCL_H ;
}
static char Write_I2C_Byte ( char byte )
{
char i ;
SCL_L ;
BitDelay () ;
for ( i = 0 ; i < 8 ; i++ )
{
if ( (byte & 0x80) == 0x80 )
{
SDA_H ;
}
else
{
SDA_L ;
}
BitDelay () ;
SCL_H ;
BitDelay () ;
SCL_L ;
BitDelay () ;
byte <<= 1 ;
}
return 1 ;
}
static char Read_I2C_Byte ( void )
{
char i, buff = 0 ;
SCL_L ;
BitDelay () ;
for ( i = 0 ; i < 8 ; i++ )
{
SDA_OUT ;
SDA_H ;
BitDelay () ;
SCL_H ;
SDA_IN ;
BitDelay () ;
if ( WHILE_SDA_HIGH )
{
buff |= 0x01 ;
}
else
{
buff &=~0x01;
}
if ( i < 7 )
{
buff <<= 1 ;
}
SCL_L ;
BitDelay () ;
}
return buff ;
}
static void ByteDelay ( void )
{
volatile unsigned int dwTimeout ;
dwTimeout = ByteDelayTimeout ;
while ( --dwTimeout )
{
asm ( "nop" ) ;
}
}
static void BitDelay ( void )
{
volatile unsigned int dwTimeout ;
dwTimeout = BitDelayTimeout ;
while ( --dwTimeout )
{
asm ( "nop" ) ;
}
}
static void InterfaceInit ( void )
{
gpio_direction_output (S5PV210_GPG3(5), 1); // SCL OUT
gpio_direction_output (S5PV210_GPG3(6), 1); // SDA OUT
gpio_set_value (S5PV210_GPG3(5), 1);
gpio_set_value (S5PV210_GPG3(6), 1);
ByteDelay () ;
ByteDelay () ;
ByteDelay () ;
}
static int e2prom_open ( struct inode *inode_ptr, struct file *fptr )
{
printk( "--------------------------------------------\n" ) ;
if ( e2prom_priv.ref_cnt != 0 )
{
printk ( "%s: exclusive access only\n", E2PROM_DEV_NAME ) ;
return -EIO ;
}
e2prom_priv.ref_cnt++ ;
e2prom_priv.address = 0x00 ;
fptr->f_op = &e2prom_fops ;
fptr->private_data = (void *) &e2prom_priv ;
return 0 ;
}
static int e2prom_release ( struct inode *inode_ptr, struct file *fptr )
{
struct e2prom_private *priv = (struct e2prom_private *) fptr->private_data ;
priv->ref_cnt-- ;
priv->address = 0x00 ;
return 0 ;
}
static int e2prom_read (struct file *fptr, char __user *buffer, size_t count, loff_t * fp)
{
int i = 0;
unsigned char data[100] = {0x00,};
InterfaceInit () ;
I2C_Start () ;
Write_I2C_Byte ( I2C_AT24CXX_ADDRESS ) ;
I2C_Ack1() ;
I2C_Start () ;
Write_I2C_Byte ( I2C_AT24CXX_ADDRESS + 1 ) ;
I2C_Ack1() ;
for ( i = 0; i < count; i++ )
{
data[i] = Read_I2C_Byte () ;
I2C_Ack () ;
printk( "0x%x ", data[i] ) ;
}
Read_I2C_Byte () ;
I2C_Nack () ;
I2C_Stop () ;
copy_to_user ( buffer, (char *) &data, count );
return count;
}
static int e2prom_write ( struct file *fptr, const char *buffer, size_t size, loff_t * fp )
{
int i = 0;
unsigned char data[100] = { 0x00, } ;
copy_from_user ( (char *) data, buffer, size );
I2C_Start () ;
Write_I2C_Byte ( I2C_AT24CXX_ADDRESS ) ;
I2C_Ack1 () ;
for ( i = 0; i < size; i++ )
{
printk( "0x%x ", data[i] ) ;
Write_I2C_Byte ( data[i] ) ;
I2C_Ack1 () ;
}
I2C_Stop () ;
I2C_Nack () ;
I2C_Stop () ;
return size;
}
static int e2prom_ioctl ( struct inode *inode, struct file *fptr, unsigned int cmd, unsigned long arg )
{
struct e2prom_private *priv = (struct e2prom_private *) fptr->private_data ;
priv->address = (unsigned char)arg ;
if ( priv->address >= I2C_AT24C02_MAXSIZE || priv->address < 0x00 )
{
printk( "e2prom_ioctl : the address you specificed is overflow e2prom area .\n" ) ;
return -EFAULT ;
}
return 0 ;
}
static struct class *led_class;
static int e2prom_init ( void )
{
printk("Real210 LED DRIVER MODULE INIT\n");
int status = 0 ;
memset ( &e2prom_priv, 0, sizeof (struct e2prom_private) ) ;
InterfaceInit () ;
spin_lock_init ( &e2prom_priv.lock ) ;
e2prom_priv.ref_cnt = 0 ;
e2prom_priv.address = 0x00 ;
status = register_chrdev (major, E2PROM_DEV_NAME, &e2prom_fops) ;
if ( status < 0 )
{
printk ( "e2prom_init : cannot get major number .\n" ) ;
return status ;
}
else if ( major == 0 )
{
major = status ;
}
led_class = class_create(THIS_MODULE, E2PROM_DEV_NAME); //创建节点
if(IS_ERR(led_class))
{
printk("Err: failed in Real210-LED class. \n");
return -1;
}
device_create(led_class, NULL, MKDEV(major, 0), NULL, E2PROM_DEV_NAME);
return 0 ;
}
static void e2prom_exit ( void )
{
printk("Real210 LED DRIVER MODULE EXIT\n");
unregister_chrdev ( major, E2PROM_DEV_NAME) ;
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
}
module_init ( e2prom_init ) ;
module_exit ( e2prom_exit ) ;
MODULE_DESCRIPTION ( "S5PV210 i2c e2prom driver\n" ) ;
MODULE_AUTHOR ( "light" ) ;
MODULE_LICENSE ( "GPL" ) ;
Makefile文件:
ifneq ($(KERNELRELEASE),)
obj-m := iic_io.o
else
KDIR := /home/light/miniAndroid/linux-2.6.35.7-android
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *~ *.mod.c *.symvers
endif
测试应用程序:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/types.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include "e2prom.h"
#define false 0
int main (int argc, char *argv[])
{
int fd ,ii,jj,kk;
unsigned char dataA[4] = { 0x03, 0x13, 0x13, 0x03 } ;
unsigned char dataB[4] = { 0x00, } ;
unsigned char address = 0x00 ;
fd = open ( "/dev/e2prom", O_RDWR ) ;
if ( fd == -1 )
{
printf( "Open device e2prom failed .\n" ) ;
return false ;
}
/* if ( ioctl( fd, E2PROM_WRITE_READ, address ) < 0 )
{
printf( "ioctl failed .\n" ) ;
close ( fd ) ;
return false ;
}
*/
if ( write ( fd, (char*)dataA, 4 ) != 4 )
{
printf( "Write device e2prom failed .\n" ) ;
close ( fd ) ;
return false ;
}
for(ii=10000;ii>0;ii--)
{
for(jj=10000;jj>0;jj--)
{
}
}
//注意延时时间必须得够,否则读不出数据。
if ( read ( fd, dataB, 4 ) != 4 )
{
printf( "Read device e2prom failed .\n" ) ;
close ( fd ) ;
return false ;
}
for(ii=10000;ii>0;ii--)
{
for(jj=10000;jj>0;jj--);
}
if ( read ( fd, dataB, 4 ) != 4 )
{
printf( "Read device e2prom failed .\n" ) ;
close ( fd ) ;
return false ;
}
printf( "dataB : 0x%x, 0x%x, 0x%x, 0x%x\n", dataB[0], dataB[1], dataB[2], dataB[3] ) ;
close ( fd ) ;
return EXIT_SUCCESS ;
}
Makefile:
CROSSCOMPILE=arm-linux-
call:iictest
iictest:iictest.c
$(CROSSCOMPILE)gcc -g -o iictest iictest.c -static
$(CROSSCOMPILE)strip iictest
clean:
@rm -vf iic-1 *.o *~
注意:
调试时候,必须注意ACK 响应,主机写,从机响应,主机检测,主机读,主机响应,读完了发送不响应。
- 基于S5pv210--IO口模拟I2C总线Linux系统下驱动设计
- S5PV210 Linux -- IO口模拟I2C总线驱动
- 嵌入式Linux系统中I2C总线设备的驱动设计
- 嵌入式Linux系统中I2C总线设备的驱动设计
- I2C总线在Linux系统中的驱动设计
- I2C总线在Linux系统中的驱动设计
- Linux系统中I2C总线设备的驱动设计
- 嵌入式Linux系统中I2C总线设备的驱动设计
- I2C总线在Linux系统中的驱动设计
- Linux下的I2C总线驱动
- Linux下的I2C总线驱动
- Linux下的I2C总线驱动
- Linux下的I2C总线驱动 .
- linux下I2C总线驱动架构分析
- 普通IO模拟i2c总线
- Linux I2C 总线驱动
- linux i2c总线驱动
- S5PV210下gpio模拟i2c
- C#读Excel文件并插入到数据库中(转自:http://www.cnblogs.com/michaelxu/archive/2009/03/12/1409761.html)
- Dotnetnuke Portal的皮肤系统
- SQL2000的系统表sysproperties在SQL2005中 无效的 问题
- 正则表达式表
- <Ibatis in action>中使用动态SQL的一个小细节提示(与CDATA)
- 基于S5pv210--IO口模拟I2C总线Linux系统下驱动设计
- 路由器登陆密码暴力破解程序
- Android sqlite3 CommandLine
- Unix 学习笔记(一)
- 给找工作的同学一点参考
- 不使用第三方变量交换两个变量的值
- 火星人谚语系列之八:少读书,多思考
- 【Asp.net】编程命名
- 使用预处理器进行调试