spi: add spi_msg_t struct and spi_transfer_advanced() api

This commit is contained in:
Vanya A. Sergeev
2025-10-06 02:35:00 -05:00
parent f60ce6b590
commit 5b714afbb8
3 changed files with 62 additions and 0 deletions
+25
View File
@@ -15,6 +15,7 @@ int spi_open_advanced(spi_t *spi, const char *path, unsigned int mode, uint32_t
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_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count);
int spi_close(spi_t *spi);
void spi_free(spi_t *spi);
@@ -108,6 +109,30 @@ Returns 0 on success, or a negative [SPI error code](#return-value) on failure.
------
``` c
typedef struct spi_msg {
const uint8_t *txbuf;
uint8_t *rxbuf;
size_t len;
bool deselect;
uint16_t deselect_delay_us;
uint8_t word_delay_us;
} spi_msg_t;
int spi_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count);
```
Transfer messages, shifting out `len` word counts of the `txbuf` buffer, while shifting in `len` word counts to the `rxbuf` buffer for each message. If `deselect` is true, deselect the device before reselecting it for the following transfer.
`deselect_delay_us` specifies a delay in microseconds before deselection when `deselect` is true. `word_delay_us` specifies a delay in microseconds between words within a transfer. Note that `deselect_delay_us` and `word_delay_us` may not by supported by all SPI controllers and may be silently ignored.
`spi` should be a valid pointer to an SPI handle opened with `spi_open()` or `spi_open_advanced()`.
`rxbuf` may be NULL. `txbuf` and `rxbuf` may point to the same buffer.
Returns 0 on success, or a negative [SPI error code](#return-value) on failure.
------
``` c
int spi_close(spi_t *spi);
```
+26
View File
@@ -18,6 +18,7 @@
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#include <linux/spi/spidev.h>
#include <linux/version.h>
#include "spi.h"
@@ -164,6 +165,31 @@ int spi_transfer(spi_t *spi, const uint8_t *txbuf, uint8_t *rxbuf, size_t len) {
return 0;
}
int spi_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count) {
struct spi_ioc_transfer spi_xfer[count];
/* Prepare SPI transfer structures */
memset(spi_xfer, 0, count * sizeof(struct spi_ioc_transfer));
for (size_t i = 0; i < count; i++) {
spi_xfer[i].tx_buf = (uintptr_t)msgs[i].txbuf;
spi_xfer[i].rx_buf = (uintptr_t)msgs[i].rxbuf;
spi_xfer[i].len = msgs[i].len;
spi_xfer[i].speed_hz = 0;
spi_xfer[i].delay_usecs = msgs[i].deselect_delay_us;
spi_xfer[i].bits_per_word = 0;
spi_xfer[i].cs_change = msgs[i].deselect;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 2, 0)
spi_xfer[i].word_delay_usecs = msgs[i].word_delay_us;
#endif
}
/* Transfer */
if (ioctl(spi->fd, SPI_IOC_MESSAGE(count), spi_xfer) < 0)
return _spi_error(spi, SPI_ERROR_TRANSFER, errno, "SPI transfer");
return 0;
}
int spi_close(spi_t *spi) {
if (spi->fd < 0)
return 0;
+11
View File
@@ -12,6 +12,7 @@ extern "C" {
#endif
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
enum spi_error_code {
@@ -29,6 +30,15 @@ typedef enum spi_bit_order {
LSB_FIRST,
} spi_bit_order_t;
typedef struct spi_msg {
const uint8_t *txbuf;
uint8_t *rxbuf;
size_t len;
bool deselect;
uint16_t deselect_delay_us;
uint8_t word_delay_us;
} spi_msg_t;
typedef struct spi_handle spi_t;
/* Primary Functions */
@@ -42,6 +52,7 @@ 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_transfer_advanced(spi_t *spi, const spi_msg_t *msgs, size_t count);
int spi_close(spi_t *spi);
void spi_free(spi_t *spi);