From 298c90d007ab740fbdbc6872d47b26011c25c554 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 29 Nov 2019 10:25:00 +0000 Subject: [PATCH] Fix SPI mode setting The SPI-Py API allows the user to choose one of the four major SPI modes. It does so using the SPI_IOC_WR_MODE ioctl, which gives access to the bottom 8 bits of the mode property of the spidev instance, but unfortunately it just sets its preferred value, zeroing any higher bits that might have been set, A change to the spi-bcm2835 driver in Linux 5.4 [1] converts it to use GPIO descriptors, which as a side effect enables SPI_CS_HIGH mode (presumably to avoid a negation somewhere). This change appears to work as expected, but its reliance on the SPI_CS_HIGH bit means that using SPI-Py breaks it in a way which persists after the SPI-Py client application exits. Fix the problem by preserving the upper mode bits. Signed-off-by: Phil Elwell [1] 3bd158c56a56 ("spi: bcm2835: Convert to use CS GPIO descriptors") --- spi.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/spi.c b/spi.c index 2cd4a4a..39d7f42 100644 --- a/spi.c +++ b/spi.c @@ -42,6 +42,7 @@ static PyObject* openSPI(PyObject *self, PyObject *args, PyObject *kwargs) { uint8_t bits = 8; uint32_t speed = 500000; uint16_t delay=0; + uint8_t temp; int ret = 0; int fd; @@ -93,14 +94,19 @@ static PyObject* openSPI(PyObject *self, PyObject *args, PyObject *kwargs) { } // Set mode of SPI device - ret = ioctl(fd, SPI_IOC_WR_MODE, &spi_mode); + ret = ioctl(fd, SPI_IOC_RD_MODE, &temp); if (ret == -1) { - pabort("can't set spi mode"); + pabort("can't get spi mode"); } - - ret = ioctl(fd, SPI_IOC_RD_MODE, &spi_mode); + temp &= ~(SPI_CPHA | SPI_CPOL); + temp |= spi_mode; + ret = ioctl(fd, SPI_IOC_WR_MODE, &temp); if (ret == -1) { - pabort("can't get spi mode"); + pabort("can't set spi mode"); + } + ret = ioctl(fd, SPI_IOC_RD_MODE, &temp); + if (ret == -1 || ((temp & (SPI_CPHA|SPI_CPOL)) != spi_mode)) { + pabort("can't modify spi mode"); } /*