i2c-qcom-geni: Calculate transfer timeout based on payload size

Large I2C transfers gets timed out, which can take more than
1 second for completion. To support such large transfers,
calculate transfer completion timeout based on the payload size.

Change-Id: Iccb8466ae334ba2940588528be18235f63f2fddd
Signed-off-by: Shrey Vijay <shreyv@codeaurora.org>
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index c7f6c6b..bc4af98 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -77,6 +77,10 @@
 
 #define I2C_AUTO_SUSPEND_DELAY	250
 
+#define I2C_TIMEOUT_SAFETY_COEFFICIENT	10
+
+#define I2C_TIMEOUT_MIN_USEC	500000
+
 enum i2c_se_mode {
 	UNINITIALIZED,
 	FIFO_SE_DMA,
@@ -89,6 +93,7 @@
 	unsigned int tx_wm;
 	int irq;
 	int err;
+	u32 xfer_timeout;
 	struct i2c_adapter adap;
 	struct completion xfer;
 	struct i2c_msg *cur;
@@ -192,12 +197,26 @@
 	mb();
 }
 
+static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c)
+{
+
+	struct geni_i2c_clk_fld *clk_itr = geni_i2c_clk_map + gi2c->clk_fld_idx;
+	size_t bit_cnt = gi2c->cur->len*9;
+	size_t bit_usec = (bit_cnt*USEC_PER_SEC)/clk_itr->clk_freq_out;
+	size_t xfer_max_usec = (bit_usec*I2C_TIMEOUT_SAFETY_COEFFICIENT) +
+							I2C_TIMEOUT_MIN_USEC;
+
+	gi2c->xfer_timeout = usecs_to_jiffies(xfer_max_usec);
+
+}
+
 static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
 {
 	if (gi2c->cur)
 		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
-			    "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len,
-			    gi2c->cur->addr, gi2c->cur->flags);
+			"len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n",
+			gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags,
+			gi2c->xfer_timeout);
 
 	if (err == I2C_NACK || err == GENI_ABORT_DONE) {
 		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n",
@@ -476,6 +495,7 @@
 		struct device *tx_dev = gi2c->wrapper_dev;
 
 		gi2c->cur = &msgs[i];
+		qcom_geni_i2c_calc_timeout(gi2c);
 		if (!gi2c->cfg_sent) {
 			segs++;
 			sg_init_table(gi2c->tx_sg, segs);
@@ -567,7 +587,8 @@
 		tx_cookie = dmaengine_submit(gi2c->tx_desc);
 		dma_async_issue_pending(gi2c->tx_c);
 
-		timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
+		timeout = wait_for_completion_timeout(&gi2c->xfer,
+						gi2c->xfer_timeout);
 		if (msgs[i].flags & I2C_M_RD)
 			geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
 				msgs[i].len, DMA_FROM_DEVICE);
@@ -577,7 +598,8 @@
 
 		if (!timeout) {
 			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
-				    "GSI Txn timed out\n");
+				    "GSI Txn timed out: %u len: %d\n",
+					gi2c->xfer_timeout, gi2c->cur->len);
 			gi2c->err = -ETIMEDOUT;
 		}
 		if (gi2c->err) {
@@ -633,6 +655,7 @@
 		m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT);
 
 		gi2c->cur = &msgs[i];
+		qcom_geni_i2c_calc_timeout(gi2c);
 		mode = msgs[i].len > 32 ? SE_DMA : FIFO_MODE;
 		ret = geni_se_select_mode(gi2c->base, mode);
 		if (ret) {
@@ -682,7 +705,8 @@
 		}
 		/* Ensure FIFO write go through before waiting for Done evet */
 		mb();
-		timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
+		timeout = wait_for_completion_timeout(&gi2c->xfer,
+						gi2c->xfer_timeout);
 		if (!timeout) {
 			geni_i2c_err(gi2c, GENI_TIMEOUT);
 			gi2c->cur = NULL;