Serial Peripheral Interface (SPI)

SPI is the “Serial Peripheral Interface”, widely used with embeddedsystems because it is a simple and efficient interface: basically amultiplexed shift register. Its three signal wires hold a clock (SCK,often in the range of 1-20 MHz), a “Master Out, Slave In” (MOSI) dataline, and a “Master In, Slave Out” (MISO) data line. SPI is a fullduplex protocol; for each bit shifted out the MOSI line (one per clock)another is shifted in on the MISO line. Those bits are assembled intowords of various sizes on the way to and from system memory. Anadditional chipselect line is usually active-low (nCS); four signals arenormally used for each peripheral, plus sometimes an interrupt.

The SPI bus facilities listed here provide a generalized interface todeclare SPI busses and devices, manage them according to the standardLinux driver model, and perform input/output operations. At this time,only “master” side interfaces are supported, where Linux talks to SPIperipherals and does not implement such a peripheral itself. (Interfacesto support implementing SPI slaves would necessarily look different.)

The programming interface is structured around two kinds of driver, andtwo kinds of device. A “Controller Driver” abstracts the controllerhardware, which may be as simple as a set of GPIO pins or as complex asa pair of FIFOs connected to dual DMA engines on the other side of theSPI shift register (maximizing throughput). Such drivers bridge betweenwhatever bus they sit on (often the platform bus) and SPI, and exposethe SPI side of their device as astructspi_master. SPI devices are children of that master,represented as astructspi_device andmanufactured fromstructspi_board_info descriptors which are usually provided byboard-specific initialization code. Astructspi_driver is called a “Protocol Driver”, and is bound to aspi_device using normal driver model calls.

The I/O model is a set of queued messages. Protocol drivers submit oneor morestructspi_message objects,which are processed and completed asynchronously. (There are synchronouswrappers, however.) Messages are built from one or morestructspi_transfer objects, each ofwhich wraps a full duplex SPI transfer. A variety of protocol tweakingoptions are needed, because different chips adopt very differentpolicies for how they use the bits transferred with SPI.

structspi_statistics

statistics for spi transfers

Definition

