aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2010-12-09 10:37:39 +0000
committerAlan Cox <alan@linux.intel.com>2010-12-09 10:37:39 +0000
commit3d73d6872ee9d23883cb2f4f2fd492f9e3e636e5 (patch)
tree7ea23fb7a1516336258eb54ccdf283db947530d3 /drivers
parentc61f30105e1081dd3d7332eb1275b5291654c182 (diff)
downloadmrst-s0i3-test-3d73d6872ee9d23883cb2f4f2fd492f9e3e636e5.tar.gz
mrst-s0i3-test-3d73d6872ee9d23883cb2f4f2fd492f9e3e636e5.tar.xz
mrst-s0i3-test-3d73d6872ee9d23883cb2f4f2fd492f9e3e636e5.zip
The old solution for i2c xfer timeout was to set timeout value to one second
for all i2c xfers. That's not reasonable for all of the various speed modes and data lengths. This patch sets the xfer_read timeout value based on both bus speed and data length. Signed-off-by: Bin Yang <bin.yang@intel.com> [Ported to the upstream branch and extracted as a helper function] Signed-off-by: Alan Cox <alan@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-intel-mid.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c
index fd30e8b219b..f540d278847 100644
--- a/drivers/i2c/busses/i2c-intel-mid.c
+++ b/drivers/i2c/busses/i2c-intel-mid.c
@@ -303,6 +303,29 @@ static int ctl_num = 6;
module_param_array(speed_mode, int, &ctl_num, S_IRUGO);
MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)");
+/* Timeout and delay bases for the speed modes */
+static const u16 xfer_timeout[NUM_SPEEDS] = {100, 25, 3};
+
+/**
+ * xfer_wait - wait for a transfer to complete
+ * @adapt: i2c interface
+ * @len: length of message
+ *
+ * Wait for completion or timeout of a message. The timeout depends upon
+ * the speed of the interface and the message length
+ *
+ * Returns the result of the wait for completion
+ */
+
+static int xfer_wait(struct intel_mid_i2c_private *i2c, int len)
+{
+ unsigned long timeout;
+
+ timeout = msecs_to_jiffies(len * xfer_timeout[i2c->speed]);
+ return wait_for_completion_interruptible_timeout(&i2c->complete,
+ timeout);
+}
+
/**
* intel_mid_i2c_disable - Disable I2C controller
* @adap: struct pointer to i2c_adapter
@@ -322,7 +345,6 @@ static int intel_mid_i2c_disable(struct i2c_adapter *adap)
int err = 0;
int count = 0;
int ret1, ret2;
- static const u16 delay[NUM_SPEEDS] = {100, 25, 3};
/* Set IC_ENABLE to 0 */
writel(0, i2c->base + IC_ENABLE);
@@ -331,7 +353,7 @@ static int intel_mid_i2c_disable(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "mrst i2c disable\n");
while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1)
|| (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) {
- udelay(delay[i2c->speed]);
+ udelay(xfer_timeout[i2c->speed]);
writel(0, i2c->base + IC_ENABLE);
dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n",
count, i2c->speed);
@@ -513,6 +535,7 @@ static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c)
i2c->status = STATUS_XFER_ABORT;
}
+
/**
* xfer_read - Internal function to implement master read transfer.
* @adap: i2c_adapter struct pointer
@@ -554,7 +577,7 @@ static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
writel(IC_RD, i2c->base + IC_DATA_CMD);
i2c->status = STATUS_READ_START;
- err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+ err = xfer_wait(i2c, length);
if (!err) {
dev_err(&adap->dev, "Timeout for ACK from I2C slave 0x%x\n",
i2c->msg->addr);
@@ -607,7 +630,7 @@ static int xfer_write(struct i2c_adapter *adap,
writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD);
i2c->status = STATUS_WRITE_START;
- err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
+ err = xfer_wait(i2c, length);
if (!err) {
dev_err(&adap->dev, "Timeout for ACK from I2C slave 0x%x\n",
i2c->msg->addr);