‹ archive

kernel

The SPI Bus

The four-wire model

SPI is a synchronous, full-duplex, master/slave serial bus. Motorola defined it in the 1980s and it never went away. Four signals carry the whole protocol. SCLK is the clock, and only the controller drives it. MOSI carries bits from the controller out to the peripheral. MISO carries bits the other way, from the peripheral back to the controller. CS, the chip select (also called slave select, SS), is an active-low line that picks which peripheral is listening.

Because there is a dedicated wire for each direction, transfer is inherently full-duplex. On every clock edge a bit leaves on MOSI and a bit arrives on MISO at the same instant. There is no addressing scheme on the wire and no acknowledgement bit; SPI trades the cleverness of I2C for raw speed and simplicity. Standard implementations run from roughly 10 to 50 Mbit/s, and JEDEC NOR-flash variants push much higher with dual and octal lanes. The cost of that simplicity is pin count: every extra peripheral wants its own CS line.

Clock polarity and phase

Two parameters decide exactly when bits are valid, and both ends must agree. CPOL, the clock polarity, sets the idle level of SCLK: CPOL=0 idles low, CPOL=1 idles high. CPHA, the clock phase, sets which edge samples data: CPHA=0 latches on the leading edge, CPHA=1 latches on the trailing edge. The other edge is when the line is allowed to change.

Get the mode wrong and the bus does not fail loudly. The code runs, the clock toggles, and the peripheral returns plausible-looking garbage. Many datasheets never print a mode number; they show a timing diagram instead, and the burden is on the reader to translate the rising and falling edges into a CPOL and CPHA. Worse, edge language is slippery. "First edge" and "leading edge" are relative to the idle level, while "rising" and "falling" are absolute. The two descriptions only line up once you anchor them to CPOL. This is the single most common SPI bring-up bug.

The four SPI modes

The mode number is just the two bits read together, CPOL high and CPHA low. Mode 0 is CPOL=0, CPHA=0: clock idles low, data sampled on the rising edge, shifted on the falling edge. Mode 1 is CPOL=0, CPHA=1: idles low, sampled on the falling edge. Mode 2 is CPOL=1, CPHA=0: idles high, sampled on the falling edge. Mode 3 is CPOL=1, CPHA=1: idles high, sampled on the rising edge.

In practice the field is not flat. Mode 0 and mode 3 dominate; the kernel's own spi-summary notes those two are the most commonly used. A useful detail for debugging: in mode 0 and mode 2, where CPHA=0, the first data bit must already be present on the line before the first clock edge arrives, because that leading edge samples it. Modes with CPHA=1 give the peripheral one half-clock of setup time after CS asserts, which some slow parts prefer. None of this matters until controller and peripheral disagree; then it is the only thing that matters.

Chip select, topology, and daisy chains

The usual multi-peripheral wiring shares SCLK, MOSI, and MISO across every device and gives each one its own CS line. Only one CS is asserted at a time. Unselected peripherals must release MISO into high impedance, which is why their MISO pins are required to be tri-state; otherwise two parts would fight over the same wire. With N peripherals you need N chip selects, and pin pressure is real on small controllers.

Daisy-chaining is the alternative. The peripherals are strung together so the MISO of one feeds the MOSI of the next, forming one long shift register under a single shared CS. The controller clocks enough bits to push data through the whole chain, then latches all parts at once. It saves chip-select pins at the cost of latency and software bookkeeping, and only works with parts that document chained operation. Some devices instead drop a wire entirely, merging MOSI and MISO into a single bidirectional data line; that is half-duplex three-wire SPI (SCK, data, nCS), distinct from the full-duplex four-wire norm.

Why displays, sensors, and flash use SPI

SPI shows up wherever a device wants a fast, cheap, point-to-point link and does not need many masters. Displays are a clear case: pushing a framebuffer is mostly one-directional, high-volume writes, and SPI's full-duplex clocking handles that at tens of megabits without protocol overhead. Many small panel controllers, including the ILI9341 class of TFT drivers, speak SPI with a separate data/command GPIO alongside the bus.

Sensors like it because a transaction is often just "send a register address, read back the value," which the full-duplex model does in one exchange. NOR flash uses SPI because the chip count is low and throughput matters; the dual and octal QSPI variants exist precisely to keep flash fast. The tradeoffs are honest. SPI has no built-in flow control, no error checking, and no standard for sharing the bus among multiple controllers. What it offers is determinism and speed on a short board-level link, which is exactly what these three device classes want.

Binding a Linux SPI driver

Linux splits SPI into two driver kinds. A controller driver manages the host hardware and exposes it as a struct spi_controller; a protocol driver speaks to one peripheral and registers as a struct spi_driver with probe() and remove() callbacks. Each peripheral on the bus is represented by a struct spi_device, the controller-side proxy that holds the mode, bits-per-word, and max clock speed for that part. Binding happens by matching: the kernel compares a device's modalias, usually filled from a device-tree compatible string or an of_device_id table, against registered drivers and calls probe() on a hit.

Data moves through two paired structures. A struct spi_transfer is one full-duplex segment with optional tx_buf and rx_buf pointers; a struct spi_message chains several transfers that run atomically so no other device interrupts the sequence. Drivers submit with spi_sync(), which blocks until done and is the common path, or spi_async(), which queues the message and fires a completion callback. The documentation has shifted from master/slave toward controller/peripheral (and controller/target) wording, though the older struct field names linger.

DMA and the Rust-for-Linux picture

For large transfers the controller can use DMA so the CPU does not copy every word. A controller driver advertises this through a can_dma() callback, and the SPI core maps the transfer buffers into tx_sg and rx_sg scatterlists for it. The catch is that DMA buffers must live in DMA-safe memory; a buffer on the kernel stack is not safe to hand to a DMA engine, so drivers allocate transfer buffers from an appropriate pool. For repeated identical messages, spi_optimize_message() does the validation and setup once and spi_unoptimize_message() releases it.

Rust-for-Linux is where this gets current. Rust support in the kernel was merged in v6.1, and at the 2025 Maintainers Summit the "Rust experiment" was formally declared a success and concluded, per reporting from Phoronix. Most Rust work lives in drivers and the abstraction layers that let a Rust driver call a C subsystem safely. A safe SPI abstraction has been worked on since at least Kangrejos 2021, originally targeting an arm64 device driver. As far as is documented in mid-2026, a fully merged in-tree kernel::spi abstraction with stable spi::Driver and spi::Device types is still in progress rather than settled mainline; the authoritative status lives on the rust-for-linux tree and the linux-spi list.

defines

references

all external links are collected at the reference desk.

ask the oracle about this ›

source/ Synthesized from kernel.org SPI driver-api and spi-summary docs, Analog Devices 'Introduction to SPI', Wikipedia SPI, and Rust-for-Linux status reporting (Phoronix, Kangrejos 2021) as of June 2026.