此代码段如何在I2C控制器中工作

时间:2014-10-04 13:33:03

标签: c linux linux-device-driver i2c

我试图从i2c-mpc.c I2C控制器中了解以下代码片段。

https://github.com/torvalds/linux/blob/master/drivers/i2c/busses/i2c-mpc.c#L440

static int mpc_write(struct mpc_i2c *i2c, int target,
             const u8 *data, int length, int restart)
{

    int i, result;
    unsigned timeout = i2c->adap.timeout;
    u32 flags = restart ? CCR_RSTA : 0;

    /* Start as master */
    writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
    /* Write target byte */
    writeb((target << 1), i2c->base + MPC_I2C_DR);

    result = i2c_wait(i2c, timeout, 1);
    if (result < 0)
        return result;

    for (i = 0; i < length; i++) {
        /* Write data byte */
        writeb(data[i], i2c->base + MPC_I2C_DR);

        result = i2c_wait(i2c, timeout, 1);
        if (result < 0)
            return result;
    }

    return 0;
}

任何人都可以请指出我们正在做的第440行writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);

是否所有四个寄存器都设置为值1以及标记varibales包含的内容是什么?

1 个答案:

答案 0 :(得分:2)

如果您想编写不可读且不可维护的代码(例如,经常在ucontroller代码中找到),那么有关语句可以写成:

if (restart)
    CCR = 0xF4;
else
    CCR = 0xF0;

但可读和可维护的代码使用外设寄存器中每个控制位(或字段/选项)的符号名称 因此,对于CCR寄存器,驱动程序在第45:50行定义这些符号:

#define CCR_MEN 0x80
#define CCR_MIEN 0x40
#define CCR_MSTA 0x20
#define CCR_MTX 0x10
#define CCR_TXAK 0x08
#define CCR_RSTA 0x04

标准做法是使用寄存器的助记符作为前缀,并为每个控制位名称的其余部分重用硬件名称(如数据表中所示)。
所以函数中的第二个参数是四个常量的按位ORing和一个产生0xF4或0xF0的变量,具体取决于传递的参数重新启动的值。


请注意,* NIX内核(即结构良好的代码)通常将内存映射外设寄存器定义为简单地址,并使用函数(或宏)执行写(或读)操作,与ucontroller代码经常使用赋值语句的方式不同。这种约定避免了寄存器名称的重载,因此仍然可以执行地址算术 例如,驱动程序定义控制寄存器的寄存器偏移量

#define MPC_I2C_CR 0x08

然后在写入CCR寄存器的驱动程序中定义 writeccr()

static inline void writeccr(struct mpc_i2c *i2c, u32 x)
{
    writeb(x, i2c->base + MPC_I2C_CR);
}

base 变量将包含外围寄存器使用物理地址范围的 ioremap()调用映射到的虚拟地址。
而ucontroller代码通常只是取消引用(物理)地址:

#define  CCR  (volatile u8 *)0x000003008

  

标志varibales包含什么?

第437行的声明和初始化:

    u32 flags = restart ? CCR_RSTA : 0;

相当于

u32 flags;
if (restart != 0) {
    flags = 0x04;    /* CCR_RSTA */
} else {
    flags = 0; 
}