原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://blog.youkuaiyun.com/piaozhiye
由于TVP5150的I2C协议不标准,TVP5150 I2C挂死导致系统I2C总线挂死,但是在dm6467 的I2C总线驱动中并没有处理好I2C timeout问题,因为一直dm6467的I2C复的位也是通过I2C读写去完成的,但是总线总是busy,因此I2C 永远复位不成功,导致死循环,系统CPU使用率100?(CPU使用率100 这个是猜测)。
I2C 挂死只能通过上电复位来恢复I2C总线,这个是linux 2.6.18版本的davinci驱动的一个bug,在后面的高版本内核已经修改过来,但是只是在DM355和DM644X中有效,在DM6467中没有作用。其原因是因为DM355和DM646X中它们的I2C引脚和GPIO引脚是复用的,可以通过操作GPIO引脚来复位I2C,但是在DM6467中I2C引脚没有复用因此不能通过这种方法去恢复I2C总线。
其大致的算法是在i2c_davinci_wait_bus_not_busy 中增加timeout次数的判定超过两次timeout的话,就恢复I2C总线,重新初始化I2C。代码如下:
static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
char allow_sleep)
{
unsigned long timeout;
static u16 to_cnt;
timeout = jiffies + DAVINCI_I2C_TIMEOUT;
while (davinci_i2c_read_reg(dev, DAVINCI_I2C_STR_REG)
& DAVINCI_I2C_STR_BB) {
if (to_cnt <= DAVINCI_I2C_MAX_TRIES) {
if (time_after(jiffies, timeout)) {
dev_warn(dev->dev,
"timeout waiting for bus ready\n");
to_cnt++;
return -ETIMEDOUT;
} else {
to_cnt = 0;
i2c_recover_bus(dev);
i2c_davinci_init(dev);
}
}
/* if (time_after(jiffies, timeout)) {
dev_warn(dev->dev,
"timeout waiting for bus ready\n");
return -ETIMEDOUT;
}*/
if (allow_sleep)
schedule_timeout(1);
}
return 0;
}
i2c_recover_bus(dev);是通过发送一个NACK给从设备,然后用GPIO模拟I2C时钟停止I2C设备,来恢复总线。
static void i2c_recover_bus(struct davinci_i2c_dev *dev)
{
u32 flag = 0;
struct davinci_i2c_platform_data *pdata = dev->dev->platform_data;
dev_err(dev->dev, "initiating i2c bus recovery\n");
/* Send NACK to the slave */
flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
flag |= DAVINCI_I2C_MDR_NACK;
/* write the data into mode register */
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
if (pdata)
generic_i2c_clock_pulse(pdata->scl_pin);
/* Send STOP */
flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
flag |= DAVINCI_I2C_MDR_STP;
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
}
具体可查阅:
http://lxr.linux.no/linux+v3.3.6/drivers/i2c/busses/i2c-davinci.c
其中需要修改的头文件。
在i2c.h头文件davinci_i2c_platform_data中增加 I2C sda 和scl 两个引脚的描述
1.include\asm-arm\arch\i2c.h
2.include\asm-arm\arch-davinci\i2c.h
3.include\asm\arch\i2c.h
4.asm\arch-davinci\i2c.h
#ifndef __ASM_ARCH_I2C_H
#define __ASM_ARCH_I2C_H
/* All frequencies are expressed in kHz */
struct davinci_i2c_platform_data {
unsigned int bus_freq; /* standard bus frequency */
unsigned int bus_delay; /* transaction delay */
unsigned int sda_pin; /* GPIO pin ID to use for SDA */
unsigned int scl_pin; /* GPIO pin ID to use for SCL */
};
#endif /* __ASM_ARCH_I2C_H */
2.初始化davinci_i2c_platform_data数据,例如以下是DM355的私有数据,
static struct davinci_i2c_platform_data i2c_pdata = {
.bus_freq = 400 /* kHz */,
.bus_delay = 0 /* usec */,
.sda_pin = 15,
.scl_pin = 14,
};
具体可以看path信息
http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2010-January/017526.html
这里是一个同样的问题
http://e2e.ti.com/support/embedded/linux/f/354/p/70448/309432.aspx#309432
http://e2e.ti.com/search/default.aspx#q=timeout+waiting+for+bus+ready&as=1&g=232