STRUCT SPI_DEVICE(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… struct spi_device(9) πŸ’…

okay bestie, buckle up β€” this is the struct spi_device page from the Kernel API Manual (yes, struct spi_device(9), we're in kernel-doc land now πŸŽ€) and honestly? she's iconic. this is the controller side proxy for an SPI target device β€” the little struct that stands between your CPU and that one random chip on your board. iykyk. ✨


πŸ¦‹ SYNOPSIS πŸ¦‹

struct spi_device {
    struct device           dev;
    struct spi_controller   *controller;
    u32 max_speed_hz;
    u8 bits_per_word;
    bool rt;
  #define SPI_NO_TX               BIT(31)         ;
  #define SPI_NO_RX               BIT(30)         ;
  #define SPI_TPM_HW_FLOW         BIT(29)         ;
  #define SPI_MODE_KERNEL_MASK    (~(BIT(29) - 1));
    u32 mode;
    int irq;
    void *controller_state;
    void *controller_data;
    char modalias[SPI_NAME_SIZE];
    struct spi_statistics __percpu  *pcpu_statistics;
    struct spi_delay        word_delay;
    struct spi_delay        cs_setup;
    struct spi_delay        cs_hold;
    struct spi_delay        cs_inactive;
    u8 chip_select[SPI_DEVICE_CS_CNT_MAX];
    u8 num_chipselect;
    u32 cs_index_mask : SPI_DEVICE_CS_CNT_MAX;
    struct gpio_desc        *cs_gpiod[SPI_DEVICE_CS_CNT_MAX];
    u8 tx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
    u8 num_tx_lanes;
    u8 rx_lane_map[SPI_DEVICE_DATA_LANE_CNT_MAX];
    u8 num_rx_lanes;
  #if IS_ENABLED(CONFIG_SPI_DYNAMIC);
    struct list_head        userspace_node;
  #endif;
 };

literally just look at her. gorgeous. no notes. πŸ’œ


🌸 Members 🌸

  • dev β€” the driver model representation of the device. her official government name. 🫢
  • controller β€” the SPI controller this device is hanging out with.
  • max_speed_hz β€” the maximum clock rate to be used with this chip (on this board) β€” and yes, the device's driver can change it later. also, spi_transfer.speed_hz can override this for each individual transfer. so she's flexible πŸ’…
  • bits_per_word β€” so data transfers involve one or more words, and word sizes like eight or 12 bits are common. but plot twist: in-memory wordsizes are powers of two bytes (e.g. 20 bit samples use 32 bits β€” the way that works is genuinely so cool). the device's driver may change this, or you can leave it at the default (0), which means protocol words are eight bit bytes. and spi_transfer.bits_per_word can override this for each transfer too. override queen. πŸ‘‘
  • rt β€” makes the pump thread real time priority. real time. she's got main character energy scheduling-wise. πŸ”₯
  • mode β€” the spi mode defines how data is clocked out and in. the device's driver may change this. the "active low" default for chipselect mode can be overridden (by specifying SPI_CS_HIGH), and so can the "MSB first" default for each word in a transfer (by specifying SPI_LSB_FIRST). defaults are cute but options are cuter ✨
  • irq β€” negative, or the number passed to request_irq to receive interrupts from this device.
  • controller_state β€” the controller's runtime state.
  • controller_data β€” board-specific definitions for the controller, like FIFO initialization parameters ✨ fr fr board-specific ✨ β€” comes from board_info.controller_data.
  • modalias β€” the name of the driver to use with this device, or an alias for that name. this shows up in the sysfs "modalias" attribute for driver coldplugging, and in uevents used for hotplugging. she's everywhere, she's booked and busy πŸ’€
  • pcpu_statistics β€” statistics for the spi_device.
  • word_delay β€” delay to be inserted between consecutive words of a transfer.
  • cs_setup β€” delay to be introduced by the controller after CS is asserted.
  • cs_hold β€” delay to be introduced by the controller before CS is deasserted.
  • cs_inactive β€” delay to be introduced by the controller after CS is deasserted. ⚠️ and heads up: if cs_change_delay is used from spi_transfer, then the two delays will be added up. math is mathing 😭
  • chip_select β€” array of physical chipselect; spi->chipselect[i] gives the corresponding physical CS for logical CS i. indexing, but make it hardware πŸŽ€
  • num_chipselect β€” number of physical chipselects used.
  • cs_index_mask β€” bit mask of the active chipselect(s) in the chipselect array.
  • cs_gpiod β€” array of GPIO descriptors of the corresponding chipselect lines (optional, NULL when not using a GPIO line). no cap, she can be null. πŸ™ˆ
  • tx_lane_map β€” map of peripheral lanes (index) to controller lanes (value).
  • num_tx_lanes β€” number of transmit lanes wired up.
  • rx_lane_map β€” map of peripheral lanes (index) to controller lanes (value). yes bestie, same description as tx, she's symmetrical like that πŸ¦‹
  • num_rx_lanes β€” number of receive lanes wired up.
  • userspace_node β€” entry on the parent controller's userspace_clients list when this device was instantiated via the sysfs new_device interface. only exists under #if IS_ENABLED(CONFIG_SPI_DYNAMIC) β€” conditional icon πŸ’…

✨ Description ✨

so a spi_device is used to interchange data between an SPI target device (usually a discrete chip β€” like, a literal physical chip on your board) and CPU memory. that's the whole job. that's the vibe check. 🌈

inside dev, the platform_data is used to hold information about this device that's meaningful to the device's protocol driver, but not to its controller. one example might be an identifier for a chip variant with slightly different functionality; another might be information about how this particular board wires the chip's pins. it's giving "context that only matters to the diva who's actually driving." πŸ’–


πŸ”₯ SEE ALSO πŸ”₯

kernel file ./include/linux/spi/spi.h, plus the whole friend group: struct spi_statistics(9), struct spi_delay(9), struct spi_driver(9), spi_unregister_driver(9), module_spi_driver(9), struct spi_controller(9), struct spi_res(9), struct spi_transfer(9), struct spi_message(9), spi_message_init_with_transfers(9), spi_is_bpw_supported(9), spi_bpw_to_bytes(9), spi_controller_xfer_timeout(9), struct spi_replaced_transfers(9), spi_sync_transfer(9), spi_write(9), spi_read(9), spi_w8r8(9), spi_w8r16(9), spi_w8r16be(9), struct spi_board_info(9) β€” bestie really said "you will read the whole squad." 🫢


that's the page fr fr πŸ’œ this beauty lives over in ./include/linux/spi and she's dated October 2026 β€” struct spi_device(9), slay, go forth and talk to your chips βœ¨πŸŽ€πŸ¦‹

πŸ“¦ where this page comes from