Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d62eb3a authored by Shrey Vijay's avatar Shrey Vijay Committed by Alok Chauhan
Browse files

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: default avatarShrey Vijay <shreyv@codeaurora.org>
parent a08aafd7
Loading
Loading
Loading
Loading
+29 −5
Original line number Original line Diff line number Diff line
@@ -77,6 +77,10 @@


#define I2C_AUTO_SUSPEND_DELAY	250
#define I2C_AUTO_SUSPEND_DELAY	250


#define I2C_TIMEOUT_SAFETY_COEFFICIENT	10

#define I2C_TIMEOUT_MIN_USEC	500000

enum i2c_se_mode {
enum i2c_se_mode {
	UNINITIALIZED,
	UNINITIALIZED,
	FIFO_SE_DMA,
	FIFO_SE_DMA,
@@ -89,6 +93,7 @@ struct geni_i2c_dev {
	unsigned int tx_wm;
	unsigned int tx_wm;
	int irq;
	int irq;
	int err;
	int err;
	u32 xfer_timeout;
	struct i2c_adapter adap;
	struct i2c_adapter adap;
	struct completion xfer;
	struct completion xfer;
	struct i2c_msg *cur;
	struct i2c_msg *cur;
@@ -192,12 +197,26 @@ static inline void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c, int dfs)
	mb();
	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)
static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
{
{
	if (gi2c->cur)
	if (gi2c->cur)
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev,
			    "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len,
			"len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n",
			    gi2c->cur->addr, gi2c->cur->flags);
			gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags,
			gi2c->xfer_timeout);


	if (err == I2C_NACK || err == GENI_ABORT_DONE) {
	if (err == I2C_NACK || err == GENI_ABORT_DONE) {
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n",
		GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n",
@@ -476,6 +495,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
		struct device *tx_dev = gi2c->wrapper_dev;
		struct device *tx_dev = gi2c->wrapper_dev;


		gi2c->cur = &msgs[i];
		gi2c->cur = &msgs[i];
		qcom_geni_i2c_calc_timeout(gi2c);
		if (!gi2c->cfg_sent) {
		if (!gi2c->cfg_sent) {
			segs++;
			segs++;
			sg_init_table(gi2c->tx_sg, segs);
			sg_init_table(gi2c->tx_sg, segs);
@@ -569,7 +589,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
		tx_cookie = dmaengine_submit(gi2c->tx_desc);
		tx_cookie = dmaengine_submit(gi2c->tx_desc);
		dma_async_issue_pending(gi2c->tx_c);
		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)
		if (msgs[i].flags & I2C_M_RD)
			geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
			geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph,
				msgs[i].len, DMA_FROM_DEVICE);
				msgs[i].len, DMA_FROM_DEVICE);
@@ -579,7 +600,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],


		if (!timeout) {
		if (!timeout) {
			GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev,
			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;
			gi2c->err = -ETIMEDOUT;
		}
		}
		if (gi2c->err) {
		if (gi2c->err) {
@@ -635,6 +657,7 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT);
		m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT);


		gi2c->cur = &msgs[i];
		gi2c->cur = &msgs[i];
		qcom_geni_i2c_calc_timeout(gi2c);
		mode = msgs[i].len > 32 ? SE_DMA : FIFO_MODE;
		mode = msgs[i].len > 32 ? SE_DMA : FIFO_MODE;
		ret = geni_se_select_mode(gi2c->base, mode);
		ret = geni_se_select_mode(gi2c->base, mode);
		if (ret) {
		if (ret) {
@@ -684,7 +707,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
		}
		}
		/* Ensure FIFO write go through before waiting for Done evet */
		/* Ensure FIFO write go through before waiting for Done evet */
		mb();
		mb();
		timeout = wait_for_completion_timeout(&gi2c->xfer, HZ);
		timeout = wait_for_completion_timeout(&gi2c->xfer,
						gi2c->xfer_timeout);
		if (!timeout) {
		if (!timeout) {
			geni_i2c_err(gi2c, GENI_TIMEOUT);
			geni_i2c_err(gi2c, GENI_TIMEOUT);
			gi2c->cur = NULL;
			gi2c->cur = NULL;