Comprehensive Guide to spidev Driver ioctl Commands: Beyond SPI_IOC_MESSAGE
The Linux spidev driver provides a versatile ioctl interface for configuring SPI devices and controlling data transfers. While SPI_IOC_MESSAGE handles data transactions, other ioctl commands manage critical settings like SPI mode, clock speed, and hardware-specific behaviors. This article explores all ioctl commands supported by spidev, detailing their user-space usage, kernel-space handling, and impact on hardware.
1. Overview of spidev ioctl Commands
The spidev driver supports the following ioctl commands, grouped by functionality:
2. General ioctl Dispatch Mechanism
Kernel-Space Workflow
User-space calls ioctl(fd, cmd, arg), which triggers a transition to kernel mode.
The kernel’s VFS layer maps the fd to the spidev driver’s file_operations structure.
The spidev_ioctl function is invoked (drivers/spi/spidev.c).
Read Commands (e.g., SPI_IOC_RD_MODE): Copy data from kernel to user space.
Write Commands (e.g., SPI_IOC_WR_MODE): Copy data from user to kernel space.
The driver updates the struct spi_device’s settings (e.g., spi->mode, spi->max_speed_hz). Changes are propagated to the SPI controller driver (e.g., spi-bcm2835).
3. Detailed Command Breakdown
3.1 SPI Mode Configuration (SPI_IOC_RD_MODE, SPI_IOC_WR_MODE)
Purpose: Set CPOL (clock polarity) and CPHA (clock phase). User-Space Example:
uint8_t mode;
ioctl(fd, SPI_IOC_RD_MODE, &mode); // Read current mode
mode |= SPI_MODE_3; // Set CPOL=1, CPHA=1
ioctl(fd, SPI_IOC_WR_MODE, &mode); // Apply new mode
Kernel Handling:
Note: SPI_IOC_RD_MODE32/SPI_IOC_WR_MODE32 handle 32-bit mode flags for exotic controllers.
3.2 Bits per Word (SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD)
Purpose: Set the number of bits per SPI word (e.g., 8, 16). User-Space Example:
uint8_t bits = 16;
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
Kernel Handling:
Error Case: Returns -EINVAL if the controller doesn’t support the requested bits.
3.3 Clock Speed (SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ)
Purpose: Set the SPI clock frequency (Hz). User-Space Example:
uint32_t speed = 1000000; // 1 MHz
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
Kernel Handling:
Note: Actual speed may differ if the controller can’t match the exact value.
Recommended by LinkedIn
3.4 Data Order (SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST)
Purpose: Transmit data LSB-first (default: MSB-first). User-Space Example:
uint8_t lsb = 1;
ioctl(fd, SPI_IOC_WR_LSB_FIRST, &lsb);
Kernel Handling:
3.5 Loopback Mode (SPI_IOC_RD_LOOP, SPI_IOC_WR_LOOP)
Purpose: Echo transmitted data to the receive buffer (for debugging). User-Space Example:
uint8_t loop = 1;
ioctl(fd, SPI_IOC_WR_LOOP, &loop);
Kernel Handling:
3.6 Chip Select Configuration
User-Space Example:
uint8_t cs_high = 1;
ioctl(fd, SPI_IOC_WR_CS_HIGH, &cs_high);
3.7 3-Wire Mode (SPI_IOC_RD_3WIRE, SPI_IOC_WR_3WIRE)
Purpose: Enable half-duplex mode with a shared MISO/MOSI line. Kernel Handling:
3.8 Number of Bits (SPI_IOC_RD_NBITS, SPI_IOC_WR_NBITS)
Purpose: Set non-byte-aligned transfer sizes (e.g., 12 bits). User-Space Example:
uint8_t nbits = 12;
ioctl(fd, SPI_IOC_WR_NBITS, &nbits);
Note: Rarely used; requires controller support.
4. Error Handling and Common Issues
5. Example: Full SPI Configuration
User-Space Code:
int fd = open("/dev/spidev0.0", O_RDWR);
// Set mode to SPI_MODE_3 (CPOL=1, CPHA=1)
uint8_t mode = SPI_MODE_3;
ioctl(fd, SPI_IOC_WR_MODE, &mode);
// Set 8 bits per word
uint8_t bits = 8;
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
// Set clock speed to 1 MHz
uint32_t speed = 1000000;
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
// Perform transfer
struct spi_ioc_transfer tr = { ... };
ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
Kernel Flow:
6. Conclusion
The spidev driver’s ioctl interface provides fine-grained control over SPI hardware, enabling developers to optimize performance and compatibility. By understanding how each command configures the kernel’s SPI subsystem and interacts with controller drivers, you can debug complex issues and tailor SPI behavior to your application’s needs. Whether adjusting clock speeds for sensor compatibility or enabling loopback for testing, these commands form the backbone of Linux’s SPI user-space support.