Skip to content

Commit 656147f

Browse files
Aniket RandiveAndi Shyti
authored andcommitted
i2c: qcom-geni: Avoid extra TX DMA TRE for single read message in GPI mode
In GPI mode, the I2C GENI driver programs an extra TX DMA transfer descriptor (TRE) on the TX channel when handling a single read message. This results in an unintended write phase being issued on the I2C bus, even though a read transaction does not require any TX data. For a single-byte read, the correct hardware sequence consists of the CONFIG and GO commands followed by a single RX DMA TRE. Programming an additional TX DMA TRE is redundant, causes unnecessary DMA buffer mapping on the TX channel, and may lead to incorrect bus behavior. Update the transfer logic to avoid programming a TX DMA TRE for single read messages in GPI mode. Co-developed-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com> Signed-off-by: Maramaina Naresh <naresh.maramaina@oss.qualcomm.com> Signed-off-by: Aniket Randive <aniket.randive@oss.qualcomm.com> Reviewed-by: Mukesh Kumar Savaliya <mukesh.savaliya@oss.qualcomm.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org> Link: https://lore.kernel.org/r/20260410101949.2315058-1-aniket.randive@oss.qualcomm.com
1 parent 6ecea20 commit 656147f

1 file changed

Lines changed: 19 additions & 5 deletions

File tree

drivers/i2c/busses/i2c-qcom-geni.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,8 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
625625
{
626626
struct gpi_i2c_config *peripheral;
627627
unsigned int flags;
628-
void *dma_buf;
629-
dma_addr_t addr;
628+
void *dma_buf = NULL;
629+
dma_addr_t addr = 0;
630630
enum dma_data_direction map_dirn;
631631
enum dma_transfer_direction dma_dirn;
632632
struct dma_async_tx_descriptor *desc;
@@ -639,6 +639,16 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
639639
gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config;
640640
msg_idx = gi2c_gpi_xfer->msg_idx_cnt;
641641

642+
/*
643+
* Skip TX DMA mapping for a read message (I2C_M_RD) to avoid
644+
* programming an extra TX DMA TRE that would cause an unintended
645+
* write cycle on the I2C bus before the actual read operation.
646+
*/
647+
if (op == I2C_WRITE && msgs[msg_idx].flags & I2C_M_RD) {
648+
peripheral->multi_msg = true;
649+
goto skip_tx_dma_map;
650+
}
651+
642652
dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1);
643653
if (!dma_buf) {
644654
ret = -ENOMEM;
@@ -658,6 +668,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
658668
goto out;
659669
}
660670

671+
skip_tx_dma_map:
661672
if (gi2c->is_tx_multi_desc_xfer) {
662673
flags = DMA_CTRL_ACK;
663674

@@ -740,9 +751,12 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[],
740751
return 0;
741752

742753
err_config:
743-
dma_unmap_single(gi2c->se.dev->parent, addr,
744-
msgs[msg_idx].len, map_dirn);
745-
i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false);
754+
/* Avoid DMA unmap as the write operation skipped DMA mapping */
755+
if (dma_buf) {
756+
dma_unmap_single(gi2c->se.dev->parent, addr,
757+
msgs[msg_idx].len, map_dirn);
758+
i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false);
759+
}
746760

747761
out:
748762
gi2c->err = ret;

0 commit comments

Comments
 (0)