diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 1c93864e0e4d..6d718916fba4 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -1076,7 +1076,17 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan,
 	dev_dbg(gpii->gpi_dev->dev, "Residue %d\n", result.residue);
 
 	dma_cookie_complete(&vd->tx);
-	dmaengine_desc_get_callback_invoke(&vd->tx, &result);
+	if (gchan->protocol == QCOM_GPI_I2C) {
+		struct dmaengine_desc_callback cb;
+		struct gpi_i2c_config *i2c;
+
+		dmaengine_desc_get_callback(&vd->tx, &cb);
+		i2c = cb.callback_param;
+		i2c->status = compl_event->status;
+		dmaengine_desc_callback_invoke(&cb, &result);
+	} else {
+		dmaengine_desc_get_callback_invoke(&vd->tx, &result);
+	}
 
 gpi_free_desc:
 	spin_lock_irqsave(&gchan->vc.lock, flags);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index da94df466e83..5092d10e8f47 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -484,9 +484,16 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
 
 static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result)
 {
-	struct geni_i2c_dev *gi2c = cb;
-
-	if (result->result != DMA_TRANS_NOERROR) {
+	struct gpi_i2c_config *i2c = cb;
+	struct geni_i2c_dev *gi2c = i2c->gi2c;
+
+	if (i2c->status & (BIT(NACK) << 5)) {
+		geni_i2c_err(gi2c, NACK);
+	} else if (i2c->status & (BIT(BUS_PROTO) << 5)) {
+		geni_i2c_err(gi2c, BUS_PROTO);
+	} else if (i2c->status & (BIT(ARB_LOST) << 5)) {
+		geni_i2c_err(gi2c, ARB_LOST);
+	} else if (result->result != DMA_TRANS_NOERROR) {
 		dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result);
 		gi2c->err = -EIO;
 	} else if (result->residue) {
@@ -568,7 +575,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
 	}
 
 	desc->callback_result = i2c_gpi_cb_result;
-	desc->callback_param = gi2c;
+	desc->callback_param = peripheral;
 
 	dmaengine_submit(desc);
 	*buf = dma_buf;
@@ -585,33 +592,38 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
 static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], int num)
 {
 	struct dma_slave_config config = {};
-	struct gpi_i2c_config peripheral = {};
+	struct gpi_i2c_config *peripheral;
 	int i, ret = 0, timeout;
 	dma_addr_t tx_addr, rx_addr;
 	void *tx_buf = NULL, *rx_buf = NULL;
 	const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
 
-	config.peripheral_config = &peripheral;
-	config.peripheral_size = sizeof(peripheral);
+	peripheral = devm_kzalloc(gi2c->se.dev, sizeof(*peripheral), GFP_KERNEL);
+	if (!peripheral)
+		return -ENOMEM;
+
+	config.peripheral_config = peripheral;
+	config.peripheral_size = sizeof(struct gpi_i2c_config);
 
-	peripheral.pack_enable = I2C_PACK_TX | I2C_PACK_RX;
-	peripheral.cycle_count = itr->t_cycle_cnt;
-	peripheral.high_count = itr->t_high_cnt;
-	peripheral.low_count = itr->t_low_cnt;
-	peripheral.clk_div = itr->clk_div;
-	peripheral.set_config = 1;
-	peripheral.multi_msg = false;
+	peripheral->gi2c = gi2c;
+	peripheral->pack_enable = I2C_PACK_TX | I2C_PACK_RX;
+	peripheral->cycle_count = itr->t_cycle_cnt;
+	peripheral->high_count = itr->t_high_cnt;
+	peripheral->low_count = itr->t_low_cnt;
+	peripheral->clk_div = itr->clk_div;
+	peripheral->set_config = 1;
+	peripheral->multi_msg = false;
 
 	for (i = 0; i < num; i++) {
 		gi2c->cur = &msgs[i];
 		gi2c->err = 0;
 		dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len);
 
-		peripheral.stretch = 0;
+		peripheral->stretch = 0;
 		if (i < num - 1)
-			peripheral.stretch = 1;
+			peripheral->stretch = 1;
 
-		peripheral.addr = msgs[i].addr;
+		peripheral->addr = msgs[i].addr;
 
 		ret =  geni_i2c_gpi(gi2c, &msgs[i], &config,
 				    &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c);
diff --git a/include/linux/dma/qcom-gpi-dma.h b/include/linux/dma/qcom-gpi-dma.h
index 6680dd1a43c6..af264f769344 100644
--- a/include/linux/dma/qcom-gpi-dma.h
+++ b/include/linux/dma/qcom-gpi-dma.h
@@ -64,6 +64,8 @@ enum i2c_op {
  * @set_config: set peripheral config
  * @rx_len: receive length for buffer
  * @op: i2c cmd
+ * @status: stores gpi event status based on interrupt
+ * @gi2c: pointer to i2c device handle
  * @muli-msg: is part of multi i2c r-w msgs
  */
 struct gpi_i2c_config {
@@ -78,6 +80,8 @@ struct gpi_i2c_config {
 	u32 rx_len;
 	enum i2c_op op;
 	bool multi_msg;
+	u32 status;
+	struct geni_i2c_dev *gi2c;
 };
 
 #endif /* QCOM_GPI_DMA_H */
