git: 8ef8939fd458 - main - bcm2835/spi: Support SPI_FLAG_KEEP_CS
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 14 Nov 2023 21:48:35 UTC
The branch main has been updated by jhibbits: URL: https://cgit.FreeBSD.org/src/commit/?id=8ef8939fd4581572e17860d7089cc6e06fd0221f commit 8ef8939fd4581572e17860d7089cc6e06fd0221f Author: Justin Hibbits <jhibbits@FreeBSD.org> AuthorDate: 2023-11-02 20:09:14 +0000 Commit: Justin Hibbits <jhibbits@FreeBSD.org> CommitDate: 2023-11-14 21:47:35 +0000 bcm2835/spi: Support SPI_FLAG_KEEP_CS Summary: 3c08673438 brought in SPI_FLAG_KEEP_CS to keep the SPI chip select held post-transfer completion. Add this support to bcm2835 SPI for SPI devices that need it. As part of this, the owner thread needed carried through so that no other thread can take over the SPI bus until the owner releases the chip select. Reviewed by: manu Sponsored by: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D42599 --- sys/arm/broadcom/bcm2835/bcm2835_spi.c | 33 +++++++++++++++++++++---------- sys/arm/broadcom/bcm2835/bcm2835_spivar.h | 2 ++ 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/sys/arm/broadcom/bcm2835/bcm2835_spi.c b/sys/arm/broadcom/bcm2835/bcm2835_spi.c index 7d11e6aa50f7..b7f53be2da8d 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_spi.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_spi.c @@ -388,8 +388,10 @@ bcm_spi_intr(void *arg) /* Check for end of transfer. */ if (sc->sc_written == sc->sc_len && sc->sc_read == sc->sc_len) { /* Disable interrupts and the SPI engine. */ - bcm_spi_modifyreg(sc, SPI_CS, - SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0); + if ((sc->sc_flags & BCM_SPI_KEEP_CS) == 0) { + bcm_spi_modifyreg(sc, SPI_CS, + SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0); + } wakeup(sc->sc_dev); } @@ -438,16 +440,23 @@ bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) /* If the controller is in use wait until it is available. */ BCM_SPI_LOCK(sc); - while (sc->sc_flags & BCM_SPI_BUSY) - mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0); + if (sc->sc_thread != curthread) + while (sc->sc_flags & BCM_SPI_BUSY) + mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0); /* Now we have control over SPI controller. */ sc->sc_flags = BCM_SPI_BUSY; + if ((cmd->flags & SPI_FLAG_KEEP_CS) != 0) + sc->sc_flags |= BCM_SPI_KEEP_CS; + /* Clear the FIFO. */ - bcm_spi_modifyreg(sc, SPI_CS, - SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO, - SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO); + if (sc->sc_thread != curthread) + bcm_spi_modifyreg(sc, SPI_CS, + SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO, + SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO); + + sc->sc_thread = curthread; /* Save a pointer to the SPI command. */ sc->sc_cmd = cmd; @@ -517,11 +526,15 @@ bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2); /* Make sure the SPI engine and interrupts are disabled. */ - bcm_spi_modifyreg(sc, SPI_CS, SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0); + if (!(cmd->flags & SPI_FLAG_KEEP_CS)) { + bcm_spi_modifyreg(sc, + SPI_CS, SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0); + sc->sc_thread = 0; + } - /* Release the controller and wakeup the next thread waiting for it. */ - sc->sc_flags = 0; wakeup_one(dev); + sc->sc_flags &= ~BCM_SPI_BUSY; + /* Release the controller and wakeup the next thread waiting for it. */ BCM_SPI_UNLOCK(sc); /* diff --git a/sys/arm/broadcom/bcm2835/bcm2835_spivar.h b/sys/arm/broadcom/bcm2835/bcm2835_spivar.h index 1c9a81edc777..85b13626a026 100644 --- a/sys/arm/broadcom/bcm2835/bcm2835_spivar.h +++ b/sys/arm/broadcom/bcm2835/bcm2835_spivar.h @@ -36,6 +36,7 @@ struct bcm_spi_softc { struct resource * sc_mem_res; struct resource * sc_irq_res; struct spi_command *sc_cmd; + struct thread *sc_thread; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; uint32_t sc_len; @@ -46,6 +47,7 @@ struct bcm_spi_softc { }; #define BCM_SPI_BUSY 0x1 +#define BCM_SPI_KEEP_CS 0x2 #define BCM_SPI_WRITE(_sc, _off, _val) \ bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _off, _val)