diff --git a/sys/arm/broadcom/bcm2835/bcm2835_spi.c b/sys/arm/broadcom/bcm2835/bcm2835_spi.c --- a/sys/arm/broadcom/bcm2835/bcm2835_spi.c +++ b/sys/arm/broadcom/bcm2835/bcm2835_spi.c @@ -388,8 +388,10 @@ /* 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 @@ /* 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 @@ 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 --- a/sys/arm/broadcom/bcm2835/bcm2835_spivar.h +++ b/sys/arm/broadcom/bcm2835/bcm2835_spivar.h @@ -36,6 +36,7 @@ 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 @@ }; #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)