SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync(). Pass it an array of related transfers, they'll execute together. Each transfer may be half duplex (either direction) or full duplex. So for example one transfer might send a nine bit command (right aligned in a 16-bit word), the next could read a block of 8-bit data before terminating that command by temporarily deselecting the chip; the next could send a different nine bit command (re-selecting the chip), and the last transfer might write some register values.
This means that in principle you could have an array of
struct spi_ioc_transfer each of which should be set up to be 4096 long and then you'd change the length parameter in the
struct spi_ioc_transfer transactions[x];
// .... fill in the structs .... then
ioctl(fd, SPI_IOC_MESSAGE(x), transactions); // notice the `x` here instead of 1.
Elsewhere (https://www.kernel.org/doc/html/latest/spi/spidev.html) they say
There’s a limit on the number of bytes each I/O request can transfer to the SPI device. It defaults to one page, but that can be changed using a module parameter.
modinfo spidev shows that the relevant parameter is:
parm: bufsiz:data bytes in biggest supported SPI message (uint)
so you can do:
modprobe -r spidev # remove module
modprobe spidev bufsiz=65536 # add module with custom parameter
The output of this command should confirm it worked:
At this point, try with larger transfers. If it works OK, then you can make this change permanent by creating the file
/etc/modprobe.d/local.conf and adding to it the following line:
options spidev bufsiz=65536
By the way, I don't think you will see a noticeable difference in CPU usage between the two options, however under heavy CPU load (e.g.: from the audio thread), the second option should produce marginally faster transfers as it only needs the CPU once per transfer.