Linux设备驱动剖析之IIC(四)
558行,又重试2次。
560行,调用s3c24xx_i2c_doxfer函数:
static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
struct i2c_msg *msgs, int num)
{
unsigned long iicstat, timeout;
int spins = ;
int ret; if (i2c->suspended)
return -EIO; ret = s3c24xx_i2c_set_master(i2c);
if (ret != ) {
dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
ret = -EAGAIN;
goto out;
} spin_lock_irq(&i2c->lock); i2c->msg = msgs;
i2c->msg_num = num;
i2c->msg_ptr = ;
i2c->msg_idx = ;
i2c->state = STATE_START; s3c24xx_i2c_enable_irq(i2c);
s3c24xx_i2c_message_start(i2c, msgs);
spin_unlock_irq(&i2c->lock); timeout = wait_event_timeout(i2c->wait, i2c->msg_num == , HZ * ); ret = i2c->msg_idx; /* having these next two as dev_err() makes life very
00000516 * noisy when doing an i2cdetect */ if (timeout == )
dev_dbg(i2c->dev, "timeout\n");
else if (ret != num)
dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); /* ensure the stop has been through the bus */ dev_dbg(i2c->dev, "waiting for bus idle\n"); /* first, try busy waiting briefly */
do {
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
} while ((iicstat & S3C2410_IICSTAT_START) && --spins); /* if that timed out sleep */
if (!spins) {
msleep();
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
} if (iicstat & S3C2410_IICSTAT_START)
dev_warn(i2c->dev, "timeout waiting for bus idle\n"); out:
return ret;
}
489行,如果IIC控制器挂起了的话就不用往下走了,返回出错。
492至497行,调用s3c24xx_i2c_set_master函数,读取IICSTAT寄存器,等待IIC总线空闲。
501至505行,记住这些变量的值,后面的分析会遇到。
507行,使能IIC控制器中断。
508行,调用s3c24xx_i2c_message_start函数开始读写操作,它的定义如下:
static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
struct i2c_msg *msg)
{
unsigned int addr = (msg->addr & 0x7f) << ;
unsigned long stat;
unsigned long iiccon; stat = ;
stat |= S3C2410_IICSTAT_TXRXEN; if (msg->flags & I2C_M_RD) {
stat |= S3C2410_IICSTAT_MASTER_RX;
addr |= ;
} else
stat |= S3C2410_IICSTAT_MASTER_TX; if (msg->flags & I2C_M_REV_DIR_ADDR)
addr ^= ; /* todo - check for wether ack wanted or not */
s3c24xx_i2c_enable_ack(i2c); iiccon = readl(i2c->regs + S3C2410_IICCON);
writel(stat, i2c->regs + S3C2410_IICSTAT); dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
writeb(addr, i2c->regs + S3C2410_IICDS); /* delay here to ensure the data byte has gotten onto the bus
00000192 * before the transaction is started */ ndelay(i2c->tx_setup); dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
writel(iiccon, i2c->regs + S3C2410_IICCON); stat |= S3C2410_IICSTAT_START;
writel(stat, i2c->regs + S3C2410_IICSTAT);
}
166行,高7位表示从机地址,最低1位表示读或写操作,0表示写,1表示读。
171行,IIC控制器发送和接收使能。
173行,条件不成立,所以执行177行,主机发送使能。
179行,与读操作相关的,因此if条件不成立。
183行,使能IIC控制器ACK应答。
剩下那些语句基本上都是在操作IIC控制器的寄存器,具体含义请看s3c6410的数据手册。
189行,将从机地址写入移位寄存器。
s3c24xx_i2c_message_start函数执行完后硬件就开始进行数据传输,回到s3c24xx_i2c_doxfer函数的第509行,释放锁,与499行是配对使用的。
511行,等待,等待传输操作完成,等待,只因曾经承若。有两种情况会唤醒它,一是超时,二是传输完成。
程序是在等待了,但我们的步伐却不会因此而停留,前面还有很长的路等着我们呢,还等什么,继续前进!
接下来看等待过程中发生的事情,没错,就是在中断里。中断处理函数是s3c24xx_i2c_irq,它的定义:
static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{
struct s3c24xx_i2c *i2c = dev_id;
unsigned long status;
unsigned long tmp; status = readl(i2c->regs + S3C2410_IICSTAT); if (status & S3C2410_IICSTAT_ARBITR) {
/* deal with arbitration loss */
dev_err(i2c->dev, "deal with arbitration loss\n");
} if (i2c->state == STATE_IDLE) {
dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n"); tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IRQPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
goto out;
} /* pretty much this leaves us with the fact that we've
00000446 * transmitted or received whatever byte we last sent */ i2s_s3c_irq_nextbyte(i2c, status); out:
return IRQ_HANDLED;
}
429行,读取状态寄存器。
431至434行,如果总线仲裁失败就打印错误信息。
436至443行,我们知道i2c->state是等于STATE_START的,因此这里的if条件不成立。
448行,i2s_s3c_irq_nextbyte函数执行具体中断处理,i2s_s3c_irq_nextbyte函数的定义:
static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
{
unsigned long tmp;
unsigned char byte;
int ret = ; switch (i2c->state) { case STATE_IDLE:
dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__);
goto out;
break; case STATE_STOP:
dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
s3c24xx_i2c_disable_irq(i2c);
goto out_ack; case STATE_START:
/* last thing we did was send a start condition on the
00000277 * bus, or started a new i2c message
00000278 */ if (iicstat & S3C2410_IICSTAT_LASTBIT &&
!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
/* ack was not received... */ dev_dbg(i2c->dev, "ack was not received\n");
s3c24xx_i2c_stop(i2c, -ENXIO);
goto out_ack;
} if (i2c->msg->flags & I2C_M_RD)
i2c->state = STATE_READ;
else
i2c->state = STATE_WRITE; /* terminate the transfer if there is nothing to do
00000295 * as this is used by the i2c probe to find devices. */ if (is_lastmsg(i2c) && i2c->msg->len == ) {
s3c24xx_i2c_stop(i2c, );
goto out_ack;
} if (i2c->state == STATE_READ)
goto prepare_read; /* fall through to the write state, as we will need to
00000306 * send a byte as well */ case STATE_WRITE:
/* we are writing data to the device... check for the
00000310 * end of the message, and if so, work out what to do
00000311 */ if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
if (iicstat & S3C2410_IICSTAT_LASTBIT) {
dev_dbg(i2c->dev, "WRITE: No Ack\n"); s3c24xx_i2c_stop(i2c, -ECONNREFUSED);
goto out_ack;
}
} retry_write: if (!is_msgend(i2c)) {
byte = i2c->msg->buf[i2c->msg_ptr++];
writeb(byte, i2c->regs + S3C2410_IICDS); /* delay after writing the byte to allow the
00000329 * data setup time on the bus, as writing the
00000330 * data to the register causes the first bit
00000331 * to appear on SDA, and SCL will change as
00000332 * soon as the interrupt is acknowledged */ ndelay(i2c->tx_setup); } else if (!is_lastmsg(i2c)) {
/* we need to go to the next i2c message */ dev_dbg(i2c->dev, "WRITE: Next Message\n"); i2c->msg_ptr = ;
i2c->msg_idx++;
i2c->msg++; /* check to see if we need to do another message */
if (i2c->msg->flags & I2C_M_NOSTART) { if (i2c->msg->flags & I2C_M_RD) {
/* cannot do this, the controller
00000350 * forces us to send a new START
00000351 * when we change direction */ s3c24xx_i2c_stop(i2c, -EINVAL);
} goto retry_write;
} else {
/* send the new start */
s3c24xx_i2c_message_start(i2c, i2c->msg);
i2c->state = STATE_START;
} } else {
/* send stop */ s3c24xx_i2c_stop(i2c, );
}
break; case STATE_READ:
/* we have a byte of data in the data register, do
00000372 * something with it, and then work out wether we are
00000373 * going to do any more read/write
00000374 */ byte = readb(i2c->regs + S3C2410_IICDS);
i2c->msg->buf[i2c->msg_ptr++] = byte; prepare_read:
if (is_msglast(i2c)) {
/* last byte of buffer */ if (is_lastmsg(i2c))
s3c24xx_i2c_disable_ack(i2c); } else if (is_msgend(i2c)) {
/* ok, we've read the entire buffer, see if there
00000388 * is anything else we need to do */ if (is_lastmsg(i2c)) {
/* last message, send stop and complete */
dev_dbg(i2c->dev, "READ: Send Stop\n"); s3c24xx_i2c_stop(i2c, );
} else {
/* go to the next transfer */
dev_dbg(i2c->dev, "READ: Next Transfer\n"); i2c->msg_ptr = ;
i2c->msg_idx++;
i2c->msg++;
}
} break;
} /* acknowlegde the IRQ and get back on with the work */ out_ack:
tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IRQPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
out:
return ret;
}
函数够长的,不过一路走来,早就已经习惯了。
263行,因为i2c->state=STATE_START,因此忽略其他case,直接从275行开始看。
280行,如果没有收到ACK信号并且没有设置忽略ACK则停止这次传输。
289行,if条件不成立,执行292行,i2c->state = STATE_WRITE。
297行,is_lastmsg函数的定义:
static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
{
return i2c->msg_idx >= (i2c->msg_num - );
}
因为i2c->msg_idx=0,i2c->msg_num=1,所以返回1。但是i2c->msg->len=2不为0,所以297行的if条件不成立。
302行,if条件不成立。
注意,这个case里没有并没有break,因此会继续往下执行。
313至320行,也是没收到ACK条件才会成立的。
324行,is_msgend函数的定义:
static inline int is_msgend(struct s3c24xx_i2c *i2c)
{
return i2c->msg_ptr >= i2c->msg->len;
}
因为i2c->msg_ptr=0,i2c->msg->len=2,因此返回0。324行的if条件成立。
325行,读取第一个要写的字节数据,然后i2c->msg_ptr= i2c->msg_ptr +1。
326行,将数据写入移位寄存器。
334行,延时一下。
368行,跳出switch,到411行。
411至413行,清除pending标志,恢复IIC传输。
下一次进中断的时候会进入308行的case,经过313至320行的判断后来到324行,这次is_msgend函数还是会返回0。325行,读取下一个字节数据,326行,将数据写入移位寄存器,过程和前面的一样。
当第三次进中断的时候,324行的条件就不会成立了,并且336行的if条件也不会成立,因此就会执行366行的s3c24xx_i2c_stop函数,它的定义如下:
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
{
unsigned long iicstat = readl(i2c->regs + S3C2410_IICSTAT); dev_dbg(i2c->dev, "STOP\n"); /* stop the transfer */
iicstat &= ~S3C2410_IICSTAT_START;
writel(iicstat, i2c->regs + S3C2410_IICSTAT); i2c->state = STATE_STOP; s3c24xx_i2c_master_complete(i2c, ret);
s3c24xx_i2c_disable_irq(i2c);
}
205行,读取状态寄存器。
210、211行,发送停止信号。
213行,i2c->state = STATE_STOP。
215行,调用s3c24xx_i2c_master_complete函数。
216行,禁止IIC控制器中断。下面看s3c24xx_i2c_master_complete函数的定义:
static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
{
dev_dbg(i2c->dev, "master_complete %d\n", ret); i2c->msg_ptr = ;
i2c->msg = NULL;
i2c->msg_idx++;
i2c->msg_num = ;
if (ret)
i2c->msg_idx = ret; wake_up(&i2c->wait);
}
113至118行,不用说了。
120行,唤醒那个睡着了的她,谁?就是那个“承若”。忘记了的话就回去看看呗。
至此,可以说ioctl的整个写过程已经说完了,至于读过程就不说了。累,确实有点累。
结束语
i2c-dev.c提供了一套不依赖于具体平台的驱动,让具体的驱动逻辑放在应用程序中,和SPI中的spidev.c的作用是很类似的。
Linux设备驱动剖析之IIC(四)的更多相关文章
- Linux设备驱动剖析之IIC(二)
953行,适配器的编号大于MAX_ID_MASK是不行的,MAX_ID_MASK是一个宏,展开后的值为61. 957至968行,关于管理小整形ID数的,没怎么了解,略过. 974行,调用i2c_reg ...
- Linux设备驱动剖析之IIC(一)
写在前面 由于IIC总线只需要两根线就可以完成读写操作,而且通信协议简单,一条总线上可以挂载多个设备,因此被广泛使用.但是IIC总线有一个缺点,就是传输速率比较低.本文基于Linux-2.6.36版本 ...
- Linux设备驱动剖析之IIC(三)
下面以eeprom用户程序调用ioctl函数的写操作为例追踪IIC子系统的调用过程.eeprom的用户测试是大部分开发板都自带的.看写一个字节数据的eeprom_write_byte函数的定义: in ...
- linux设备驱动归纳总结(四):5.多处理器下的竞态和并发【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-67673.html linux设备驱动归纳总结(四):5.多处理器下的竞态和并发 xxxxxxxxxx ...
- linux设备驱动归纳总结(四):4.单处理器下的竞态和并发【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-67005.html linux设备驱动归纳总结(四):4.单处理器下的竞态和并发 xxxxxxxxxx ...
- linux设备驱动归纳总结(四):3.抢占和上下文切换【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-65711.html linux设备驱动归纳总结(四):3.抢占和上下文切换 xxxxxxxxxxxxx ...
- linux设备驱动归纳总结(四):2.进程调度的相关概念【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-65555.html linux设备驱动归纳总结(四):2.进程调度的相关概念 xxxxxxxxxxxx ...
- linux设备驱动归纳总结(四):1.进程管理的相关概念【转】
本文转载自;http://blog.chinaunix.net/uid-25014876-id-64866.html linux设备驱动归纳总结(四):1.进程管理的相关概念 xxxxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(四):5.多处理器下的竞态和并发
linux设备驱动归纳总结(四):5.多处理器下的竞态和并发 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
随机推荐
- [原创]Java性能优化权威指南读书思维导图4
[原创]Java性能优化权威指南读书思维导图4
- AIX中vi编辑器使用
3.1 vi 简介 vi 是 UNIX 世界里使用非常普遍的全屏幕文本编辑器,几乎任何一种UNIX系统都会提供这套软件.AIX当然也支持这种编辑器.熟悉DOS下的文本处理后,用户在开始接触vi时也许会 ...
- PID控制器(比例-积分-微分控制器)- V
Linear Actuator - PID Control Introduction This application guide is designed to explain the basics ...
- GO开发环境搭建
GO开发环境搭建 1)下载GO SDK,并安装 https://golang.google.cn/dl/ 2)下载GO IDE:GOLAND,并安装 3)设置GOROOT和GOPATH 4)新建一个工 ...
- Knockout.Js官网学习(enable绑定、disable绑定)
enable绑定 enable绑定使DOM元素只有在参数值为 true的时候才enabled.在form表单元素input,select,和textarea上非常有用. enable简单示例 < ...
- .NET 11 个 Visual Studio 代码性能分析工具
原文地址 软件开发中的性能优化对程序员来说是一个非常重要的问题.一个小问题可能成为一个大的系统的瓶颈.但是对于程序员来说,通过自身去优化代码是十分困难的.幸运的是,有一些非常棒的工具可以帮助程序员进行 ...
- sublime 3插件推荐
新建文件以及快速注释 1. SublimeTmpl 快速生成文件模板 一直都很奇怪为什么sublime text 3没有新建文件模板的功能,像html头部的DTD声明每次都要复制粘贴.用Subli ...
- 安装babel遇到的异常
Error: Requires Babel "^7.0.0-0", but was loaded with "6.26.3". If you are sure ...
- 从HTML Components的衰落看Web Components的危机 HTML Components的一些特性 JavaScript什么叫端到端组件 自己对Polymer的意见
http://blog.jobbole.com/77837/ 原文出处: 徐飞(@民工精髓V) 搞前端时间比较长的同学都会知道一个东西,那就是HTC(HTML Components),这个东西名字很现 ...
- git checkout -b mybranch和git checkout mybranch
创建分支: $ git branch mybranch切换分支: $ git checkout mybranch创建并切换分支: $ git checkout -b mybranch更新maste ...