Skip to content

Commit 342d00a

Browse files
committed
FROMLIST: spi: qcom-geni: Fix cs_change handling on the last transfer
Commit b99181c ("spi-geni-qcom: remove manual CS control") introduced automatic CS control via the FRAGMENTATION bit, but missed the case where cs_change is set on the last transfer in a message. For the last transfer, cs_change means that CS should remain asserted after the message completes. Since GENI SPI controls CS through FRAGMENTATION, set FRAGMENTATION for this case as well as for non-last transfers where cs_change is not set. Additionally, setup_gsi_xfer() was storing FRAGMENTATION (BIT(2) = 4) in peripheral.fragmentation, which is a boolean field consumed by gpi_create_spi_tre() via u32_encode_bits(..., TRE_SPI_GO_FRAG). Storing 4 causes u32_encode_bits to mask it to 0, silently disabling the FRAG bit in the GPI TRE regardless of the cs_change logic. Store 1 instead. Without these fixes, TPM TIS SPI transfers deassert CS between single-transfer messages that use cs_change to keep CS asserted across the header, wait-state, and data phases, breaking TCG SPI flow control: tpm_tis_spi: probe of spi11.0 failed with error -110 Update both setup_se_xfer() and setup_gsi_xfer() to handle this condition. Link: https://lore.kernel.org/all/20260529-fix-spi-fragmentation-bit-logic-v1-1-3b30f1a3dd7d@oss.qualcomm.com/ Fixes: b99181c ("spi-geni-qcom: remove manual CS control") Cc: stable@vger.kernel.org Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
1 parent 07adbc9 commit 342d00a

1 file changed

Lines changed: 19 additions & 8 deletions

File tree

drivers/spi/spi-geni-qcom.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -440,10 +440,15 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas
440440
return ret;
441441
}
442442

443-
if (!xfer->cs_change) {
444-
if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
445-
peripheral.fragmentation = FRAGMENTATION;
446-
}
443+
/*
444+
* Set fragmentation to keep CS asserted after this transfer when:
445+
* - non-last transfer with cs_change=0: keep CS between chained transfers
446+
* - last transfer with cs_change=1: keep CS asserted after the message
447+
* (e.g. TPM TIS SPI uses cs_change=1 on single-transfer messages to
448+
* keep CS asserted across header, wait-state and data phases)
449+
*/
450+
peripheral.fragmentation = list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers) ?
451+
xfer->cs_change : !xfer->cs_change;
447452

448453
if (peripheral.cmd & SPI_RX) {
449454
dmaengine_slave_config(mas->rx, &config);
@@ -849,10 +854,16 @@ static int setup_se_xfer(struct spi_transfer *xfer,
849854
mas->cur_xfer_mode = GENI_SE_DMA;
850855
geni_se_select_mode(se, mas->cur_xfer_mode);
851856

852-
if (!xfer->cs_change) {
853-
if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
854-
m_params = FRAGMENTATION;
855-
}
857+
/*
858+
* Set FRAGMENTATION to keep CS asserted after this transfer when:
859+
* - non-last transfer with cs_change=0: keep CS between chained transfers
860+
* - last transfer with cs_change=1: keep CS asserted after the message
861+
* (e.g. TPM TIS SPI uses cs_change=1 on single-transfer messages to
862+
* keep CS asserted across header, wait-state and data phases)
863+
*/
864+
if (list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers) ?
865+
xfer->cs_change : !xfer->cs_change)
866+
m_params = FRAGMENTATION;
856867

857868
/*
858869
* Lock around right before we start the transfer since our

0 commit comments

Comments
 (0)