STRUCT SPI_CONTROLLER_MEM_OPS(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’– struct spi_controller_mem_ops β€” SPI memory operations πŸ’–

okay so bestie, this is a page from the Kernel API Manual and it's literally the cheat sheet for struct spi_controller_mem_ops. if you're writing a QSPI controller driver, this is your main character document. let's get into it ✨


πŸŽ€ NAME πŸŽ€

struct spi_controller_mem_ops β€” SPI memory operations


🌸 SYNOPSIS 🌸

struct spi_controller_mem_ops {
    int (*adjust_op_size)(struct spi_mem *mem, struct spi_mem_op *op);
    bool (*supports_op)(struct spi_mem *mem, const struct spi_mem_op *op);
    int (*exec_op)(struct spi_mem *mem, const struct spi_mem_op *op);
    const char *(*get_name)(struct spi_mem *mem);
    int (*dirmap_create)(struct spi_mem_dirmap_desc *desc);
    void (*dirmap_destroy)(struct spi_mem_dirmap_desc *desc);
    ssize_t (*dirmap_read)(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf);
    ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf);
    int (*poll_status)(struct spi_mem *mem, const struct spi_mem_op *op, u16 mask, u16 match, unsigned long initial_delay_us, unsigned long polling_rate_us, unsigned long timeout_ms);
};

like, that's the whole vibe right there. nine function pointers, each one doing its little job 🫢


πŸ’… Members πŸ’…

✨ the function pointers, one by one ✨

  • adjust_op_size β€” this one's job is to shrink the data xfer of an operation so it actually fits what your controller can handle. the limitations in question? could be alignment stuff, could be max RX/TX size stuff. either way, bestie, it's the vibe check for op sizes πŸ’–
  • supports_op β€” the literal question "is this operation supported by the controller?" yes or no, queen πŸ‘‘
  • exec_op β€” executes a SPI memory operation. okay so hear me: not all driver provides supports_op, so this one can return -EOPNOTSUPP if the op isn't supported by the driver/controller. no cap, that's the escape hatch 🫢
  • get_name β€” grabs a custom name for the SPI mem device straight from the controller. why would you need this? because if the controller driver has been ported to use the SPI mem layer and a custom name is used to keep mtdparts compatible, you gotta preserve that name. IMPORTANT NOTE: if your implementation of this function allocates memory dynamically, then it should do so with devm_xxx, because we don't have a ->free_name function 😭 so like, don't leak, bestie πŸ’€
  • dirmap_create β€” creates a direct mapping descriptor that can later be used to access the memory device. this method is optional, so no pressure 🌸
  • dirmap_destroy β€” destroys a memory descriptor previous created by ->dirmap_create. cleanup era 🧹
  • dirmap_read β€” reads data from the memory device using the direct mapping created by ->dirmap_create. okay so the tea here: the function can return less data than requested (for example when the request is crossing the currently mapped area), and in that case the caller of spi_mem_dirmap_read is responsible for calling it again. so it's a "come back, i'm not done" situation πŸ™ˆ
  • dirmap_write β€” writes data to the memory device using the direct mapping created by ->dirmap_create. same deal fr fr: the function can return less data than requested (for example when the request is crossing the currently mapped area), and the caller of spi_mem_dirmap_write is responsible for calling it again in this case. icon behaviour, honestly πŸ’…
  • poll_status β€” polls the memory device status until (status & mask) == match or when the timeout has expired. it fills the data buffer with the last status value. so you always know what the final answer was ⭐

πŸ¦‹ Description πŸ¦‹

so this interface should be implemented by SPI controllers that provide a high-level interface to execute SPI memory operation β€” which is usually the case for QSPI controllers πŸ‘‘

🌈 Note on ->dirmap_{read,write}(): drivers should avoid accessing the direct mapping from the CPU, because doing that can stall the CPU waiting for the SPI mem transaction to finish β€” and that will make real-time maintainers unhappy 😀 and might make your system less reactive. Instead, drivers should use DMA to access this direct mapping. periodt. πŸ’€

like genuinely, don't do the CPU thing. it's giving "why is my system laggy". use DMA, slay, move on 🫢


⭐ SEE ALSO ⭐

Kernel file ./include/linux/spi/spi-mem.h, enum spi_mem_data_dir(9), struct spi_mem_op(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_caps(9), struct spi_mem_driver(9)

go read those next, bestie, they're all connected iykyk πŸ¦‹


and that's the whole page πŸ’– it lives in ./include/linux/spi in the kernel tree, it's part of the Kernel API Manual, and this particular copy is dated October 2026. go forth and write a good QSPI driver, you absolute icon πŸ‘‘βœ¨πŸŽ€

πŸ“¦ where this page comes from