由于公司的需要,在写I2C程序,原来从头到尾自己写一个IIC驱动是一件很简单的事情,但想完美的我还是想把我的驱动和内核的I2C子系统连接起 来,I2C本身很简单,S3C2410无操作系统不用300行就搞定,但I2C子系统却把这么简单的代码变得非常庞大,非常难懂,结构错综复杂。
关于I2C子系统,我转载的文章Linux I2C核心、总线与设备驱动[转] 已经说得很请楚,这里只作一些补充。
一、master_xfer,以及i2c_msg标志位
其实抛开子系编本身其它部份,实现I2C的主要作用代码就是algorithm里的master_xfer方法。这个方法就是我们无操作系统 时的的I2C读写函数(它用参数来区分读和写)。分析这些代码,最好是读内核的i2c-algo-bit.c文件,这个文件就是用模拟的方法来实现I2C 总线,因为不和其它I2C控制芯片相关,所以比较好理解。i2c-algo-bit.c其中的master_xfer函数bit_xfer函数如下:
1static int bit_xfer(struct i2c_adapter *i2c_adap,
2 struct i2c_msg msgs[], int num)
3{
4 struct i2c_msg *pmsg;
5 struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
6
7 int i,ret;
8 unsigned short nak_ok;
9
10 i2c_start(adap);
11 for (i&#61;0;i<num;i&#43;&#43;) {
12 pmsg &#61; &msgs[i];
13 nak_ok &#61; pmsg->flags & I2C_M_IGNORE_NAK;
14 if (!(pmsg->flags & I2C_M_NOSTART)) {
15 if (i) {
16 i2c_repstart(adap);
17 }
18 ret &#61; bit_doAddress(i2c_adap, pmsg);
19 if ((ret !&#61; 0) && !nak_ok) {
20 DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d/n"
21 ,msgs[i].addr,i));
22 return (ret<0) ? ret : -EREMOTEIO;
23 }
24 }
25 if (pmsg->flags & I2C_M_RD ) {
26
27 ret &#61; readbytes(i2c_adap, pmsg);
28 DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes./n",ret));
29 if (ret < pmsg->len ) {
30 return (ret<0)? ret : -EREMOTEIO;
31 }
32 } else {
33
34 ret &#61; sendbytes(i2c_adap, pmsg);
35 DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes./n",ret));
36 if (ret < pmsg->len ) {
37 return (ret<0) ? ret : -EREMOTEIO;
38 }
39 }
40 }
41 i2c_stop(adap);
42 return num;
43} 其实也并不复杂
1&#xff09;i2c_start函数发start信号
2&#xff09;i2c_repstart函数发重复start信号
3&#xff09;bit_doAddress函数写器件地址
4&#xff09;readbytes函数读N字节
5&#xff09;writebytes函数写N字节
其中的每一个函数都不复杂&#xff0c;都是设置或读取scl和sda线。
bit_xfer函数参数只要是i2c_msg序列msgs。这个结构请看Linux I2C核心、总线与设备驱动[转] 或自己Google吧&#xff0c;里面放着要这个函数完成的任务。我们的最主要任务是i2c_msg的一些标志位&#xff0c;这些标识位网上都没有提到。我来解释一下&#xff0c;错了大家请原谅。
I2C_M_IGNORE_NAK&#xff1a;
设置这个标志意味当前i2c_msg忽略I2C器件的ack和nack信号。
I2C_M_NOSTART&#xff1a;
设置这个标志意味当前i2c_msg不发送start信号。注意&#xff0c;其实调用bit_xfer的一开始就已经发了start信号了&#xff08;程序第10 行&#xff09;&#xff0c;这个标记无非就是标志是否发送地址第18行。其次&#xff0c;如果一个i2c_msg没有定义I2C_M_NOSTART而且又不是msgs序列里的第一个 i2c_msg&#xff0c;则回发送重复start信号&#xff0c;我想这就是这个标志起这个名的原因。我们可以猜想&#xff0c;
1.msgs序列第一个数据必须是地址&#xff0c;同时必须不定义这个标志位
2.在进行读数据&#xff0c;要从写操作转变为读操作时&#xff0c;会发重复start信号和器件地址时&#xff0c;必须不定义这个标志位
3.其它情况下一的i2c_msg必须定义这个标志
以上只是我看完这个函数的理解&#xff0c;不一定正确。同时1和2总结下来就是发器件地址&#xff08;注意&#xff0c;是器件地址&#xff0c;不是像EEPROM那样的EEPROM地 址&#xff0c;这个地址是当数据发的&#xff09;时会不设置I2C_M_NOSTART, 发数据时就设置I2C_M_NOSTART这个标志。
I2C_M_NO_RD_ACK&#xff1a;
这个标识表示在正行读操作时不去ACK&#xff0c;我不知道其它芯片如果&#xff0c;如果是AT24C04则一定不能设这个标志位了。
&#xff08;下面三个标志为均为bit_doAddress函数使用&#xff0c;结合上面的说明&#xff0c;也就是这时I2C_M_NOSTART一定没有设置。&#xff09;
I2C_M_RD&#xff1a;
表示这是一个读操作&#xff0c;默认是把相应的位置1
I2C_M_REV_DIR_ADDR&#xff1a;
表示把读写标志位反转&#xff0c;也就是读是把相应位置0
I2C_M_TEN&#xff1a;
表示这个器件的器件地址是10Bit的。一定要搞清&#xff0c;这是器件地址&#xff0c;不是指EEPROM的ROM地址。24C02等芯片真正的器件地址只有4位 永远有效&#xff08;0xA)&#xff0c;低4位用来放其它东西了&#xff08;根据容量有可能是器件地址的低3位&#xff0c;或ROM地址的高3位&#xff09;。也是说&#xff0c;无论什么容量&#xff0c;这类器件的地址只是器 件地址我们只选7位模式&#xff08;内核只区分10位模式和其它模式&#xff09;