我试图从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包含的内容是什么?
答案 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;
}