SPI is a synchronous on-board peripheral interface. Its data lines come in four widths: 1 bit (standard Single SPI), 2 bits (Dual SPI), 4 bits (Quad SPI, QSPI), and 8 bits (Octal SPI, OSPI). SPI is therefore a "serial-clock-driven synchronous interface", but the data lines are not necessarily single-bit serial.
The SPI subsystem consists mainly of the following parts:
1. sysfs interface — The Linux SPI subsystem exposes SPI controllers and SPI slave devices, together with some attributes, through sysfs. Under /sys/bus/spi/devices/ you can see the registered SPI master controllers and the devices attached to them, including device names, driver bindings, and device addresses. The relevant sysfs nodes let you check device state, driver binding, and perform some device management.
2. SPI character device nodes — When an SPI device is bound to the spidev driver, the system creates character device nodes under /dev, such as /dev/spidev0.0 and /dev/spidev1.1, corresponding to specific controller and chip-select combinations. User-space programs access these nodes with open(), ioctl(), read(), and write() to exchange data with SPI devices.

# list the SPI devices available in the system
ls /sys/bus/spi/devices/
Expected output:
spi0.0 spi1.0 spi1.1 spi2.0
#spi1.0 = SPI bus 1, chip select 0
# inspect SPI device information
cat /sys/bus/spi/devices/spi0.0/modalias
Expected output:
spi:dh2228fv
spidev_test is the SPI test tool bundled with the Linux kernel, used to verify that SPI communication works.
find . -name "*gcc" | grep bin
Expected output:
./tools/linux/toolchains/arm-gcc12.2.0-linux-uclibceabi/bin/arm-gcc12.2.0_uClibcng1.0.48-linux-uclibceabi-gcc
./tools/linux/toolchains/arm-gcc12.2.0-linux-uclibceabi/bin/arm-gcc12.2.0-linux-uclibceabi-gcc
./tools/linux/toolchains/arm-gcc12.2.0-linux-uclibceabi/bin/arm-gcc12.2.0-linux-uclibceabi-gcc -static ./source/kernel/linux-5.10.y/tools/spi/spidev_test.c -o ./out/spidev_test
The spidev_test executable then appears in the out directory.
file spidev_test
Expected output:
spidev_test: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, with debug_info, not stripped
Tip
It must be a program for a 32-bit ARM Linux system. Any other architecture means the cross compiler was not used.
chmod +x spidev_test
# 5 MHz clock, mode3 (CPOL=1, CPHA=1), 8-bit, internal loopback enabled
./spidev_test -D /dev/spidev0.0 -s 5000000 -d 8 -H -O -l
Expected output:
spi mode: 0x23
bits per word: 8
max speed: 5000000 Hz (5000 kHz)
# 10 MHz clock, mode2 (CPOL=1, CPHA=0), 16-bit, internal loopback enabled
./spidev_test -v -s 10000000 -b 16 -O -I -D /dev/spidev0.0
Expected output:
spi mode: 0x2
bits per word: 16
max speed: 10000000 Hz (10000 kHz)
TX | FF FF FF FF FF FF 40 00 00 00 00 95 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF F0 0D |......@.........................|
RX | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................................|
Tip
Loopback mode (the
-loption) enables the controller's internal loopback: transmitted data is fed straight back to the receiver, which verifies that the SPI controller itself works. Do not enable loopback when communicating with a real peripheral.