Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

spi: spi-fsl-lpspi: Handle clock polarity and phase

The LPSPI driver currently does not support setting SPI bus clock
polarity and phase, add support for it.

It is important to configure correct initial clock polarity and phase
before the GPIO chipselect toggles, otherwise a chip attached to the
bus might recognize the first change of clock signal as the first
clock cycle and get confused.

In order to set up the correct polarity and phase on the clock signal
before the GPIO chipselects get configured by the SPI core, the
controller has to be briefly brought up in fsl_lpspi_prepare_message().
The fsl_lpspi_prepare_message() behaves like a zero-length transfer
which always uses PIO and never DMA, and which leaves the clock signal
in the correct state at the end of such transfer, which happens before
the GPIO chipselect toggles.

Signed-off-by: Marek Vasut <marex@nabladev.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260127222353.1452003-1-marex@nabladev.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Marek Vasut and committed by
Mark Brown
7ae4d097 5c6808d1

+50 -4
+50 -4
drivers/spi/spi-fsl-lpspi.c
··· 281 281 fsl_lpspi->rx(fsl_lpspi); 282 282 } 283 283 284 - static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi) 284 + static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *fsl_lpspi, 285 + struct spi_device *spi) 285 286 { 286 287 u32 temp = 0; 287 288 ··· 304 303 temp |= TCR_CONTC; 305 304 } 306 305 } 306 + 307 + if (spi->mode & SPI_CPOL) 308 + temp |= TCR_CPOL; 309 + 310 + if (spi->mode & SPI_CPHA) 311 + temp |= TCR_CPHA; 312 + 307 313 writel(temp, fsl_lpspi->base + IMX7ULP_TCR); 308 314 309 315 dev_dbg(fsl_lpspi->dev, "TCR=0x%x\n", temp); ··· 496 488 497 489 fsl_lpspi->watermark = min(fsl_lpspi->txfifosize, t->len); 498 490 491 + return fsl_lpspi_config(fsl_lpspi); 492 + } 493 + 494 + static int fsl_lpspi_prepare_message(struct spi_controller *controller, 495 + struct spi_message *msg) 496 + { 497 + struct fsl_lpspi_data *fsl_lpspi = 498 + spi_controller_get_devdata(controller); 499 + struct spi_device *spi = msg->spi; 500 + struct spi_transfer *t; 501 + int ret; 502 + 503 + t = list_first_entry_or_null(&msg->transfers, struct spi_transfer, 504 + transfer_list); 505 + if (!t) 506 + return 0; 507 + 508 + fsl_lpspi->is_first_byte = true; 509 + fsl_lpspi->usedma = false; 510 + ret = fsl_lpspi_setup_transfer(controller, spi, t); 511 + 499 512 if (fsl_lpspi_can_dma(controller, spi, t)) 500 513 fsl_lpspi->usedma = true; 501 514 else 502 515 fsl_lpspi->usedma = false; 503 516 504 - return fsl_lpspi_config(fsl_lpspi); 517 + if (ret < 0) 518 + return ret; 519 + 520 + fsl_lpspi_set_cmd(fsl_lpspi, spi); 521 + 522 + /* No IRQs */ 523 + writel(0, fsl_lpspi->base + IMX7ULP_IER); 524 + 525 + /* Controller disable, clear FIFOs, clear status */ 526 + writel(CR_RRF | CR_RTF, fsl_lpspi->base + IMX7ULP_CR); 527 + writel(SR_CLEAR_MASK, fsl_lpspi->base + IMX7ULP_SR); 528 + 529 + return 0; 505 530 } 506 531 507 532 static int fsl_lpspi_target_abort(struct spi_controller *controller) ··· 794 753 spi_controller_get_devdata(controller); 795 754 int ret; 796 755 797 - fsl_lpspi->is_first_byte = true; 756 + if (fsl_lpspi_can_dma(controller, spi, t)) 757 + fsl_lpspi->usedma = true; 758 + else 759 + fsl_lpspi->usedma = false; 760 + 798 761 ret = fsl_lpspi_setup_transfer(controller, spi, t); 799 762 if (ret < 0) 800 763 return ret; 801 764 802 765 t->effective_speed_hz = fsl_lpspi->config.effective_speed_hz; 803 766 804 - fsl_lpspi_set_cmd(fsl_lpspi); 767 + fsl_lpspi_set_cmd(fsl_lpspi, spi); 805 768 fsl_lpspi->is_first_byte = false; 806 769 807 770 if (fsl_lpspi->usedma) ··· 989 944 } 990 945 991 946 controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); 947 + controller->prepare_message = fsl_lpspi_prepare_message; 992 948 controller->transfer_one = fsl_lpspi_transfer_one; 993 949 controller->prepare_transfer_hardware = lpspi_prepare_xfer_hardware; 994 950 controller->unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware;