summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorChaitanya Bandi <bandik@nvidia.com>2012-03-16 17:47:35 +0530
committerSimone Willett <swillett@nvidia.com>2012-04-03 09:27:00 -0700
commit8ddb969ed5b866ddbba5c55043848b8b9ab3dda4 (patch)
treef9a5d66fcf79a53adfd0c1ea41b71851f56ed00e /drivers/i2c
parentd1bafe42b06e728e4502b9cbaba39c34d3d58913 (diff)
i2c: tegra: Fix to avoid possible race condition
Because of race condition between isr and tx fifo fill, duplicate data is being written. So added locking to make Tx fifo fill as atomic. Change-Id: Ia99466adadfb6d86a6f238ec4cd0aa13bd36e434 Signed-off-by: Chaitanya Bandi <bandik@nvidia.com> Reviewed-on: http://git-master/r/90870 Reviewed-by: Simone Willett <swillett@nvidia.com> Tested-by: Simone Willett <swillett@nvidia.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-tegra.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index ad12f75bbdbf..bde4a6dd8e33 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -151,6 +151,7 @@ struct tegra_i2c_dev {
struct clk *fast_clk;
struct resource *iomem;
struct rt_mutex dev_lock;
+ spinlock_t fifo_lock;
void __iomem *base;
int cont_id;
int irq;
@@ -320,6 +321,9 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
u8 *buf = i2c_dev->msg_buf;
size_t buf_remaining = i2c_dev->msg_buf_remaining;
int words_to_transfer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c_dev->fifo_lock, flags);
val = i2c_readl(i2c_dev, I2C_FIFO_STATUS);
tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >>
@@ -369,6 +373,8 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
i2c_writel(i2c_dev, val, I2C_TX_FIFO);
}
+ spin_unlock_irqrestore(&i2c_dev->fifo_lock, flags);
+
return 0;
}
@@ -885,6 +891,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->msgs = NULL;
i2c_dev->msgs_num = 0;
rt_mutex_init(&i2c_dev->dev_lock);
+ spin_lock_init(&i2c_dev->fifo_lock);
i2c_dev->slave_addr = plat->slave_addr;
i2c_dev->hs_master_code = plat->hs_master_code;