- 主芯片的i2c的驱动
- 从芯片的i2c的驱动
编写方法:
一般都不会使用i2c-dev.c的read()、write()方法。最常用的是ioctl()方法。ioctl()方法可以实现上面所有的情况(两种数据格式、以及I2C算法和smbus算法)。
针对i2c的算法,需要熟悉struct i2c_rdwr_ioctl_data 、struct i2c_msg。使用的命令是I2C_RDWR。
struct i2c_rdwr_ioctl_data
{
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
struct i2c_msg {
_ _u16 addr; /* slave address */
_ _u16 flags; /* 标志(读、写) */
_ _u16 len; /* msg length */
_ _u8 *buf; /* pointer to msg data */
};
针对smbus算法,需要熟悉struct i2c_smbus_ioctl_data。使用的命令是I2C_SMBUS。对于smbus算法,不需要考虑“多开始信号时序”问题。
struct i2c_smbus_ioctl_data {
__u8 read_write; //读、写
__u8 command; //命令
__u32 size; //数据长度标识
union i2c_smbus_data __user *data; //数据
};
首先在内核中已经包含了对s3c2410 中的i2c控制器(总线驱动)驱动的支持。提供了i2c算法(非smbus类型的,所以后面的ioctl的命令是I2C_RDWR)
static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
另外一方面需要确定为了实现对AT24C02 e2prom的操作,需要确定从机芯片的地址及读写访问时序。
在网上找了个例子:
具体分析如下:
#include
<stdio.h> #include
<linux/types.h> #include
<stdlib.h> #include
<fcntl.h> #include
<unistd.h> #include
<sys/types.h> #include
<sys/ioctl.h> #include
<errno.h> #define
I2C_RETRIES 0x0701 #define
I2C_TIMEOUT 0x0702 #define
I2C_RDWR 0x0707 /*********定义struct
i2c_rdwr_ioctl_data和struct i2c_msg,要和内核一致。两个重要的结构体*******/ struct i2c_msg { unsigned
short addr; unsigned
short flags; unsigned
short len; unsigned
char *buf; }; struct i2c_rdwr_ioctl_data { struct i2c_msg
*msgs; int nmsgs;
/*
nmsgs这个数量决定了有多少开始信号,对于“单开始时序”,取1*/ }; int main() { int fd,ret; struct i2c_rdwr_ioctl_data
e2prom_data; fd=open( "/dev/i2c-0" ,O_RDWR);
<br> /*<br>
<br> 为什么是i2c-0呢???那就要到内核里看啦,等会再说
open底层调用了i2c_get_adapter(int id)函数,这个函数很重要,他可以识别占用了哪个i2c总线 使用地0个i2c控制器 /dev/i2c-0是在注册i2c-dev.c后产生的,代表一个可操作的适配器。如果不使用i2c-dev.c(这里说啦上面的为什么)
的方式,就没有,也不需要这个节,i2c_driver结构体中有attach_adapter方法:里面用device_create(i2c_dev_class, &adap->dev,MKDEV(I2C_MAJOR, adap->nr), NULL,"i2c-%d",adap->nr);I2C_MAJOR=89,即i2c-dev.c针对每个i2c适配器生成一个主设备号位89的设备文件,次设备要自己定义 */ if (fd<0) { perror ( "open
error" ); } e2prom_data.nmsgs=2;
/* *因为操作时序中,最多是用到2个开始信号(字节读操作中),所以此将 *e2prom_data.nmsgs配置为2 */ e2prom_data.msgs=( struct i2c_msg*) malloc (e2prom_data.nmsgs* sizeof ( struct i2c_msg)); if (!e2prom_data.msgs) { perror ( "malloc
error" ); exit (1); } ioctl(fd,I2C_TIMEOUT,1); /*超时时间*/ ioctl(fd,I2C_RETRIES,2); /*重复次数*/ /***write
data to e2prom**/ /**/ e2prom_data.nmsgs=1; (e2prom_data.msgs[0]).len=2;
//1个
e2prom 写入目标的地址和1个数据 (e2prom_data.msgs[0]).addr=0x50; //e2prom
设备地址 (e2prom_data.msgs[0]).flags=0;
//write (e2prom_data.msgs[0]).buf=(unsigned
char *) malloc (2); (e2prom_data.msgs[0]).buf[0]=0x10; //
e2prom 写入目标的地址 (e2prom_data.msgs[0]).buf[1]=0x58; //the
data to write ret=ioctl(fd,I2C_RDWR,(unsigned
long )&e2prom_data); if (ret<0) { perror ( "ioctl
error1" ); } sleep(1); /******read
data from e2prom*******/ e2prom_data.nmsgs=2; (e2prom_data.msgs[0]).len=1;
//e2prom
目标数据的地址 (e2prom_data.msgs[0]).addr=0x50;
//
e2prom 设备地址 (e2prom_data.msgs[0]).flags=0; //write (e2prom_data.msgs[0]).buf[0]=0x10; //e2prom数据地址 (e2prom_data.msgs[1]).len=1; //读出的数据 (e2prom_data.msgs[1]).addr=0x50; //
e2prom 设备地址 (e2prom_data.msgs[1]).flags=I2C_M_RD; //read (e2prom_data.msgs[1]).buf=(unsigned
char *) malloc (1); //存放返回值的地址。 (e2prom_data.msgs[1]).buf[0]=0; //初始化读缓冲
ret=ioctl(fd,I2C_RDWR,(unsigned long )&e2prom_data); if (ret<0) { perror ( "ioctl
error2" ); } printf ( "buff[0]=%x/n" ,(e2prom_data.msgs[1]).buf[0]); close(fd);
i2c_put_adapter(client->adapter);释放i2c总线
return 0; } |
以上讲述了一种比较常用的利用i2c-dev.c操作i2c设备的方法,这种方法可以说是在应用层完成了对具体i2c设备的驱动工作。
接下来准备具体分析如何写第一部分!