diff options
author | Alok Chauhan <alokc@nvidia.com> | 2011-08-15 17:47:40 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:47:24 -0800 |
commit | b939adc95698f75884a20b0a9e40f7ef32785225 (patch) | |
tree | 24b77c1fbe11017ed8c776e2649b3da5ade75112 /drivers/i2c | |
parent | 74460b7effdcd931f287da336e664f5819ee12c5 (diff) |
Revert "i2c: tegra: Remove the synchronization between isr and caller"
This reverts commit 738c1a66079ee7db8e4365aa85819ccdef2592a8.
This fixed the video recording system hang bug
Bug 842901
Reviewed-on: http://git-master/r/39912
Rebase-Id: R183a5a9202ec65099503ddad913a25b139bd6d91
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 46 |
1 files changed, 38 insertions, 8 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b9f155c14665..58cf7030860f 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -146,10 +146,12 @@ struct tegra_i2c_dev { struct clk *clk; struct resource *iomem; struct rt_mutex dev_lock; + spinlock_t clk_lock; void __iomem *base; int cont_id; int irq; bool irq_disabled; + bool controller_enabled; int is_dvc; bool is_slave; struct completion msg_complete; @@ -444,6 +446,14 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) u32 status; const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | I2C_INT_TX_FIFO_OVERFLOW; struct tegra_i2c_dev *i2c_dev = dev_id; + unsigned long flags; + + spin_lock_irqsave(&i2c_dev->clk_lock, flags); + if (!i2c_dev->controller_enabled) { + dev_warn(i2c_dev->dev, "Controller not enabled\n"); + spin_unlock_irqrestore(&i2c_dev->clk_lock, flags); + return IRQ_NONE; + } status = i2c_readl(i2c_dev, I2C_INT_STATUS); @@ -457,7 +467,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) i2c_dev->irq_disabled = 1; } - complete(&i2c_dev->msg_complete); goto err; } @@ -486,8 +495,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) dev_warn(i2c_dev->dev, "Packet status 0x%08x\n", i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS)); } - complete(&i2c_dev->msg_complete); - goto err; } @@ -503,7 +510,6 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) i2c_dev->irq_disabled = 1; } - complete(&i2c_dev->msg_complete); goto err; } @@ -521,15 +527,17 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ); } - if (status & I2C_INT_PACKET_XFER_COMPLETE) { - BUG_ON(i2c_dev->msg_buf_remaining); - complete(&i2c_dev->msg_complete); - } i2c_writel(i2c_dev, status, I2C_INT_STATUS); if (i2c_dev->is_dvc) dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); + if (status & I2C_INT_PACKET_XFER_COMPLETE) { + BUG_ON(i2c_dev->msg_buf_remaining); + complete(&i2c_dev->msg_complete); + } + + spin_unlock_irqrestore(&i2c_dev->clk_lock, flags); return IRQ_HANDLED; err: @@ -563,6 +571,8 @@ err: if (i2c_dev->is_dvc) dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); + complete(&i2c_dev->msg_complete); + spin_unlock_irqrestore(&i2c_dev->clk_lock, flags); return IRQ_HANDLED; } @@ -572,6 +582,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus, struct tegra_i2c_dev *i2c_dev = i2c_bus->dev; u32 int_mask; int ret; + unsigned long flags; tegra_i2c_flush_fifos(i2c_dev); @@ -628,7 +639,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus, "i2c transfer timed out, addr 0x%04x, data 0x%02x\n", msg->addr, msg->buf[0]); + spin_lock_irqsave(&i2c_dev->clk_lock, flags); + i2c_dev->controller_enabled = false; tegra_i2c_init(i2c_dev); + spin_unlock_irqrestore(&i2c_dev->clk_lock, flags); return -ETIMEDOUT; } @@ -638,7 +652,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus, if (likely(i2c_dev->msg_err == I2C_ERR_NONE)) return 0; + spin_lock_irqsave(&i2c_dev->clk_lock, flags); + i2c_dev->controller_enabled = false; tegra_i2c_init(i2c_dev); + spin_unlock_irqrestore(&i2c_dev->clk_lock, flags); + if (i2c_dev->msg_err == I2C_ERR_NO_ACK) { if (msg->flags & I2C_M_IGNORE_NAK) return 0; @@ -658,6 +676,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], struct tegra_i2c_dev *i2c_dev = i2c_bus->dev; int i; int ret = 0; + unsigned long flags; if (i2c_dev->is_suspended) return -EBUSY; @@ -683,6 +702,11 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (!i2c_dev->is_clkon_always) clk_enable(i2c_dev->clk); + + spin_lock_irqsave(&i2c_dev->clk_lock, flags); + i2c_dev->controller_enabled = true; + spin_unlock_irqrestore(&i2c_dev->clk_lock, flags); + for (i = 0; i < num; i++) { int stop = (i == (num - 1)) ? 1 : 0; ret = tegra_i2c_xfer_msg(i2c_bus, &msgs[i], stop); @@ -690,6 +714,10 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], break; } + spin_lock_irqsave(&i2c_dev->clk_lock, flags); + i2c_dev->controller_enabled = false; + spin_unlock_irqrestore(&i2c_dev->clk_lock, flags); + if (!i2c_dev->is_clkon_always) clk_disable(i2c_dev->clk); @@ -799,7 +827,9 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->msgs = NULL; i2c_dev->msgs_num = 0; + i2c_dev->controller_enabled = false; rt_mutex_init(&i2c_dev->dev_lock); + spin_lock_init(&i2c_dev->clk_lock); i2c_dev->slave_addr = plat->slave_addr; i2c_dev->is_dvc = plat->is_dvc; |