aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorDale Farnsworth <dale@farnsworth.org>2007-08-14 12:37:14 -0400
committerJean Delvare <khali@hyperion.delvare>2007-08-14 12:37:14 -0400
commita07ad1cc0300931bfd76bfcd2da3ddad743f4a89 (patch)
treed8b7eb634571649f9401d351801e5de87cc5c91d /drivers/i2c
parent5af0e07f87e7d9be2a9db514af1e338341240f6d (diff)
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 <dale@farnsworth.org> Acked-by: Mark A. Greer <mgreer@mvista.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 251154ae5d97..bb7bf68a7fb6 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -107,6 +107,21 @@ struct mv64xxx_i2c_data {
107 * 107 *
108 ***************************************************************************** 108 *****************************************************************************
109 */ 109 */
110
111/* Reset hardware and initialize FSM */
112static void
113mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
114{
115 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
116 writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
117 drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
118 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
119 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
120 writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
121 drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
122 drv_data->state = MV64XXX_I2C_STATE_IDLE;
123}
124
110static void 125static void
111mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) 126mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
112{ 127{
@@ -203,7 +218,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
203 drv_data->state, status, drv_data->msg->addr, 218 drv_data->state, status, drv_data->msg->addr,
204 drv_data->msg->flags); 219 drv_data->msg->flags);
205 drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; 220 drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
206 drv_data->state = MV64XXX_I2C_STATE_IDLE; 221 mv64xxx_i2c_hw_init(drv_data);
207 drv_data->rc = -EIO; 222 drv_data->rc = -EIO;
208 } 223 }
209} 224}
@@ -367,6 +382,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
367 "mv64xxx: I2C bus locked, block: %d, " 382 "mv64xxx: I2C bus locked, block: %d, "
368 "time_left: %d\n", drv_data->block, 383 "time_left: %d\n", drv_data->block,
369 (int)time_left); 384 (int)time_left);
385 mv64xxx_i2c_hw_init(drv_data);
370 } 386 }
371 } else 387 } else
372 spin_unlock_irqrestore(&drv_data->lock, flags); 388 spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -443,19 +459,6 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
443 * 459 *
444 ***************************************************************************** 460 *****************************************************************************
445 */ 461 */
446static void __devinit
447mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
448{
449 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
450 writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
451 drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
452 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
453 writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
454 writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
455 drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
456 drv_data->state = MV64XXX_I2C_STATE_IDLE;
457}
458
459static int __devinit 462static int __devinit
460mv64xxx_i2c_map_regs(struct platform_device *pd, 463mv64xxx_i2c_map_regs(struct platform_device *pd,
461 struct mv64xxx_i2c_data *drv_data) 464 struct mv64xxx_i2c_data *drv_data)