From a07ad1cc0300931bfd76bfcd2da3ddad743f4a89 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Tue, 14 Aug 2007 18:37:14 +0200 Subject: [PATCH] i2c-mv64xxx: Reinitialize hw and driver on I2C bus hang Under certain conditions, the mv64xxx I2C bus can hang preventing further operation. To make the driver more robust, we now reset the I2C hardware and the driver state machine when such hangs are detected. Signed-off-by: Dale Farnsworth Acked-by: Mark A. Greer Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-mv64xxx.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 251154ae5d9..bb7bf68a7fb 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -107,6 +107,21 @@ struct mv64xxx_i2c_data { * ***************************************************************************** */ + +/* Reset hardware and initialize FSM */ +static void +mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) +{ + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET); + writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), + drv_data->reg_base + MV64XXX_I2C_REG_BAUD); + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); + writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); + writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP, + drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->state = MV64XXX_I2C_STATE_IDLE; +} + static void mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) { @@ -203,7 +218,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) drv_data->state, status, drv_data->msg->addr, drv_data->msg->flags); drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; - drv_data->state = MV64XXX_I2C_STATE_IDLE; + mv64xxx_i2c_hw_init(drv_data); drv_data->rc = -EIO; } } @@ -367,6 +382,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) "mv64xxx: I2C bus locked, block: %d, " "time_left: %d\n", drv_data->block, (int)time_left); + mv64xxx_i2c_hw_init(drv_data); } } else spin_unlock_irqrestore(&drv_data->lock, flags); @@ -443,19 +459,6 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = { * ***************************************************************************** */ -static void __devinit -mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) -{ - writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET); - writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), - drv_data->reg_base + MV64XXX_I2C_REG_BAUD); - writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); - writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); - writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); - drv_data->state = MV64XXX_I2C_STATE_IDLE; -} - static int __devinit mv64xxx_i2c_map_regs(struct platform_device *pd, struct mv64xxx_i2c_data *drv_data) -- 2.46.0