Chinaunix首页 | 论坛 | 博客
  • 博客访问: 411188
  • 博文数量: 118
  • 博客积分: 294
  • 博客等级: 二等列兵
  • 技术积分: 667
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-16 20:31
文章分类

全部博文(118)

文章存档

2014年(3)

2012年(25)

2011年(90)

分类:

2011-10-17 21:11:31

原文地址:我对linux理解之i2c 二 作者:amingriyue

------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:amingriyue.blog.chinaunix.net
------------------------------------------

我们下面开始分析i2c的通信,即读写过程。
我们先看读函数,对应i2c core中的i2c_master_recv:
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
{
    struct i2c_adapter *adap=client->adapter;//通过client访问adapter
    struct i2c_msg msg;//i2c传输的单位
    int ret;

    msg.addr = client->addr;
    msg.flags = client->flags & I2C_M_TEN;
    msg.flags |= I2C_M_RD;//读标记,如果没有就是写
    msg.len = count;//数据字节数
    msg.buf = buf;//数据保存的地方

    ret = i2c_transfer(adap, &msg, 1);//传输1个msg

    /* If everything went ok (i.e. 1 msg transmitted), return #bytes
       transmitted, else error code. */
    return (ret == 1) ? count : ret;
}
在看下写函数,对应i2c core中的i2c_master_send:
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
    int ret;
    struct i2c_adapter *adap=client->adapter;//通过client访问adapter
    struct i2c_msg msg;//这个就是i2c传输的单位

    msg.addr = client->addr;
    msg.flags = client->flags & I2C_M_TEN;//没有读标记就代表写操作
    msg.len = count;//数据字节数
    msg.buf = (char *)buf;//要写的buf

    ret = i2c_transfer(adap, &msg, 1);//传输1个msg

    /* If everything went ok (i.e. 1 msg transmitted), return #bytes
       transmitted, else error code. */
    return (ret == 1) ? count : ret;
}
我们发现无论读还是写函数最终都使用i2c_transfer()进行传输msg,下面具体分析一下i2c_transfer:
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{
    unsigned long orig_jiffies;
    int ret, try;

    /* REVISIT the fault reporting model here is weak:
     *
     *  - When we get an error after receiving N bytes from a slave,
     *    there is no way to report "N".
     *
     *  - When we get a NAK after transmitting N bytes to a slave,
     *    there is no way to report "N" ... or to let the master
     *    continue executing the rest of this combined message, if
     *    that's the appropriate response.
     *
     *  - When for example "num" is two and we successfully complete
     *    the first message but get an error part way through the
     *    second, it's unclear whether that should be reported as
     *    one (discarding status on the second message) or errno
     *    (discarding status on the first one).
     */

    if (adap->algo->master_xfer) {//显然这个i2c_transfer依赖i2c_algorithm中的master_xfer是否被定义,我们在注册分析中知道它已经被赋值为.master_xfer = mxc_i2c_xfer
#ifdef DEBUG
        for (ret = 0; ret < num; ret++) {
            dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
                "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
                ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
                (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
        }
#endif

        if (in_atomic() || irqs_disabled()) {
            ret = mutex_trylock(&adap->bus_lock);
            if (!ret)
                /* I2C activity is ongoing. */
                return -EAGAIN;
        } else {
            mutex_lock_nested(&adap->bus_lock, adap->level);//给bus上锁了
        }

        /* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (ret = 0, try = 0; try <= adap->retries; try++) {
            ret = adap->algo->master_xfer(adap, msgs, num);//最终转换为i2c_algorithm中的master_xfer传输
            if (ret != -EAGAIN)
                break;
            if (time_after(jiffies, orig_jiffies + adap->timeout))//retry间隔时间
                break;
        }
        mutex_unlock(&adap->bus_lock);

        return ret;
    } else {
        dev_dbg(&adap->dev, "I2C level transfers not supported\n");
        return -EOPNOTSUPP;
    }
}
我们在注册分析中知道adap->algo被赋值为&mxc_i2c_algorithm,而mxc_i2c_algorithm定义为:
static struct i2c_algorithm mxc_i2c_algorithm = {
    .master_xfer = mxc_i2c_xfer,//传输函数
    .functionality = mxc_i2c_func//功能支持
};
所以adap->algo->master_xfer实际为mxc_i2c_xfer,这个函数即为i2c控制器的传输函数:
static int mxc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
            int num)
{
    mxc_i2c_device *dev = (mxc_i2c_device *) (i2c_get_adapdata(adap));
    int i, ret = 0, addr_comp = 0;
    volatile unsigned int sr;
    int retry = 5, retry_start = 5;

retry:
    if (dev->low_power) {
        dev_err(&dev->adap.dev, "I2C Device in low power mode\n");
        return -EREMOTEIO;
    }

    if (num < 1) {
        return 0;
    }

    mxc_i2c_module_en(dev, msgs[0].flags);
    sr = readw(dev->membase + MXC_I2SR);//读i2c的状态寄存器
    /*
     * Check bus state
     */

    while ((sr & MXC_I2SR_IBB) && retry--) {//检查i2c总线状态是否处于忙
        udelay(5);
        sr = readw(dev->membase + MXC_I2SR);
    }

    if ((sr & MXC_I2SR_IBB) && retry < 0) {
        mxc_i2c_module_dis(dev);
        dev_err(&dev->adap.dev, "Bus busy\n");
        return -EREMOTEIO;
    }

    //gpio_i2c_active(dev->adap.id);
    dev->transfer_done = false;
    dev->tx_success = false;
    for (i = 0; i < num && ret >= 0; i++) {//num是要传输的msg个数
        addr_comp = 0;
        /*
         * Send the slave address and transfer direction in the
         * address cycle
         */
        if (i == 0) {
            /*
             * Send a start or repeat start signal
             */
            if (mxc_i2c_start(dev, &msgs[0])){//发送开始信号
                if(retry_start-- != 0)
                    goto retry;
                return -EREMOTEIO;
            }
            /* Wait for the address cycle to complete */
            if (mxc_i2c_wait_for_tc(dev, msgs[0].flags)) {//等待地址周期完成
                mxc_i2c_stop(dev);
                //gpio_i2c_inactive(dev->adap.id);
                mxc_i2c_module_dis(dev);
                return -EREMOTEIO;
            }
            addr_comp = 1;
        } else {
            /*
             * Generate repeat start only if required i.e the address
             * changed or the transfer direction changed
             */
            if ((msgs[i].addr != msgs[i - 1].addr) ||
                ((msgs[i].flags & I2C_M_RD) !=
                 (msgs[i - 1].flags & I2C_M_RD))) {//从if条件可以看出是判断地址和读写方向
                mxc_i2c_repstart(dev, &msgs[i]);
                /* Wait for the address cycle to complete */
                if (mxc_i2c_wait_for_tc(dev, msgs[i].flags)) {
                    mxc_i2c_stop(dev);
                    //gpio_i2c_inactive(dev->adap.id);
                    mxc_i2c_module_dis(dev);
                    return -EREMOTEIO;
                }
                addr_comp = 1;
            }
        }

        /* Transfer the data */
        if (msgs[i].flags & I2C_M_RD) {//根据读写标记决定是读操作还是写操作
            /* Read the data */
            ret = mxc_i2c_readbytes(dev, &msgs[i], (i + 1 == num),
                        addr_comp);
            if (ret < 0) {
                dev_err(&dev->adap.dev, "mxc_i2c_readbytes:"
                    " fail.\n");
                break;
            }
        } else {
            /* Write the data */
            ret = mxc_i2c_writebytes(dev, &msgs[i], (i + 1 == num));
            if (ret < 0) {
                dev_err(&dev->adap.dev, "mxc_i2c_writebytes:"
                    " fail.\n");
                break;
            }
        }
    }

    //gpio_i2c_inactive(dev->adap.id);
    mxc_i2c_module_dis(dev);
    /*
     * Decrease by 1 as we do not want Start message to be included in
     * the count
     */
    return (i < 0 ? ret : i);
}
我们看到控制器的传输函数是按照i2c协议的传输过程。在这里我们要看下mxc_i2c_start(dev, &msgs[0]):
static int mxc_i2c_start(mxc_i2c_device *dev, struct i2c_msg *msg)
{
    volatile unsigned int cr, sr;
    unsigned int addr_trans;
    int retry = 16;
retry:
    /*
     * Set the slave address and the requested transfer mode
     * in the data register
     */
    addr_trans = msg->addr << 1;//地址x2,所以设备开始设置地址时要设为写地址的1/2
    if (msg->flags & I2C_M_RD) {//如果是读操作,这地址加1
        addr_trans |= 0x01;
    }
......
}
我们注意一下这里的地址转换,所以设备信息设置的时候注意一下地址大小需要除以2 。

上面就是i2c读写过程:driver->i2c_core->adapter

阅读(4506) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~