STRUCT SPI_MEM_OP(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’… struct spi_mem_op(9) β€” the Kernel API Manual, but make it make sense ✨

okay bestie, so you know how the kernel talks to SPI memory chips (think flash, like the little storage goblin on your board)? This struct is literally the whole conversation plan πŸ’–. It's struct spi_mem_op β€” one (1) complete SPI memory operation, wrapped up in a cute little package: the command, the address, the dummy phase, and the data phase. All four acts of the show, main character energy only πŸ‘‘.

It lives in the Kernel API Manual, iykyk 🧚


🌸 SYNOPSIS 🌸

struct spi_mem_op {
    struct {
      u8 nbytes;
      u8 buswidth;
      u8 dtr : 1;
      u8 __pad : 7;
      u16 opcode;
    } cmd;
    struct {
      u8 nbytes;
      u8 buswidth;
      u8 dtr : 1;
      u8 __pad : 7;
      u64 val;
    } addr;
    struct {
      u8 nbytes;
      u8 buswidth;
      u8 dtr : 1;
      u8 __pad : 7;
    } dummy;
    struct {
      u8 buswidth;
      u8 dtr : 1;
      u8 ecc : 1;
      u8 swap16 : 1;
      u8 __pad : 5;
      enum spi_mem_data_dir dir;
      unsigned int nbytes;
      union {
        void *in;
        const void *out;
      } buf;
    } data;
    unsigned int max_freq;
 };

like, look at her. four nested structs and a frequency cap. iconic πŸŽ€


πŸ¦‹ MEMBERS πŸ¦‹

so let's go through every single one, no skipping, we are NOT leaving anyone out of the group chat πŸ’…

🌈 the command block

  • cmd β€” the complete command. the whole vibe of "what are we even doing here" 🫢
  • cmd.nbytes β€” number of opcode bytes. and listen: only 1 or 2 are valid ⚠️. the opcode is sent MSB-first.
  • cmd.buswidth β€” number of IO lines used to transmit the command. how many lanes we're taking, basically πŸ›£οΈ
  • cmd.dtr β€” whether the command opcode should be sent in DTR mode or not. yes/no, that's the whole bit πŸͺ©
  • cmd.opcode β€” the operation opcode. the actual thing we're asking for, bestie.

🌟 the address block

  • addr β€” the address attributes.
  • addr.nbytes β€” number of address bytes to send. can be zero if the operation does not need to send an address. zero is a valid slay πŸ™ˆ
  • addr.buswidth β€” number of IO lines used to transmit the address cycles.
  • addr.dtr β€” whether the address should be sent in DTR mode or not.
  • addr.val β€” the address value. this value is always sent MSB first on the bus. and note this note: only addr.nbytes are taken into account in this address value β€” so users should make sure the value fits in the assigned number of bytes. like, if it doesn't fit, that's on you, not on the struct πŸ’€

🧚 the dummy block

  • dummy β€” data for dummy operation. yes she's called dummy and yes she matters πŸ’œ
  • dummy.nbytes β€” number of dummy bytes to send after an opcode or address. can be zero if the operation does not require dummy bytes.
  • dummy.buswidth β€” number of IO lanes used to transmit the dummy bytes.
  • dummy.dtr β€” whether the dummy bytes should be sent in DTR mode or not.

πŸ“ the data block

  • data β€” the data attributes.
  • data.buswidth β€” number of IO lanes used to send/receive the data.
  • data.dtr β€” whether the data should be sent in DTR mode or not.
  • data.ecc β€” whether error correction is required or not.
  • data.swap16 β€” whether the byte order of 16-bit words is swapped when read or written in Octal DTR mode compared to STR mode. yes that's the whole sentence, yes it's a lot, yes it's important 🌸
  • data.dir β€” direction of the transfer. which way the data's flowing, bestie βž‘οΈβ¬…οΈ
  • data.nbytes β€” number of data bytes to send/receive. can be zero if the operation does not involve transferring data.
  • data.buf.in β€” input buffer (must be DMA-able). must be DMA-able!! say it with me πŸ“£
  • data.buf.out β€” output buffer (must be DMA-able). also DMA-able, no exceptions 🫢

⭐ the frequency one

  • max_freq β€” frequency limitation wrt this operation. 0 means there is no specific constraint and the highest achievable frequency can be attempted. zero = go fast, no cap πŸ”₯

πŸ‘‘ SEE ALSO πŸ‘‘

go read these next, they're all in the Kernel file ./include/linux/spi/spi-mem.h:

  • enum spi_mem_data_dir(9)
  • struct spi_mem_dirmap_info(9)
  • struct spi_mem_dirmap_desc(9)
  • struct spi_mem(9)
  • spi_mem_set_drvdata(9)
  • spi_mem_get_drvdata(9)
  • struct spi_controller_mem_ops(9)
  • struct spi_controller_mem_caps(9)
  • struct spi_mem_driver(9)

like, the whole friend group πŸ’–


quick vibe check: data.buf.in and data.buf.out are a union β€” you get one or the other, not both. and both have to be DMA-able. don't come crying to me if you forget 😭

that's the page, bestie! πŸŽ€ this one came from ./include/linux/spi and it's dated October 2026 β€” and the struct spi_mem_op(9) girlies stay winning, periodt πŸ’…βœ¨πŸ¦‹

πŸ“¦ where this page comes from