SysTutorials

MAX3421E USB Host Driver for Linux Kernel

· updated April 11, 2026

The Linux kernel includes a USB host controller driver for the Maxim MAX3421E chip, which implements a USB 2.0 full-speed and low-speed host controller over SPI. This was introduced in commit 2d53139 by David Mosberger-Tang and is maintained in the kernel’s USB subsystem.

Overview

The MAX3421E is a specialized chip that allows SPI-connected systems to function as USB hosts. Unlike traditional USB controllers that are memory-mapped or use dedicated buses, the MAX3421E communicates entirely through SPI transactions. This makes it useful for embedded systems, microcontrollers, and single-board computers where native USB host support isn’t available.

Key capabilities:

Driver Architecture

The driver (drivers/usb/host/max3421-hcd.c) uses a dedicated kernel thread (max3421_spi_thread) to handle all USB operations. This design is necessary because SPI transactions can sleep, which means they cannot be performed while holding spinlocks or with interrupts disabled.

Threading model:

Register Architecture

The MAX3421E uses a register-based interface. All register access goes through SPI with the format:

[Command Byte] [Optional Data Bytes]

The command byte encodes the register address and direction (read/write). Key registers include:

Packet States and Transfer Flow

The driver models USB transfers as a state machine with three states:

  1. PKT_STATE_SETUP: Control transfers send an 8-byte SETUP packet
  2. PKT_STATE_TRANSFER: Data transfer phase (IN or OUT)
  3. PKT_STATE_TERMINATE: Handshake phase (completing control transfers)

Control transfers always follow: SETUP → TRANSFER (if data exists) → TERMINATE.

Scheduling

The driver implements a two-pass scheduler running once per USB frame:

SCHED_PASS_PERIODIC: Handles interrupt and isochronous endpoints SCHED_PASS_NON_PERIODIC: Handles control and bulk endpoints

This ensures periodic transfers get priority while allowing bulk transfers to use remaining frame bandwidth. Each control endpoint is limited to one transaction per frame.

Error Handling and Retries

The driver maps MAX3421E error codes (HRSL register) to standard Linux error codes:

Toggle bit handling is automatic—the driver reads toggle state from HRSL and saves it per endpoint when switching to a new device.

Configuration and Probe

The driver is registered as an SPI driver and probes compatible SPI devices:

static struct spi_driver max3421_driver = {
    .probe = max3421_probe,
    .remove = max3421_remove,
    .driver = {
        .name = "max3421-hcd",
        .owner = THIS_MODULE,
    },
};

During probe:

  1. Initialize the SPI bus
  2. Create a USB HCD structure
  3. Start the SPI thread
  4. Register the HCD with the USB core
  5. Request the IRQ line (typically low-active)

The probe function validates the chip revision (0x12 or 0x13) and logs SPI configuration details.

Platform Data

The driver accepts platform data for GPIO control:

struct max3421_hcd_platform_data {
    u8 vbus_gpout; /* GPIO pin number (1-8) for VBUS control */
};

The vbus_gpout parameter specifies which MAX3421E GPIO output drives the VBUS power control. This allows automatic power management on the USB port.

SPI Communication

All SPI operations use helper functions to abstract the transaction layer:

These functions handle proper SPI message formatting and use cache-aligned buffers to prevent DMA coherency issues.

Known Limitations

Module Loading

Build as a module with CONFIG_USB_MAX3421_HCD=m or compile in with CONFIG_USB_MAX3421_HCD=y.

modprobe max3421_hcd

The driver requires:

Performance Considerations

SPI communication is the bottleneck. At typical SPI speeds (10-50MHz), full-speed USB performance can be achieved, but latency is higher than native controllers. The SPI thread runs at normal priority and can be preempted, which may cause occasional packet retransmissions under heavy system load.

For applications requiring predictable timing or very high throughput, consider using native USB controllers or dedicated hardware solutions instead of MAX3421E.

← All posts