diff --git a/docs/spi.md b/docs/spi.md index 243bf25..5986621 100644 --- a/docs/spi.md +++ b/docs/spi.md @@ -12,6 +12,8 @@ spi_t *spi_new(void); int spi_open(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed); int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint8_t extra_flags); +int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, + spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags); int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len); int spi_close(spi_t *spi); void spi_free(spi_t *spi); @@ -81,6 +83,18 @@ Returns 0 on success, or a negative [SPI error code](#return-value) on failure. ------ +``` c +int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, + spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags); +``` +Open the `spidev` device at the specified path, with the specified SPI mode, max speed in hertz, bit order, bits per word, and extra flags. This open function is the same as `spi_open_advanced()`, except that `extra_flags` can be 32-bits. + +`spi` should be a valid pointer to an allocated SPI handle structure. SPI mode can be 0, 1, 2, or 3. Bit order can be `MSB_FIRST` or `LSB_FIRST`, as defined [above](#enumerations). Bits per word specifies the transfer word size. Extra flags specified additional flags bitwise-ORed with the SPI mode. + +Returns 0 on success, or a negative [SPI error code](#return-value) on failure. + +------ + ``` c int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len); ``` diff --git a/src/spi.c b/src/spi.c index c7ccfa4..2e1c07f 100644 --- a/src/spi.c +++ b/src/spi.c @@ -68,6 +68,11 @@ int spi_open(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed } int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint8_t extra_flags) { + return spi_open_advanced2(spi, path, mode, max_speed, bit_order, bits_per_word, extra_flags); +} + +int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint32_t extra_flags) { + uint32_t data32; uint8_t data8; /* Validate arguments */ @@ -75,6 +80,10 @@ int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid mode (can be 0,1,2,3)"); if (bit_order != MSB_FIRST && bit_order != LSB_FIRST) return _spi_error(spi, SPI_ERROR_ARG, 0, "Invalid bit order (can be MSB_FIRST,LSB_FIRST)"); +#ifndef SPI_IOC_WR_MODE32 + if (extra_flags > 0xff) + return _spi_error(spi, SPI_ERROR_UNSUPPORTED, "Kernel version does not support 32-bit SPI mode flags"); +#endif memset(spi, 0, sizeof(spi_t)); @@ -83,6 +92,7 @@ int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t return _spi_error(spi, SPI_ERROR_OPEN, errno, "Opening SPI device \"%s\"", path); /* Set mode, bit order, extra flags */ +#ifndef SPI_IOC_WR_MODE32 data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags; if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) { int errsv = errno; @@ -90,6 +100,28 @@ int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t spi->fd = -1; return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode"); } +#else + if (extra_flags > 0xff) { + /* Use 32-bit mode if extra_flags is wider than 8-bits */ + data32 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags; + if (ioctl(spi->fd, SPI_IOC_WR_MODE32, &data32) < 0) { + int errsv = errno; + close(spi->fd); + spi->fd = -1; + return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode"); + } + } else { + /* Prefer 8-bit mode, in case this library is inadvertently used on an + * older kernel. */ + data8 = mode | ((bit_order == LSB_FIRST) ? SPI_LSB_FIRST : 0) | extra_flags; + if (ioctl(spi->fd, SPI_IOC_WR_MODE, &data8) < 0) { + int errsv = errno; + close(spi->fd); + spi->fd = -1; + return _spi_error(spi, SPI_ERROR_CONFIGURE, errsv, "Setting SPI mode"); + } + } +#endif /* Set max speed */ if (ioctl(spi->fd, SPI_IOC_WR_MAX_SPEED_HZ, &max_speed) < 0) { diff --git a/src/spi.h b/src/spi.h index 2b66ad4..979d4ce 100644 --- a/src/spi.h +++ b/src/spi.h @@ -38,6 +38,9 @@ int spi_open(spi_t *spi, const char *path, unsigned int mode, int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t max_speed, spi_bit_order_t bit_order, uint8_t bits_per_word, uint8_t extra_flags); +int spi_open_advanced2(spi_t *spi, const char *path, unsigned int mode, + uint32_t max_speed, spi_bit_order_t bit_order, + uint8_t bits_per_word, uint32_t extra_flags); int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len); int spi_close(spi_t *spi); void spi_free(spi_t *spi);