struct spi_statistics {  spinlock_t lock;  unsigned long           messages;  unsigned long           transfers;  unsigned long           errors;  unsigned long           timedout;  unsigned long           spi_sync;  unsigned long           spi_sync_immediate;  unsigned long           spi_async;  unsigned long long      bytes;  unsigned long long      bytes_rx;  unsigned long long      bytes_tx;#define SPI_STATISTICS_HISTO_SIZE 17;  unsigned long transfer_bytes_histo[SPI_STATISTICS_HISTO_SIZE];  unsigned long transfers_split_maxsize;};

Members

lock
lock protecting this structure
messages
number of spi-messages handled
transfers
number of spi_transfers handled
errors
number of errors during spi_transfer
timedout
number of timeouts during spi_transfer
spi_sync
number of times spi_sync is used
spi_sync_immediate
number of times spi_sync is executed immediatelyin calling context without queuing and scheduling
spi_async
number of times spi_async is used
bytes
number of bytes transferred to/from device
bytes_rx
number of bytes received from device
bytes_tx
number of bytes sent to device
transfer_bytes_histo
transfer bytes histogramm
transfers_split_maxsize
number of transfers that have been split because ofmaxsize limit
structspi_delay

SPI delay information

Definition

struct spi_delay {#define SPI_DELAY_UNIT_USECS    0;#define SPI_DELAY_UNIT_NSECS    1;#define SPI_DELAY_UNIT_SCK      2;  u16 value;  u8 unit;};

Members

value
Value for the delay
unit
Unit for the delay
structspi_device

Controller side proxy for an SPI slave device

Definition

struct spi_device {  struct device           dev;  struct spi_controller   *controller;  struct spi_controller   *master;  u32 max_speed_hz;  u8 chip_select;  u8 bits_per_word;  bool rt;  u32 mode;#define SPI_CPHA        0x01                    ;#define SPI_CPOL        0x02                    ;#define SPI_MODE_0      (0|0)                   ;#define SPI_MODE_1      (0|SPI_CPHA);#define SPI_MODE_2      (SPI_CPOL|0);#define SPI_MODE_3      (SPI_CPOL|SPI_CPHA);#define SPI_CS_HIGH     0x04                    ;#define SPI_LSB_FIRST   0x08                    ;#define SPI_3WIRE       0x10                    ;#define SPI_LOOP        0x20                    ;#define SPI_NO_CS       0x40                    ;#define SPI_READY       0x80                    ;#define SPI_TX_DUAL     0x100                   ;#define SPI_TX_QUAD     0x200                   ;#define SPI_RX_DUAL     0x400                   ;#define SPI_RX_QUAD     0x800                   ;#define SPI_CS_WORD     0x1000                  ;#define SPI_TX_OCTAL    0x2000                  ;#define SPI_RX_OCTAL    0x4000                  ;#define SPI_3WIRE_HIZ   0x8000                  ;  int irq;  void *controller_state;  void *controller_data;  char modalias[SPI_NAME_SIZE];  const char              *driver_override;  int cs_gpio;  struct gpio_desc        *cs_gpiod;  struct spi_delay        word_delay;  struct spi_statistics   statistics;};

Members

dev
Driver model representation of the device.
controller
SPI controller used with the device.
master
Copy of controller, for backwards compatibility.
max_speed_hz
Maximum clock rate to be used with this chip(on this board); may be changed by the device’s driver.The spi_transfer.speed_hz can override this for each transfer.
chip_select
Chipselect, distinguishing chips handled bycontroller.
bits_per_word
Data transfers involve one or more words; word sizeslike eight or 12 bits are common. In-memory wordsizes arepowers of two bytes (e.g. 20 bit samples use 32 bits).This may be changed by the device’s driver, or left at thedefault (0) indicating protocol words are eight bit bytes.The spi_transfer.bits_per_word can override this for each transfer.
rt
Make the pump thread real time priority.
mode
The spi mode defines how data is clocked out and in.This may be changed by the device’s driver.The “active low” default for chipselect mode can be overridden(by specifying SPI_CS_HIGH) as can the “MSB first” default foreach word in a transfer (by specifying SPI_LSB_FIRST).
irq
Negative, or the number passed torequest_irq() to receiveinterrupts from this device.
controller_state
Controller’s runtime state
controller_data
Board-specific definitions for controller, such asFIFO initialization parameters; from board_info.controller_data
modalias
Name of the driver to use with this device, or an aliasfor that name. This appears in the sysfs “modalias” attributefor driver coldplugging, and in uevents used for hotplugging
driver_override
If the name of a driver is written to this attribute, thenthe device will bind to the named driver and only the named driver.
cs_gpio
LEGACY: gpio number of the chipselect line (optional, -ENOENT whennot using a GPIO line) use cs_gpiod in new drivers by opting in onthe spi_master.
cs_gpiod
gpio descriptor of the chipselect line (optional, NULL whennot using a GPIO line)
word_delay
delay to be inserted between consecutivewords of a transfer
statistics
statistics for the spi_device

Description

Aspi_device is used to interchange data between an SPI slave(usually a discrete chip) and CPU memory.

Indev, the platform_data is used to hold information about thisdevice that’s meaningful to the device’s protocol driver, but notto its controller. One example might be an identifier for a chipvariant with slightly different functionality; another might beinformation about how this particular board wires the chip’s pins.

structspi_driver

Host side “protocol” driver

Definition

struct spi_driver {  const struct spi_device_id *id_table;  int (*probe)(struct spi_device *spi);  int (*remove)(struct spi_device *spi);  void (*shutdown)(struct spi_device *spi);  struct device_driver    driver;};

Members

id_table
List of SPI devices supported by this driver
probe
Binds this driver to the spi device. Drivers can verifythat the device is actually present, and may need to configurecharacteristics (such as bits_per_word) which weren’t needed forthe initial configuration done during system setup.
remove
Unbinds this driver from the spi device
shutdown
Standard shutdown callback used during system statetransitions such as powerdown/halt and kexec
driver
SPI device drivers should initialize the name and ownerfield of this structure.

Description

This represents the kind of device driver that uses SPI messages tointeract with the hardware at the other end of a SPI link. It’s calleda “protocol” driver because it works through messages rather than talkingdirectly to SPI hardware (which is what the underlying SPI controllerdriver does to pass those messages). These protocols are defined in thespecification for the device(s) supported by the driver.

As a rule, those device protocols represent the lowest level interfacesupported by a driver, and it will support upper level interfaces too.Examples of such upper levels include frameworks like MTD, networking,MMC, RTC, filesystem character device nodes, and hardware monitoring.

voidspi_unregister_driver(structspi_driver * sdrv)

reverse effect of spi_register_driver

Parameters

structspi_driver*sdrv
the driver to unregister

Context

can sleep

module_spi_driver(__spi_driver)

Helper macro for registering a SPI driver

Parameters

__spi_driver
spi_driver struct

Description

Helper macro for SPI drivers which do not do anything special in moduleinit/exit. This eliminates a lot of boilerplate. Each module may onlyuse this macro once, and calling it replacesmodule_init() andmodule_exit()

structspi_controller

interface to SPI master or slave controller

Definition

struct spi_controller {  struct device   dev;  struct list_head list;  s16 bus_num;  u16 num_chipselect;  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_MASTER_GPIO_SS              BIT(5)  ;  bool slave;  size_t (*max_transfer_size)(struct spi_device *spi);  size_t (*max_message_size)(struct spi_device *spi);  struct mutex            io_mutex;  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, struct spi_delay *setup, struct spi_delay *hold, struct spi_delay *inactive);  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);  bool queued;  struct kthread_worker           *kworker;  struct kthread_work             pump_messages;  spinlock_t queue_lock;  struct list_head                queue;  struct spi_message              *cur_msg;  bool idling;  bool busy;  bool running;  bool rt;  bool auto_runtime_pm;  bool cur_msg_prepared;  bool cur_msg_mapped;  bool last_cs_enable;  bool last_cs_mode_high;  bool fallback;  struct completion               xfer_completion;  size_t max_dma_len;  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 (*slave_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;  struct spi_delay        cs_setup;  struct spi_delay        cs_hold;  struct spi_delay        cs_inactive;  int *cs_gpios;  struct gpio_desc        **cs_gpiods;  bool use_gpio_descriptors;  u8 unused_native_cs;  u8 max_native_cs;  struct spi_statistics   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;};

Members

dev
device interface to this driver
list
link with the global spi_controller list
bus_num
board-specific (and often SOC-specific) identifier for agiven SPI controller.
num_chipselect
chipselects are used to distinguish individualSPI slaves, and are numbered from zero to num_chipselects.each slave has a chipselect signal, but it’s common that notevery chipselect is connected to a slave.
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 of bits_per_word aresupported by the driver. Bit n indicates that a bits_per_word n+1 issupported. If set, the SPI core will reject any transfer with anunsupported bits_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
slave
indicates that this is an SPI slave controller
max_transfer_size
function that returns the max transfer size foraspi_device; may beNULL, so the defaultSIZE_MAX will be used.
max_message_size
function that returns the max message size foraspi_device; may beNULL, so the defaultSIZE_MAX will be used.
io_mutex
mutex for physical bus access
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 adevice’s SPI controller; protocol code may call this. Thismust fail if an unrecognized or unsupported mode is requested.It’s always safe to call this unless transfers are pending onthe device whose settings are being modified.
set_cs_timing
optional hook for SPI devices to request SPI mastercontroller for configuring specific CS setup time, hold time and inactivedelay interms 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
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 syncronise access to message queue
queue
message queue
cur_msg
the currently in-flight message
idling
the device is entering idle state
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 heldwhile the hardware is prepared, using the parentdevice for the spidev
cur_msg_prepared
spi_prepare_message was called for the currentlyin-flight message
cur_msg_mapped
message has been mapped for DMA
last_cs_enable
was enable true on the last call to set_cs.
last_cs_mode_high
was (mode & SPI_CS_HIGH) true on the last call to set_cs.
fallback
fallback to pio if dma transfer return failure withSPI_TRANS_FAIL_NO_START.
xfer_completion
used by core transfer_one_message()
max_dma_len
Maximum length of a DMA transfer for the device.
prepare_transfer_hardware
a message will soon arrive from the queueso the subsystem requests the driver to prepare the transfer hardwareby issuing this call
transfer_one_message
the subsystem calls the driver to transfer a singlemessage while queuing transfers that arrive in the meantime. When thedriver is finished with this message, it must callspi_finalize_current_message() so the subsystem can issue the nextmessage
unprepare_transfer_hardware
there are currently no more messages on thequeue so the subsystem notifies the driver that it may relax thehardware by issuing this call
prepare_message
set up the controller to transfer a single message,for example doing DMA mapping. Called from threadedcontext.
unprepare_message
undo any work done by prepare_message().
slave_abort
abort the ongoing transfer request on an SPI slave controller
set_cs
set the logic level of the chip select line. May be calledfrom interrupt context.
transfer_one

transfer a single spi_transfer.

  • return 0 if the transfer is finished,
  • return 1 if the transfer is still in progress. Whenthe driver is finished with this transfer it mustcallspi_finalize_current_transfer() so the subsystemcan issue the next transfer. Note: transfer_one andtransfer_one_message are mutually exclusive; when bothare set, the generic subsystem does not call yourtransfer_one callback.
handle_err
the subsystem calls the driver to handle an error that occursin the generic implementation of transfer_one_message().
mem_ops
optimized/dedicated operations for interactions with SPI memory.This field is optional and should only be implemented if thecontroller has native support for memory like operations.
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 isdeasserted. Ifcs_change_delay is used fromspi_transfer, then thetwo delays will be added up.
cs_gpios
LEGACY: array of GPIO descs to use as chip select lines; one perCS number. Any individual value may be -ENOENT for CS lines thatare not GPIOs (driven by the SPI controller itself). Use the cs_gpiodsin new drivers.
cs_gpiods
Array of GPIO descs to use as chip select lines; one per CSnumber. Any individual value may be NULL for CS lines thatare not GPIOs (driven by the SPI controller itself).
use_gpio_descriptors
Turns on the code in the SPI core to parse and grabGPIO descriptors rather than using global GPIO numbers grabbed by thedriver. This will fill incs_gpiods andcs_gpios should not be used,and SPI devices will have the cs_gpiod assigned rather than cs_gpio.
unused_native_cs
When cs_gpiods is used,spi_register_controller() willfill in this field with the first unused native CS, to be used by SPIcontroller drivers that need to drive a native CS when using GPIO CS.
max_native_cs
When cs_gpiods is used, and this field is filled in,spi_register_controller() will validate all native CS (including theunused native CS) against this value.
statistics
statistics for the spi_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 schemewhat Linux expects, this optional hook can be used to translatebetween the two.
ptp_sts_supported
If the driver sets this to true, it must provide atime snapshot inspi_transfer->ptp_sts as close as possible to themoment in time whenspi_transfer->ptp_sts_word_pre andspi_transfer->ptp_sts_word_post were transmitted.If the driver does not set this, the SPI core takes the snapshot asclose to the driver hand-over as possible.
irq_flags
Interrupt enable state during PTP system timestamping

Description

Each SPI controller can communicate with one or morespi_devicechildren. These make a small bus, sharing MOSI, MISO and SCK signalsbut not chip select signals. Each device may be configured to use adifferent clock rate, since those shared signals are ignored unlessthe chip is selected.

The driver for an SPI controller manages access to those devices througha queue of spi_message transactions, copying data between CPU memory andan SPI slave device. For each such message it queues, it calls themessage’s completion function when the transaction completes.

structspi_res

spi resource management structure

Definition

struct spi_res {  struct list_head        entry;  spi_res_release_t release;  unsigned long long      data[];};

Members

entry
list entry
release
release code called prior to freeing this resource
data
extra data allocated for the specific use-case

Description

this is based on ideas from devres, but focused on life-cyclemanagement during spi_message processing

structspi_transfer

a read/write buffer pair

Definition

struct spi_transfer {  const void      *tx_buf;  void *rx_buf;  unsigned len;  dma_addr_t tx_dma;  dma_addr_t rx_dma;  struct sg_table tx_sg;  struct sg_table rx_sg;  unsigned cs_change:1;  unsigned tx_nbits:3;  unsigned rx_nbits:3;#define SPI_NBITS_SINGLE        0x01 ;#define SPI_NBITS_DUAL          0x02 ;#define SPI_NBITS_QUAD          0x04 ;  u8 bits_per_word;  u16 delay_usecs;  struct spi_delay        delay;  struct spi_delay        cs_change_delay;  struct spi_delay        word_delay;  u32 speed_hz;  u32 effective_speed_hz;  unsigned int    ptp_sts_word_pre;  unsigned int    ptp_sts_word_post;  struct ptp_system_timestamp *ptp_sts;  bool timestamped;  struct list_head transfer_list;#define SPI_TRANS_FAIL_NO_START BIT(0);  u16 error;};

Members

tx_buf
data to be written (dma-safe memory), or NULL
rx_buf
data to be read (dma-safe memory), or NULL
len
size of rx and tx buffers (in bytes)
tx_dma
DMA address of tx_buf, ifspi_message.is_dma_mapped
rx_dma
DMA address of rx_buf, ifspi_message.is_dma_mapped
tx_sg
Scatterlist for transmit, currently not for client use
rx_sg
Scatterlist for receive, currently not for client use
cs_change
affects chipselect after this transfer completes
tx_nbits
number of bits used for writing. If 0 the default(SPI_NBITS_SINGLE) is used.
rx_nbits
number of bits used for reading. If 0 the default(SPI_NBITS_SINGLE) is used.
bits_per_word
select a bits_per_word other than the device defaultfor this transfer. If 0 the default (fromspi_device) is used.
delay_usecs
microseconds to delay after this transfer before(optionally) changing the chipselect status, then startingthe next transfer or completing thisspi_message.
delay
delay to be introduced after this transfer before(optionally) changing the chipselect status, then startingthe next transfer or completing thisspi_message.
cs_change_delay
delay between cs deassert and assert whencs_change is set andspi_transfer is not the last inspi_message
word_delay
inter word delay to be introduced after each word size(set by bits_per_word) transmission.
speed_hz
Select a speed other than the device default for thistransfer. If 0 the default (fromspi_device) is used.
effective_speed_hz
the effective SCK-speed that was used totransfer this transfer. Set to 0 if the spi bus driver doesnot support it.
ptp_sts_word_pre
The word (subject to bits_per_word semantics) offsetwithintx_buf for which the SPI device is requesting that the timesnapshot for this transfer begins. Upon completing the SPI transfer,this value may have changed compared to what was requested, dependingon the available snapshotting resolution (DMA transfer,ptp_sts_supported is false, etc).
ptp_sts_word_post
Seeptp_sts_word_post. The two can be equal (meaningthat a single byte should be snapshotted).If the core takes care of the timestamp (ifptp_sts_supported is falsefor this controller), it will setptp_sts_word_pre to 0, andptp_sts_word_post to the length of the transfer. This is donepurposefully (instead of setting to spi_transfer->len - 1) to denotethat a transfer-level snapshot taken from within the driver may stillbe of higher quality.
ptp_sts
Pointer to a memory location held by the SPI slave device where aPTP system timestamp structure may lie. If drivers use PIO or theirhardware has some sort of assist for retrieving exact transfer timing,they can (and should) assertptp_sts_supported and populate thisstructure using the ptp_read_system_*ts helper functions.The timestamp must represent the time at which the SPI slave device hasprocessed the word, i.e. the “pre” timestamp should be taken beforetransmitting the “pre” word, and the “post” timestamp after receivingtransmit confirmation from the controller for the “post” word.
timestamped
true if the transfer has been timestamped
transfer_list
transfers are sequenced throughspi_message.transfers
error
Error status logged by spi controller driver.

Description

SPI transfers always write the same number of bytes as they read.Protocol drivers should always providerx_buf and/ortx_buf.In some cases, they may also want to provide DMA addresses forthe data being transferred; that may reduce overhead, when theunderlying driver uses dma.

If the transmit buffer is null, zeroes will be shifted outwhile fillingrx_buf. If the receive buffer is null, the datashifted in will be discarded. Only “len” bytes shift out (or in).It’s an error to try to shift out a partial word. (For example, byshifting out three bytes with word size of sixteen or twenty bits;the former uses two bytes per word, the latter uses four bytes.)

In-memory data values are always in native CPU byte order, translatedfrom the wire byte order (big-endian except with SPI_LSB_FIRST). Sofor example when bits_per_word is sixteen, buffers are 2N bytes long(len = 2N) and hold N sixteen bit words in CPU byte order.

When the word size of the SPI transfer is not a power-of-two multipleof eight bits, those in-memory words include extra bits. In-memorywords are always seen by protocol drivers as right-justified, so theundefined (rx) or unused (tx) bits are always the most significant bits.

All SPI transfers start with the relevant chipselect active. Normallyit stays selected until after the last transfer in a message. Driverscan affect the chipselect signal using cs_change.

(i) If the transfer isn’t the last one in the message, this flag isused to make the chipselect briefly go inactive in the middle of themessage. Toggling chipselect in this way may be needed to terminatea chip command, letting a single spi_message perform all of group ofchip transactions together.

(ii) When the transfer is the last one in the message, the chip maystay selected until the next transfer. On multi-device SPI busseswith nothing blocking messages going to other devices, this is justa performance hint; starting a message to another device deselectsthis one. But in other cases, this can be used to ensure correctness.Some devices need protocol transactions to be built from a series ofspi_message submissions, where the content of one message is determinedby the results of previous messages and where the whole transactionends when the chipselect goes intactive.

When SPI can transfer in 1x,2x or 4x. It can get this transfer informationfrom device throughtx_nbits andrx_nbits. In Bi-direction, thesetwo should both be set. User can set transfer mode with SPI_NBITS_SINGLE(1x)SPI_NBITS_DUAL(2x) and SPI_NBITS_QUAD(4x) to support these three transfer.

The code that submits an spi_message (and its spi_transfers)to the lower layers is responsible for managing its memory.Zero-initialize every field you don’t set up explicitly, toinsulate against future API updates. After you submit a messageand its transfers, ignore them until its completion callback.

structspi_message

one multi-segment SPI transaction

Definition

struct spi_message {  struct list_head        transfers;  struct spi_device       *spi;  unsigned is_dma_mapped:1;  void (*complete)(void *context);  void *context;  unsigned frame_length;  unsigned actual_length;  int status;  struct list_head        queue;  void *state;  struct list_head        resources;};

Members

transfers
list of transfer segments in this transaction
spi
SPI device to which the transaction is queued
is_dma_mapped
if true, the caller provided both dma and cpu virtualaddresses for each transfer buffer
complete
called to report transaction completions
context
the argument to complete() when it’s called
frame_length
the total number of bytes in the message
actual_length
the total number of bytes that were transferred in allsuccessful segments
status
zero for success, else negative errno
queue
for use by whichever driver currently owns the message
state
for use by whichever driver currently owns the message
resources
for resource management when the spi message is processed

Description

Aspi_message is used to execute an atomic sequence of data transfers,each represented by a struct spi_transfer. The sequence is “atomic”in the sense that no other spi_message may use that SPI bus until thatsequence completes. On some systems, many such sequences can execute asa single programmed DMA transfer. On all systems, these messages arequeued, and might complete after transactions to other devices. Messagessent to a given spi_device are always executed in FIFO order.

The code that submits an spi_message (and its spi_transfers)to the lower layers is responsible for managing its memory.Zero-initialize every field you don’t set up explicitly, toinsulate against future API updates. After you submit a messageand its transfers, ignore them until its completion callback.

voidspi_message_init_with_transfers(structspi_message * m, structspi_transfer * xfers, unsigned int num_xfers)

Initialize spi_message and append transfers

Parameters

structspi_message*m
spi_message to be initialized
structspi_transfer*xfers
An array of spi transfers
unsignedintnum_xfers
Number of items in the xfer array

Description

This function initializes the given spi_message and adds each spi_transfer inthe given array to the message.

boolspi_is_bpw_supported(structspi_device * spi, u32 bpw)

Check if bits per word is supported

Parameters

structspi_device*spi
SPI device
u32bpw
Bits per word

Description

This function checks to see if the SPI controller supportsbpw.

Return

True ifbpw is supported, false otherwise.

structspi_replaced_transfers

structure describing the spi_transfer replacements that have occurred so that they can get reverted

Definition

struct spi_replaced_transfers {  spi_replaced_release_t release;  void *extradata;  struct list_head replaced_transfers;  struct list_head *replaced_after;  size_t inserted;  struct spi_transfer inserted_transfers[];};

Members

release
some extra release code to get executed prior torelasing this structure
extradata
pointer to some extra data if requested or NULL
replaced_transfers
transfers that have been replaced and which needto get restored
replaced_after
the transfer after which thereplaced_transfersare to get re-inserted
inserted
number of transfers inserted
inserted_transfers
array of spi_transfers of array-sizeinserted,that have been replacing replaced_transfers

note

thatextradata will point toinserted_transfers**[**inserted]if some extra allocation is requested, so alignment will be the sameas for spi_transfers

intspi_sync_transfer(structspi_device * spi, structspi_transfer * xfers, unsigned int num_xfers)

synchronous SPI data transfer

Parameters

structspi_device*spi
device with which data will be exchanged
structspi_transfer*xfers
An array of spi_transfers
unsignedintnum_xfers
Number of items in the xfer array

Context

can sleep

Description

Does a synchronous SPI data transfer of the given spi_transfer array.

For more specific semantics seespi_sync().

Return

zero on success, else a negative error code.

intspi_write(structspi_device * spi, const void * buf, size_t len)

SPI synchronous write

Parameters

structspi_device*spi
device to which data will be written
constvoid*buf
data buffer
size_tlen
data buffer size

Context

can sleep

Description

This function writes the bufferbuf.Callable only from contexts that can sleep.

Return

zero on success, else a negative error code.

intspi_read(structspi_device * spi, void * buf, size_t len)

SPI synchronous read

Parameters

structspi_device*spi
device from which data will be read
void*buf
data buffer
size_tlen
data buffer size

Context

can sleep

Description

This function reads the bufferbuf.Callable only from contexts that can sleep.

Return

zero on success, else a negative error code.

ssize_tspi_w8r8(structspi_device * spi, u8 cmd)

SPI synchronous 8 bit write followed by 8 bit read

Parameters

structspi_device*spi
device with which data will be exchanged
u8cmd
command to be written before data is read back

Context

can sleep

Description

Callable only from contexts that can sleep.

Return

the (unsigned) eight bit number returned by thedevice, or else a negative error code.

ssize_tspi_w8r16(structspi_device * spi, u8 cmd)

SPI synchronous 8 bit write followed by 16 bit read

Parameters

structspi_device*spi
device with which data will be exchanged
u8cmd
command to be written before data is read back

Context

can sleep

Description

The number is returned in wire-order, which is at least sometimesbig-endian.

Callable only from contexts that can sleep.

Return

the (unsigned) sixteen bit number returned by thedevice, or else a negative error code.

ssize_tspi_w8r16be(structspi_device * spi, u8 cmd)

SPI synchronous 8 bit write followed by 16 bit big-endian read

Parameters

structspi_device*spi
device with which data will be exchanged
u8cmd
command to be written before data is read back

Context

can sleep

Description

This function is similar to spi_w8r16, with the exception that it willconvert the read 16 bit data word from big-endian to native endianness.

Callable only from contexts that can sleep.

Return

the (unsigned) sixteen bit number returned by the device in cpuendianness, or else a negative error code.

structspi_board_info

board-specific template for a SPI device

Definition

struct spi_board_info {  char modalias[SPI_NAME_SIZE];  const void      *platform_data;  const struct property_entry *properties;  void *controller_data;  int irq;  u32 max_speed_hz;  u16 bus_num;  u16 chip_select;  u32 mode;};

Members

modalias
Initializes spi_device.modalias; identifies the driver.
platform_data
Initializes spi_device.platform_data; the particulardata stored there is driver-specific.
properties
Additional device properties for the device.
controller_data
Initializes spi_device.controller_data; somecontrollers need hints about hardware setup, e.g. for DMA.
irq
Initializes spi_device.irq; depends on how the board is wired.
max_speed_hz
Initializes spi_device.max_speed_hz; based on limitsfrom the chip datasheet and board-specific signal quality issues.
bus_num
Identifies which spi_controller parents the spi_device; unusedbyspi_new_device(), and otherwise depends on board wiring.
chip_select
Initializes spi_device.chip_select; depends on howthe board is wired.
mode
Initializes spi_device.mode; based on the chip datasheet, boardwiring (some devices support both 3WIRE and standard modes), andpossibly presence of an inverter in the chipselect path.

Description

When adding new SPI devices to the device tree, these structures serveas a partial device template. They hold information which can’t alwaysbe determined by drivers. Information that probe() can establish (suchas the default transfer wordsize) is not included here.

These structures are used in two places. Their primary role is tobe stored in tables of board-specific device descriptors, which aredeclared early in board initialization and then used (much later) topopulate a controller’s device tree after the that controller’s driverinitializes. A secondary (and atypical) role is as a parameter tospi_new_device() call, which happens after those controller driversare active in some dynamic board configuration models.

intspi_register_board_info(structspi_board_info const * info, unsigned n)

register SPI devices for a given board

Parameters

structspi_board_infoconst*info
array of chip descriptors
unsignedn
how many descriptors are provided

Context

can sleep

Description

Board-specific early init code calls this (probably during arch_initcall)with segments of the SPI device table. Any device nodes are created later,after the relevant parent SPI controller (bus_num) is defined. We keepthis table of devices forever, so that reloading a controller driver willnot make Linux forget about these hard-wired devices.

Other code can also call this, e.g. a particular add-on board might provideSPI devices through its expansion connector, so code initializing that boardwould naturally declare its SPI devices.

The board info passed can safely be __initdata … but be careful ofany embedded pointers (platform_data, etc), they’re copied as-is.Device properties are deep-copied though.

Return

zero on success, else a negative error code.

int__spi_register_driver(struct module * owner, structspi_driver * sdrv)

register a SPI driver

Parameters

structmodule*owner
owner module of the driver to register
structspi_driver*sdrv
the driver to register

Context

can sleep

Return

zero on success, else a negative error code.

structspi_device *spi_alloc_device(structspi_controller * ctlr)

Allocate a new SPI device

Parameters

structspi_controller*ctlr
Controller to which device is connected

Context

can sleep

Description

Allows a driver to allocate and initialize a spi_device withoutregistering it immediately. This allows a driver to directlyfill the spi_device with device parameters before callingspi_add_device() on it.

Caller is responsible to callspi_add_device() on the returnedspi_device structure to add it to the SPI controller. If the callerneeds to discard the spi_device without adding it, then it shouldcall spi_dev_put() on it.

Return

a pointer to the new device, or NULL.

intspi_add_device(structspi_device * spi)

Add spi_device allocated with spi_alloc_device

Parameters

structspi_device*spi
spi_device to register

Description

Companion function to spi_alloc_device. Devices allocated withspi_alloc_device can be added onto the spi bus with this function.

Return

0 on success; negative errno on failure

structspi_device *spi_new_device(structspi_controller * ctlr, structspi_board_info * chip)

instantiate one new SPI device

Parameters

structspi_controller*ctlr
Controller to which device is connected
structspi_board_info*chip
Describes the SPI device

Context

can sleep

Description

On typical mainboards, this is purely internal; and it’s not neededafter board init creates the hard-wired devices. Some developmentplatforms may not be able to use spi_register_board_info though, andthis is exported so that for example a USB or parport based adapterdriver could add devices (which it would learn about out-of-band).

Return

the new device, or NULL.

voidspi_unregister_device(structspi_device * spi)

unregister a single SPI device

Parameters

structspi_device*spi
spi_device to unregister

Description

Start making the passed SPI device vanish. Normally this would be handledbyspi_unregister_controller().

voidspi_finalize_current_transfer(structspi_controller * ctlr)

report completion of a transfer

Parameters

structspi_controller*ctlr
the controller reporting completion

Description

Called by SPI drivers using the core transfer_one_message()implementation to notify it that the current interrupt driventransfer has finished and the next one may be scheduled.

voidspi_take_timestamp_pre(structspi_controller * ctlr, structspi_transfer * xfer, size_t progress, bool irqs_off)

helper for drivers to collect the beginning of the TX timestamp for the requested byte from the SPI transfer. The frequency with which this function must be called (once per word, once for the whole transfer, once per batch of words etc) is arbitrary as long as thetx buffer offset is greater than or equal to the requested byte at the time of the call. The timestamp is only taken once, at the first such call. It is assumed that the driver advances itstx buffer pointer monotonically.

Parameters

structspi_controller*ctlr
Pointer to the spi_controller structure of the driver
structspi_transfer*xfer
Pointer to the transfer being timestamped
size_tprogress
How many words (not bytes) have been transferred so far
boolirqs_off
If true, will disable IRQs and preemption for the duration of thetransfer, for less jitter in time measurement. Only compatiblewith PIO drivers. If true, must follow up withspi_take_timestamp_post or otherwise system will crash.WARNING: for fully predictable results, the CPU frequency mustalso be under control (governor).
voidspi_take_timestamp_post(structspi_controller * ctlr, structspi_transfer * xfer, size_t progress, bool irqs_off)

helper for drivers to collect the end of the TX timestamp for the requested byte from the SPI transfer. Can be called with an arbitrary frequency: only the first call wheretx exceeds or is equal to the requested word will be timestamped.

Parameters

structspi_controller*ctlr
Pointer to the spi_controller structure of the driver
structspi_transfer*xfer
Pointer to the transfer being timestamped
size_tprogress
How many words (not bytes) have been transferred so far
boolirqs_off
If true, will re-enable IRQs and preemption for the local CPU.
structspi_message *spi_get_next_queued_message(structspi_controller * ctlr)

called by driver to check for queued messages

Parameters

structspi_controller*ctlr
the controller to check for queued messages

Description

If there are more messages in the queue, the next message is returned fromthis call.

Return

the next message in the queue, else NULL if the queue is empty.

voidspi_finalize_current_message(structspi_controller * ctlr)

the current message is complete

Parameters

structspi_controller*ctlr
the controller to return the message to

Description

Called by the driver to notify the core that the message in the front of thequeue is complete and can be removed from the queue.

intspi_slave_abort(structspi_device * spi)

abort the ongoing transfer request on an SPI slave controller

Parameters

structspi_device*spi
device used for the current transfer
structspi_controller *__spi_alloc_controller(structdevice * dev, unsigned int size, bool slave)

allocate an SPI master or slave controller

Parameters

structdevice*dev
the controller, possibly using the platform_bus
unsignedintsize
how much zeroed driver-private data to allocate; the pointer to thismemory is in the driver_data field of the returned device, accessiblewith spi_controller_get_devdata(); the memory is cacheline aligned;drivers granting DMA access to portions of their private data need toround upsize using ALIGN(size, dma_get_cache_alignment()).
boolslave
flag indicating whether to allocate an SPI master (false) or SPIslave (true) controller

Context

can sleep

Description

This call is used only by SPI controller drivers, which are theonly ones directly touching chip registers. It’s how they allocatean spi_controller structure, prior to callingspi_register_controller().

This must be called from context that can sleep.

The caller is responsible for assigning the bus number and initializing thecontroller’s methods before callingspi_register_controller(); and (aftererrors adding the device) calling spi_controller_put() to prevent a memoryleak.

Return

the SPI controller structure on success, else NULL.

intspi_register_controller(structspi_controller * ctlr)

register SPI master or slave controller

Parameters

structspi_controller*ctlr
initialized master, originally from spi_alloc_master() orspi_alloc_slave()

Context

can sleep

Description

SPI controllers connect to their drivers using some non-SPI bus,such as the platform bus. The final stage of probe() in that codeincludes callingspi_register_controller() to hook up to this SPI bus glue.

SPI controllers use board specific (often SOC specific) bus numbers,and board-specific addressing for SPI devices combines those numberswith chip select numbers. Since SPI does not directly support dynamicdevice identification, boards need configuration tables telling whichchip is at which address.

This must be called from context that can sleep. It returns zero onsuccess, else a negative error code (dropping the controller’s refcount).After a successful return, the caller is responsible for callingspi_unregister_controller().

Return

zero on success, else a negative error code.

intdevm_spi_register_controller(structdevice * dev, structspi_controller * ctlr)

register managed SPI master or slave controller

Parameters

structdevice*dev
device managing SPI controller
structspi_controller*ctlr
initialized controller, originally from spi_alloc_master() orspi_alloc_slave()

Context

can sleep

Description

Register a SPI device as withspi_register_controller() which willautomatically be unregistered and freed.

Return

zero on success, else a negative error code.

voidspi_unregister_controller(structspi_controller * ctlr)

unregister SPI master or slave controller

Parameters

structspi_controller*ctlr
the controller being unregistered

Context

can sleep

Description

This call is used only by SPI controller drivers, which are theonly ones directly touching chip registers.

This must be called from context that can sleep.

Note that this function also drops a reference to the controller.

structspi_controller *spi_busnum_to_master(u16 bus_num)

look up master associated with bus_num

Parameters

u16bus_num
the master’s bus number

Context

can sleep

Description

This call may be used with devices that are registered afterarch init time. It returns a refcounted pointer to the relevantspi_controller (which the caller must release), or NULL if there isno such master registered.

Return

the SPI master structure on success, else NULL.

void *spi_res_alloc(structspi_device * spi, spi_res_release_t release, size_t size, gfp_t gfp)

allocate a spi resource that is life-cycle managed during the processing of a spi_message while using spi_transfer_one

Parameters

structspi_device*spi
the spi device for which we allocate memory
spi_res_release_trelease
the release code to execute for this resource
size_tsize
size to alloc and return
gfp_tgfp
GFP allocation flags

Return

the pointer to the allocated data

Description

This may get enhanced in the future to allocate from a memory poolof thespi_device orspi_controller to avoid repeated allocations.

voidspi_res_free(void * res)

free an spi resource

Parameters

void*res
pointer to the custom data of a resource
voidspi_res_add(structspi_message * message, void * res)

add a spi_res to the spi_message

Parameters

structspi_message*message
the spi message
void*res
the spi_resource
voidspi_res_release(structspi_controller * ctlr, structspi_message * message)

release all spi resources for this message

Parameters

structspi_controller*ctlr
thespi_controller
structspi_message*message
thespi_message
structspi_replaced_transfers *spi_replace_transfers(structspi_message * msg, structspi_transfer * xfer_first, size_t remove, size_t insert, spi_replaced_release_t release, size_t extradatasize, gfp_t gfp)

replace transfers with several transfers and register change with spi_message.resources

Parameters

structspi_message*msg
the spi_message we work upon
structspi_transfer*xfer_first
the first spi_transfer we want to replace
size_tremove
number of transfers to remove
size_tinsert
the number of transfers we want to insert instead
spi_replaced_release_trelease
extra release code necessary in some circumstances
size_textradatasize
extra data to allocate (with alignment guaranteesof structspi_transfer)
gfp_tgfp
gfp flags

Return

pointer tospi_replaced_transfers,
PTR_ERR(…) in case of errors.
intspi_split_transfers_maxsize(structspi_controller * ctlr, structspi_message * msg, size_t maxsize, gfp_t gfp)

split spi transfers into multiple transfers when an individual transfer exceeds a certain size

Parameters

structspi_controller*ctlr
thespi_controller for this transfer
structspi_message*msg
thespi_message to transform
size_tmaxsize
the maximum when to apply this
gfp_tgfp
GFP allocation flags

Return

status of transformation

intspi_setup(structspi_device * spi)

setup SPI mode and clock rate

Parameters

structspi_device*spi
the device whose settings are being modified

Context

can sleep, and no requests are queued to the device

Description

SPI protocol drivers may need to update the transfer mode if thedevice doesn’t work with its default. They may likewise needto update clock rates or word sizes from initial values. This functionchanges those settings, and must be called from a context that can sleep.Except for SPI_CS_HIGH, which takes effect immediately, the changes takeeffect the next time the device is selected and data is transferred toor from it. When this function returns, the spi device is deselected.

Note that this call will fail if the protocol driver specifies an optionthat the underlying controller or its driver does not support. Forexample, not all hardware supports wire transfers using nine bit words,LSB-first wire encoding, or active-high chipselects.

Return

zero on success, else a negative error code.

intspi_set_cs_timing(structspi_device * spi, structspi_delay * setup, structspi_delay * hold, structspi_delay * inactive)

configure CS setup, hold, and inactive delays

Parameters

structspi_device*spi
the device that requires specific CS timing configuration
structspi_delay*setup
CS setup time specified viaspi_delay
structspi_delay*hold
CS hold time specified viaspi_delay
structspi_delay*inactive
CS inactive delay between transfers specified viaspi_delay

Return

zero on success, else a negative error code.

intspi_async(structspi_device * spi, structspi_message * message)

asynchronous SPI transfer

Parameters

structspi_device*spi
device with which data will be exchanged
structspi_message*message
describes the data transfers, including completion callback

Context

any (irqs may be blocked, etc)

Description

This call may be used in_irq and other contexts which can’t sleep,as well as from task contexts which can sleep.

The completion callback is invoked in a context which can’t sleep.Before that invocation, the value of message->status is undefined.When the callback is issued, message->status holds either zero (toindicate complete success) or a negative error code. After thatcallback returns, the driver which issued the transfer request maydeallocate the associated memory; it’s no longer in use by any SPIcore or controller driver code.

Note that although all messages to a spi_device are handled inFIFO order, messages may go to different devices in other orders.Some device might be higher priority, or have various “hard” accesstime requirements, for example.

On detection of any fault during the transfer, processing ofthe entire message is aborted, and the device is deselected.Until returning from the associated message completion callback,no other spi_message queued to that device will be processed.(This rule applies equally to all the synchronous transfer calls,which are wrappers around this core asynchronous primitive.)

Return

zero on success, else a negative error code.

intspi_async_locked(structspi_device * spi, structspi_message * message)

version of spi_async with exclusive bus usage

Parameters

structspi_device*spi
device with which data will be exchanged
structspi_message*message
describes the data transfers, including completion callback

Context

any (irqs may be blocked, etc)

Description

This call may be used in_irq and other contexts which can’t sleep,as well as from task contexts which can sleep.

The completion callback is invoked in a context which can’t sleep.Before that invocation, the value of message->status is undefined.When the callback is issued, message->status holds either zero (toindicate complete success) or a negative error code. After thatcallback returns, the driver which issued the transfer request maydeallocate the associated memory; it’s no longer in use by any SPIcore or controller driver code.

Note that although all messages to a spi_device are handled inFIFO order, messages may go to different devices in other orders.Some device might be higher priority, or have various “hard” accesstime requirements, for example.

On detection of any fault during the transfer, processing ofthe entire message is aborted, and the device is deselected.Until returning from the associated message completion callback,no other spi_message queued to that device will be processed.(This rule applies equally to all the synchronous transfer calls,which are wrappers around this core asynchronous primitive.)

Return

zero on success, else a negative error code.

intspi_sync(structspi_device * spi, structspi_message * message)

blocking/synchronous SPI data transfers

Parameters

structspi_device*spi
device with which data will be exchanged
structspi_message*message
describes the data transfers

Context

can sleep

Description

This call may only be used from a context that may sleep. The sleepis non-interruptible, and has no timeout. Low-overhead controllerdrivers may DMA directly into and out of the message buffers.

Note that the SPI device’s chip select is active during the message,and then is normally disabled between messages. Drivers for somefrequently-used devices may want to minimize costs of selecting a chip,by leaving it selected in anticipation that the next message will goto the same chip. (That may increase power usage.)

Also, the caller is guaranteeing that the memory associated with themessage will not be freed before this call returns.

Return

zero on success, else a negative error code.

intspi_sync_locked(structspi_device * spi, structspi_message * message)

version of spi_sync with exclusive bus usage

Parameters

structspi_device*spi
device with which data will be exchanged
structspi_message*message
describes the data transfers

Context

can sleep

Description

This call may only be used from a context that may sleep. The sleepis non-interruptible, and has no timeout. Low-overhead controllerdrivers may DMA directly into and out of the message buffers.

This call should be used by drivers that require exclusive access to theSPI bus. It has to be preceded by a spi_bus_lock call. The SPI bus mustbe released by a spi_bus_unlock call when the exclusive access is over.

Return

zero on success, else a negative error code.

intspi_bus_lock(structspi_controller * ctlr)

obtain a lock for exclusive SPI bus usage

Parameters

structspi_controller*ctlr
SPI bus master that should be locked for exclusive bus access

Context

can sleep

Description

This call may only be used from a context that may sleep. The sleepis non-interruptible, and has no timeout.

This call should be used by drivers that require exclusive access to theSPI bus. The SPI bus must be released by a spi_bus_unlock call when theexclusive access is over. Data transfer must be done by spi_sync_lockedand spi_async_locked calls when the SPI bus lock is held.

Return

always zero.

intspi_bus_unlock(structspi_controller * ctlr)

release the lock for exclusive SPI bus usage

Parameters

structspi_controller*ctlr
SPI bus master that was locked for exclusive bus access

Context

can sleep

Description

This call may only be used from a context that may sleep. The sleepis non-interruptible, and has no timeout.

This call releases an SPI bus lock previously obtained by an spi_bus_lockcall.

Return

always zero.

intspi_write_then_read(structspi_device * spi, const void * txbuf, unsigned n_tx, void * rxbuf, unsigned n_rx)

SPI synchronous write followed by read

Parameters

structspi_device*spi
device with which data will be exchanged
constvoid*txbuf
data to be written (need not be dma-safe)
unsignedn_tx
size of txbuf, in bytes
void*rxbuf
buffer into which data will be read (need not be dma-safe)
unsignedn_rx
size of rxbuf, in bytes

Context

can sleep

Description

This performs a half duplex MicroWire style transaction with thedevice, sending txbuf and then reading rxbuf. The return valueis zero for success, else a negative errno status code.This call may only be used from a context that may sleep.

Parameters to this routine are always copied using a small buffer.Performance-sensitive or bulk transfer code should instead usespi_{async,sync}() calls with dma-safe buffers.

Return

zero on success, else a negative error code.