函数来源于Linux设备驱动开发详解.pdf。
// 53-54: 定义一个名为 `s3c24xx_i2c_message_start` 的静态函数,它属于 `struct s3c24xx_i2c` 结构体。
static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, struct i2c_msg *msg)
// 57: 计算I2C设备的地址,通过掩码操作获取消息地址的低7位。
unsigned int addr = (msg->addr & 0x78);
// 58-59: 声明两个无符号长整型变量 `stat` 和 `iiccon`,用于存储I2C状态和控制寄存器的值。
unsigned long stat;
unsigned long iiccon;
// 62-63: 读取I2C状态寄存器的当前值,存储到变量 `stat` 中。
stat = __raw_readl(i2c->regs + S3C2410_IICSCON);
// 检查I2C总线状态,根据不同的状态执行不同的操作:
// 64-65: 如果状态寄存器表明可以发送数据,并且消息标志表明是读操作,则设置地址为读模式。
if (stat & S3C2410_IICSTAT_TXRXEN && (msg->flags & I2C_M_RD))
{
stat |= S3C2410_IICSTAT_MASTERRX;
addr |= 0x01; // 设置读操作的标志位
}
// 68-70: 否则如果是写操作,则设置地址为写模式。
else
{
stat &= ~S3C2410_IICSTAT_MASTERTX;
addr &= ~0x01; // 清除读操作的标志位
}
// 72-73: 如果需要,启用I2C总线的ACK功能。
if (msg->flags & I2C_M_RECV_LEN)
{
s3c2410_i2c_enable_ack(i2c);
}
// 74-75: 读取I2C控制寄存器的当前值。
iiccon = __raw_readl(i2c->regs + S3C2410_IICCON);
// 76-77: 写回状态寄存器,清除可能的旧状态。
__raw_writel(stat, i2c->regs + S3C2410_IICSCON);
// 78: 发送I2C设备地址。
__raw_writeb(addr, i2c->regs + S3C2440_IICDS);
// 79: 在发送新的开始位之前,延时一段时间。
udelay(1);
// 80: 写入控制寄存器,开始I2C传输。
__raw_writel(iiccon, i2c->regs + S3C2410_IICCON);
// 81-82: 如果I2C状态寄存器表明已经开始,则再次写入状态寄存器以确认开始。
if (stat & S3C2410_IICSTAT_START)
{
__raw_writel(stat, i2c->regs + S3C2410_IICSCON);
}
这段代码主要处理I2C消息的开始阶段,包括设置I2C设备地址、配置读/写模式、可能的ACK使能,以及触发I2C传输的开始。代码使用了原始的寄存器读写操作(__raw_readl
和 __raw_writel
),这是Linux设备驱动中直接操作硬件寄存器的方法。此外,udelay
用于在发送新的开始位之前提供短暂的延时。