STRUCT SPI_CONTROLLER(9)
π struct spi_controller(9) π
ok so bestie, welcome to the Kernel API Manual β this is the page for struct spi_controller, and it's a big one, so buckle up π
β¨ NAME β¨
struct spi_controller β the interface to an SPI host or target controller π¦
like, this is the struct. the main character. the one that runs the whole SPI show π
β¨ SYNOPSIS β¨
bestie. sit down. get a snack. this struct is LONG and we are going to look at every single field because nothing gets skipped on my watch π
struct spi_controller {
struct device dev;
struct list_head list;
s16 bus_num;
u16 num_chipselect;
u16 num_data_lanes;
u16 dma_alignment;
u32 mode_bits;
u32 buswidth_override_bits;
u32 bits_per_word_mask;
#define SPI_BPW_MASK(bits) BIT((bits) - 1);
#define SPI_BPW_RANGE_MASK(min, max) GENMASK((max) - 1, (min) - 1);
u32 min_speed_hz;
u32 max_speed_hz;
u16 flags;
#define SPI_CONTROLLER_HALF_DUPLEX BIT(0) ;
#define SPI_CONTROLLER_NO_RX BIT(1) ;
#define SPI_CONTROLLER_NO_TX BIT(2) ;
#define SPI_CONTROLLER_MUST_RX BIT(3) ;
#define SPI_CONTROLLER_MUST_TX BIT(4) ;
#define SPI_CONTROLLER_GPIO_SS BIT(5) ;
#define SPI_CONTROLLER_SUSPENDED BIT(6) ;
#define SPI_CONTROLLER_MULTI_CS BIT(7);
union {
bool slave;
bool target;
};
size_t (*max_transfer_size)(struct spi_device *spi);
size_t (*max_message_size)(struct spi_device *spi);
struct mutex io_mutex;
struct mutex add_lock;
spinlock_t bus_lock_spinlock;
struct mutex bus_lock_mutex;
bool bus_lock_flag;
int (*setup)(struct spi_device *spi);
int (*set_cs_timing)(struct spi_device *spi);
int (*transfer)(struct spi_device *spi, struct spi_message *mesg);
void (*cleanup)(struct spi_device *spi);
bool (*can_dma)(struct spi_controller *ctlr, struct spi_device *spi,
struct spi_transfer *xfer);
struct device *dma_map_dev;
struct device *cur_rx_dma_dev;
struct device *cur_tx_dma_dev;
bool queued;
struct kthread_worker *kworker;
struct kthread_work pump_messages;
spinlock_t queue_lock;
struct list_head queue;
struct spi_message *cur_msg;
struct completion cur_msg_completion;
bool cur_msg_incomplete;
bool cur_msg_need_completion;
bool busy;
bool running;
bool rt;
bool auto_runtime_pm;
bool fallback;
bool last_cs_mode_high;
s8 last_cs[SPI_DEVICE_CS_CNT_MAX];
u32 last_cs_index_mask : SPI_DEVICE_CS_CNT_MAX;
struct completion xfer_completion;
size_t max_dma_len;
int (*optimize_message)(struct spi_message *msg);
int (*unoptimize_message)(struct spi_message *msg);
int (*prepare_transfer_hardware)(struct spi_controller *ctlr);
int (*transfer_one_message)(struct spi_controller *ctlr, struct
spi_message *mesg);
int (*unprepare_transfer_hardware)(struct spi_controller *ctlr);
int (*prepare_message)(struct spi_controller *ctlr, struct
spi_message *message);
int (*unprepare_message)(struct spi_controller *ctlr, struct
spi_message *message);
int (*target_abort)(struct spi_controller *ctlr);
void (*set_cs)(struct spi_device *spi, bool enable);
int (*transfer_one)(struct spi_controller *ctlr, struct spi_device
*spi, struct spi_transfer *transfer);
void (*handle_err)(struct spi_controller *ctlr, struct spi_message
*message);
const struct spi_controller_mem_ops *mem_ops;
const struct spi_controller_mem_caps *mem_caps;
bool dtr_caps;
struct spi_offload *(*get_offload)(struct spi_device *spi, const
struct spi_offload_config *config);
void (*put_offload)(struct spi_offload *offload);
struct gpio_desc **cs_gpiods;
bool use_gpio_descriptors;
s8 unused_native_cs;
s8 max_native_cs;
struct spi_statistics __percpu *pcpu_statistics;
struct dma_chan *dma_tx;
struct dma_chan *dma_rx;
void *dummy_rx;
void *dummy_tx;
int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
bool ptp_sts_supported;
unsigned long irq_flags;
bool queue_empty;
bool must_async;
bool defer_optimize_message;
#if IS_ENABLED(CONFIG_SPI_DYNAMIC);
struct list_head userspace_clients;
bool userspace_registered;
#endif;
};
bestie I know π that's a lot of fields. but we're not even done β the descriptions are coming in the next part, and there is so much to say about every single one of these. no cap, not one field gets left behind ππ
so yeah. keep your scroll finger warm. π«Ά
π Members π
okay so this struct is packed, bestie β every field of it, right here, no skips, no "you get the idea" π
devβ the device interface to this driver.listβ link with the globalspi_controllerlist.bus_numβ board-specific (and often SOC-specific) identifier for a given SPI controller.num_chipselectβ chipselects are used to distinguish individual SPI targets, and are numbered from zero tonum_chipselects. each target has a chipselect signal, but it's common that not every chipselect is connected to a target.num_data_lanesβ Number of data lanes supported by this controller. Default is1.dma_alignmentβ SPI controller constraint on DMA buffers alignment.mode_bitsβ flags understood by this controller driver.buswidth_override_bitsβ flags to override for this controller driver.bits_per_word_maskβ A mask indicating which values ofbits_per_wordare supported by the driver. Bit n indicates that abits_per_wordn+1 is supported. If set, the SPI core will reject any transfer with an unsupportedbits_per_word. If not set, this value is simply ignored, and it's up to the individual driver to perform any validation.min_speed_hzβ Lowest supported transfer speed.max_speed_hzβ Highest supported transfer speed.flagsβ other constraints relevant to this driver.{unnamed_union}β anonymous.slaveβ indicates that this is an SPI slave controller.targetβ indicates that this is an SPI target controller.max_transfer_sizeβ function that returns the max transfer size for aspi_device; may beNULL, so the defaultSIZE_MAXwill be used.max_message_sizeβ function that returns the max message size for aspi_device; may beNULL, so the defaultSIZE_MAXwill be used.io_mutexβ mutex for physical bus access.add_lockβ mutex to avoid adding devices to the same chipselect.bus_lock_spinlockβ spinlock for SPI bus locking.bus_lock_mutexβ mutex for exclusion of multiple callers.bus_lock_flagβ indicates that the SPI bus is locked for exclusive use.setupβ updates the device mode and clocking records used by a device's SPI controller; protocol code may call this. This must fail if an unrecognized or unsupported mode is requested. It's always safe to call this unless transfers are pending on the device whose settings are being modified.set_cs_timingβ optional hook for SPI devices to request SPI controller for configuring specific CS setup time, hold time and inactive delay in terms of clock counts.transferβ adds a message to the controller's transfer queue.cleanupβ frees controller-specific state.can_dmaβ determine whether this controller supports DMA.dma_map_devβ device which can be used for DMA mapping.cur_rx_dma_devβ device which is currently used for RX DMA mapping.cur_tx_dma_devβ device which is currently used for TX DMA mapping.queuedβ whether this controller is providing an internal message queue.kworkerβ pointer to thread struct for message pump.pump_messagesβ work struct for scheduling work to the message pump.queue_lockβ spinlock to synchronise access to message queue.queueβ message queue.cur_msgβ the currently in-flight message.cur_msg_completionβ a completion for the current in-flight message.cur_msg_incompleteβ Flag used internally to opportunistically skip thecur_msg_completion. This flag is used to check if the driver has already calledspi_finalize_current_message.cur_msg_need_completionβ Flag used internally to opportunistically skip thecur_msg_completion. This flag is used to signal the context that is runningspi_finalize_current_messagethat it needs to complete.busyβ message pump is busy.runningβ message pump is running.rtβ whether this queue is set to run as a realtime task.auto_runtime_pmβ the core should ensure a runtime PM reference is held while the hardware is prepared, using the parent device for the spidev.fallbackβ fallback to PIO if DMA transfer return failure withSPI_TRANS_FAIL_NO_START.last_cs_mode_highβ was (mode & SPI_CS_HIGH) true on the last call toset_cs.last_csβ the lastchip_selectthat is recorded byset_cs,-1on non chip selected.last_cs_index_maskβ bit mask the last chip selects that were used.xfer_completionβ used by coretransfer_one_message.max_dma_lenβ Maximum length of a DMA transfer for the device.optimize_messageβ optimize the message for reuse.unoptimize_messageβ release resources allocated byoptimize_message.prepare_transfer_hardwareβ a message will soon arrive from the queue so the subsystem requests the driver to prepare the transfer hardware by issuing this call.transfer_one_messageβ the subsystem calls the driver to transfer a single message while queuing transfers that arrive in the meantime. When the driver is finished with this message, it must callspi_finalize_current_messageso the subsystem can issue the next message.unprepare_transfer_hardwareβ there are currently no more messages on the queue so the subsystem notifies the driver that it may relax the hardware by issuing this call.prepare_messageβ set up the controller to transfer a single message, for example doing DMA mapping. Called from threaded context.unprepare_messageβ undo any work done byprepare_message.target_abortβ abort the ongoing transfer request on an SPI target controller.set_csβ set the logic level of the chip select line. May be called from interrupt context.transfer_oneβ transfer a singlespi_transfer.handle_errβ the subsystem calls the driver to handle an error that occurs in the generic implementation oftransfer_one_message.mem_opsβ optimized/dedicated operations for interactions with SPI memory. This field is optional and should only be implemented if the controller has native support for memory like operations.mem_capsβ controller capabilities for the handling of memory operations.dtr_capsβtrueif controller has dtr(single/dual transfer rate) capability. QSPI based controller should fill this based on controller's capability.get_offloadβ callback for controllers with offload support to get matching offload instance. Implementations should return-ENODEVif no match is found.put_offloadβ release the offload instance acquired byget_offload.cs_gpiodsβ Array of GPIO descriptors to use as chip select lines; one per CS number. Any individual value may beNULLfor CS lines that are not GPIOs (driven by the SPI controller itself).use_gpio_descriptorsβ Turns on the code in the SPI core to parse and grab GPIO descriptors. This will fill incs_gpiodsand SPI devices will have thecs_gpiodassigned if a GPIO line is found for the chipselect.unused_native_csβ Whencs_gpiodsis used,spi_register_controllerwill fill in this field with the first unused native CS, to be used by SPI controller drivers that need to drive a native CS when using GPIO CS.max_native_csβ Whencs_gpiodsis used, and this field is filled in,spi_register_controllerwill validate all native CS (including the unused native CS) against this value.pcpu_statisticsβ statistics for thespi_controller.dma_txβ DMA transmit channel.dma_rxβ DMA receive channel.dummy_rxβ dummy receive buffer for full-duplex devices.dummy_txβ dummy transmit buffer for full-duplex devices.fw_translate_csβ If the boot firmware uses different numbering scheme what Linux expects, this optional hook can be used to translate between the two.ptp_sts_supportedβ If the driver sets this totrue, it must provide a time snapshot inspi_transfer->ptp_stsas close as possible to the moment in time whenspi_transfer->ptp_sts_word_preandspi_transfer->ptp_sts_word_postwere transmitted. If the driver does not set this, the SPI core takes the snapshot as close to the driver hand-over as possible.irq_flagsβ Interrupt enable state during PTP system timestamping.queue_emptyβ signal green light for opportunistically skipping the queue forspi_synctransfers.must_asyncβ disable all fast paths in the core.defer_optimize_messageβ set totrueif controller cannot pre-optimize messages and needs to defer the optimization step until the message is actually being transferred.userspace_clientsβ list of SPI devices instantiated from userspace via the sysfsnew_deviceinterface; protected byadd_lock.userspace_registeredβtrueonce thenew_device/delete_devicesysfs group has been added byspi_register_controller; used byspi_unregister_controllerto know whether to remove it.
π¬ DESCRIPTION π¬
okay so this is where the transfer callback tells the subsystem whatβs up, bestie:
return 0β the transfer is finished, periodt. βreturn 1β the transfer is still in progress. When the driver is finished with this transfer it must callspi_finalize_current_transferso the subsystem can issue the next transfer. If the transfer fails, the driver must set the flagSPI_TRANS_FAIL_IOtospi_transfer->errorfirst, before callingspi_finalize_current_transfer. π¨
Each SPI controller can communicate with one or more spi_device children. These make a small bus, sharing MOSI, MISO and SCK signals but not chip select signals. Each device may be configured to use a different clock rate, since those shared signals are ignored unless the chip is selected. π¦
The driver for an SPI controller manages access to those devices through a queue of spi_message transactions, copying data between CPU memory and an SPI target device. For each such message it queues, it calls the messageβs completion function when the transaction completes. π
π NOTE π
transfer_oneandtransfer_one_messageare mutually exclusive; when both are set, the generic subsystem does not call yourtransfer_onecallback. no cap, pick one. ππ₯
π SEE ALSO π
- Kernel file β
./include/linux/spi/spi.h struct spi_statistics(9)struct spi_delay(9)struct spi_device(9)struct spi_driver(9)spi_unregister_driver(9)module_spi_driver(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)
okay thatβs the whole vibe π this page lives under ./include/linux/spi, is dated October 2026, and itβs the manual for struct spi_controller(9) β go be iconic with your SPI controller, bestie πβ¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms