summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorChaitanya Bandi <bandik@nvidia.com>2013-02-27 15:13:35 +0530
committerRiham Haidar <rhaidar@nvidia.com>2013-03-13 16:22:54 -0700
commit6ccd093d5282dbddb5c590d6c1ebd4cc5d097a12 (patch)
tree172e8576c04bd1061a4267baf6e225ebc78d0e73 /drivers/i2c
parent84d79a515e3074d390a91755f931def47ff383c7 (diff)
i2c: tegra: Use ALL_PACKETS_XFER_COMPLETE interrupt
The issue is that some clock stretching is observed in case of coupled Write-Read transaction after the write transaction because we wait for PACKET_XFER_COMPLETE. Using ALL_PACKETS_XFER_COMPLETE will prevent that clock stretching. In case of non-coupled transactions, PACKET_XFER_COMPLETE is used. Bug 1234504 Change-Id: I7e51bc0cc674bc91ca63b15e3d4b8696de82e1cb Signed-off-by: Chaitanya Bandi <bandik@nvidia.com> Reviewed-on: http://git-master/r/204520 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-tegra.c42
1 files changed, 24 insertions, 18 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 9a42f6423ace..45b40332beeb 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -197,7 +197,6 @@ struct tegra_i2c_dev {
bool irq_disabled;
int is_dvc;
struct completion msg_complete;
- bool has_next_msg;
int msg_err;
int next_msg_err;
u8 *msg_buf;
@@ -225,6 +224,7 @@ struct tegra_i2c_dev {
bool is_clkon_always;
bool is_high_speed_enable;
u16 hs_master_code;
+ bool use_single_xfer_complete;
int (*arb_recovery)(int scl_gpio, int sda_gpio);
struct tegra_i2c_chipdata *chipdata;
struct tegra_i2c_bus busses[1];
@@ -567,7 +567,6 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
}
static int tegra_i2c_copy_next_to_current(struct tegra_i2c_dev *i2c_dev)
{
- i2c_dev->has_next_msg = 0;
i2c_dev->msg_buf = i2c_dev->next_msg_buf;
i2c_dev->msg_buf_remaining = i2c_dev->next_msg_buf_remaining;
i2c_dev->msg_err = i2c_dev->next_msg_err;
@@ -679,14 +678,15 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
if (i2c_dev->is_dvc)
dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
- if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+ if (status & I2C_INT_ALL_PACKETS_XFER_COMPLETE) {
BUG_ON(i2c_dev->msg_buf_remaining);
- if (i2c_dev->has_next_msg) {
- tegra_i2c_copy_next_to_current(i2c_dev);
- }
- else
- complete(&i2c_dev->msg_complete);
+ complete(&i2c_dev->msg_complete);
+ } else if ((status & I2C_INT_PACKET_XFER_COMPLETE)
+ && i2c_dev->use_single_xfer_complete) {
+ BUG_ON(i2c_dev->msg_buf_remaining);
+ complete(&i2c_dev->msg_complete);
}
+
return IRQ_HANDLED;
err:
@@ -739,7 +739,6 @@ err:
static int tegra_i2c_send_next_read_msg_pkt_header(struct tegra_i2c_dev *i2c_dev, struct i2c_msg *next_msg, enum msg_end_type end_state)
{
- i2c_dev->has_next_msg = true;
i2c_dev->next_msg_buf = next_msg->buf;
i2c_dev->next_msg_buf_remaining = next_msg->len;
i2c_dev->next_msg_err = I2C_ERR_NONE;
@@ -817,7 +816,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
i2c_dev->payload_size = msg->len - 1;
i2c_writel(i2c_dev, i2c_dev->payload_size, I2C_TX_FIFO);
- i2c_dev->io_header = I2C_HEADER_IE_ENABLE;
+ i2c_dev->use_single_xfer_complete = true;
+ i2c_dev->io_header = 0;
+ if (next_msg == NULL)
+ i2c_dev->io_header = I2C_HEADER_IE_ENABLE;
+
if (end_state == MSG_END_CONTINUE)
i2c_dev->io_header |= I2C_HEADER_CONTINUE_XFER;
else if (end_state == MSG_END_REPEAT_START)
@@ -840,7 +843,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
}
i2c_writel(i2c_dev, i2c_dev->io_header, I2C_TX_FIFO);
-
if (!(msg->flags & I2C_M_RD))
tegra_i2c_fill_tx_fifo(i2c_dev);
@@ -852,23 +854,27 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
if (i2c_dev->chipdata->has_xfer_complete_interrupt)
int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
+ if (i2c_dev->chipdata->has_xfer_complete_interrupt)
+ int_mask |= I2C_INT_ALL_PACKETS_XFER_COMPLETE;
+
if (msg->flags & I2C_M_RD)
int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
else if (i2c_dev->msg_buf_remaining)
int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
- i2c_dev->has_next_msg = 0;
-
if (next_msg != NULL) {
tegra_i2c_send_next_read_msg_pkt_header(i2c_dev, next_msg,
next_msg_end_state);
+ tegra_i2c_copy_next_to_current(i2c_dev);
int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
+ i2c_dev->use_single_xfer_complete = false;
}
if (!i2c_dev->chipdata->has_xfer_complete_interrupt)
spin_unlock_irqrestore(&i2c_dev->fifo_lock, flags);
tegra_i2c_unmask_irq(i2c_dev, int_mask);
+
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
i2c_readl(i2c_dev, I2C_INT_MASK));
@@ -1011,18 +1017,18 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
else
next_msg_end_type = MSG_END_REPEAT_START;
}
- if ((!(msgs[i].flags & I2C_M_RD)) && (msgs[i].len <= 8) && (msgs[i+1].flags & I2C_M_RD)) {
+ if ((!(msgs[i].flags & I2C_M_RD)) && (msgs[i].len <= 8) && (msgs[i+1].flags & I2C_M_RD)
+ && (next_msg_end_type != MSG_END_CONTINUE) && (end_type == MSG_END_REPEAT_START)) {
ret = tegra_i2c_xfer_msg(i2c_bus, &msgs[i], end_type, &msgs[i+1], next_msg_end_type);
if (ret)
break;
i++;
- }
- else
+ } else {
ret = tegra_i2c_xfer_msg(i2c_bus, &msgs[i], end_type, NULL, next_msg_end_type);
if (ret)
break;
- }
- else {
+ }
+ } else {
ret = tegra_i2c_xfer_msg(i2c_bus, &msgs[i], end_type, NULL, next_msg_end_type);
if (ret)
break;