This note includes:
This is the interface to the code that implements the hardware-specific low-level functionality of an SPI master.
The spi_funcs_t structure is a table of pointers to functions that you can provide for your hardware-specific low-level module. The high-level code calls these functions.
typedef struct { size_t size; /* size of this structure */ void* (*init)( void *hdl, char *options ); void (*fini)( void *hdl ); int (*drvinfo)( void *hdl, spi_drvinfo_t *info ); int (*devinfo)( void *hdl, uint32_t device, spi_devinfo_t *info ); int (*setcfg)( void *hdl, uint16_t device, spi_cfg_t *cfg ); void* (*xfer)( void *hdl, uint32_t device, uint8_t *buf, int *len ); int (*dma_xfer)( void *hdl, uint32_t device, spi_dma_paddr_t *paddr, int len ); } spi_funcs_t;
There has to be a function table entry in the low-level module, and it has to be named spi_drv_entry. High-level code looks for this symbol name to find the function table for the low-level module.
The functions are described in the sections that follow:
The SPIDEV structure is the handle that the low-level module has to return to the high-level code. You can extend the structure, but SPIDEV has to be at the top. This handle is also passed to the low-level driver when the high-level code calls low-level functions.
typedef struct _spidev_entry { iofunc_attr_t attr; void *hdl; /* Pointer to high-level handle */ void *lock; /* Pointer to lock list */ } SPIDEV;
The init function initializes the master interface. The prototype for this function is:
void *init( void *hdl, char *options );
The arguments are:
The function must return either a handle, which is the pointer to the SPIDEV of the low-level module, or NULL if an error occurred.
The fini function cleans up the low-level driver and frees any memory associated with the given handle. The prototype for this function is:
void fini( void *hdl );
The argument is the handle of the low-level module that the init function returned.
The drvinfo function gets driver information from the low-level module. The prototype for this function is:
int drvinfo( void *hdl, spi_drvinfo_t *info );
The arguments are:
typedef struct { uint32_t version; char name[16]; /* Driver name */ uint32_t feature; #define SPI_FEATURE_DMA (1 << 31) #define SPI_FEATURE_DMA_ALIGN 0xFF } spi_drvinfo_t;
The function must return EOK if it successfully obtained the driver information.
The devinfo function obtains the information from specific devices that are connected to the SPI bus. The prototype for this function is:
int devinfo( void *hdl, uint32_t device, spi_devinfo_t *info );
The arguments are:
typedef struct { uint32_t device; /* Device ID */ char name[16]; /* Device description */ spi_cfg_t cfg; /* Device configuration */ } spi_devinfo_t;
This function must return EOK, or EINVAL if the device ID is invalid.
The setcfg function changes the configuration of specific devices on the SPI bus. The prototype for this function is:
int setcfg( void *hdl, uint16_t device, spi_cfg_t *cfg );
The arguments are:
typedef struct { uint32_t mode; uint32_t clock_rate; } spi_cfg_t;
This function must return EOK, or EINVAL if either the device ID or the configuration is invalid.
The xfer function initiates a transmit, receive, or exchange transaction. The prototype for this function is:
void *xfer( void *hdl, uint32_t device, uint8_t *buf, int *len );
The arguments are:
The function must return a pointer to the receive/exchange buffer, and store, in the location that len points to, the byte length of the data that has been transmitted, received, or exchanged by the low-level module. The high-level code checks the length to determine whether the transaction was successful.
The buffer is not DMA-safe, so if the low-level module needs to use DMA, it must allocate its own DMA-safe buffer and copy the data over, if necessary. |
The dma_xfer function initiates a DMA transmit, receive, or exchange transaction. The prototype for this function is:
int dma_xfer( void *hdl, uint32_t device, spi_dma_paddr_t *paddr, int len );
The arguments are:
typedef struct { uint64_t rpaddr; uint64_t wpaddr; } spi_dma_paddr_t;
The rpaddr and wpaddr are physical addresses.
This function must return the number of bytes that have been successfully transferred by DMA, or -1 if an error occurred. It's the responsibility of the application to manage the DMA buffer.
The libspi-master library provides an interface to mediate access to the SPI master. The resource manager layer registers a device name (usually /dev/spi0). Applications access the SPI master by using the functions declared in <hw/spi-master.h>.
The functions include the following:
They're described in the sections that follow.
The spi_open() function lets the application connect to the SPI resource manager. The prototype for this function is:
int spi_open( const char *path );
The argument is:
This function returns a file descriptor, or -1 if the open failed.
The spi_close() function disconnects the application from the SPI resource manager. The prototype for this function is:
int spi_close( int fd );
The argument is:
The spi_setcfg() function sets the configuration for a specific device on the SPI bus. The prototype for this function is:
int spi_setcfg( int fd, uint32_t device, spi_cfg_t *cfg );
The arguments are:
typedef struct { uint32_t mode; uint32_t clock_rate; } spi_cfg_t;
The possible mode settings are defined in <hw/spi-master.h>.
This function returns EOK if the configuration is successful.
The spi_getdevinfo() function gets the information for a specific device on the SPI bus. The prototype for this function is:
int spi_getdevinfo( int fd, uint32_t device, spi_devinfo_t *devinfo );
The arguments are:
typedef struct { uint32_t device; /* Device ID */ char name[16]; /* Device description */ spi_cfg_t cfg; /* Device configuration */ } spi_devinfo_t;
This function returns EOK if the device information is obtained successfully.
The spi_getdrvinfo() function gets the driver information for the low-level module. The prototype for this function is:
int spi_getdrvinfo( int fd, spi_drvinfo_t *drvinfo );
The arguments are:
typedef struct { uint32_t version; char name[16]; /* Driver name */ uint32_t feature; } spi_drvinfo_t;
The function returns EOK if the driver information is obtained successfully.
The spi_read() function reads data from a specific device on the SPI bus. The prototype for this function is:
int spi_read( int fd, uint32_t device, void *buf, int len );
The arguments are:
The function returns the number of bytes of data that it successfully read from the device. If an error occurred, the function returns -1 and sets errno:
An SPI driver typically considers it to be an error if the number of bytes returned by this function isn't the same as the number of bytes it asked the function to read.
The spi_write() function writes data to a specific device on the SPI bus. The prototype for this function is:
int spi_write( int fd, uint32_t device, void *buf, int len );
The arguments are:
The function returns the number of bytes of data that it successfully wrote to the device. If an error occurred, the function returns -1 and sets errno:
An SPI driver typically considers it to be an error if the number of bytes returned by this function isn't the same as the number of bytes it asked the function to write.
The spi_exchange() function exchanges data between a specific device and the SPI master. The prototype for this function is:
int spi_xchange( int fd, uint32_t device, void *wbuf, void *rbuf, int len );
The arguments are:
The function returns the number of bytes of data that it successfully exchanged between the device and the SPI master. If an error occurred, the function returns -1 and sets errno:
An SPI driver typically considers it to be an error if the number of bytes returned by this function isn't the same as the number of bytes it asked the function to exchange.
The spi_cmdread() function sends a command to, and then reads data from, a specific device on SPI bus. The prototype for this function is:
int spi_cmdread( int fd, uint32_t device, void *cbuf, int16_t clen, void *rbuf, int rlen );
The arguments are:
The function returns the number of bytes of data that it successfully read. If an error occurred, the function returns -1 and sets errno:
An SPI driver typically considers it to be an error if the number of bytes returned by this function isn't the same as the number of bytes it asked the function to read.
You can achieve the same results by calling spi_xchange(). |
The spi_dma_xchange() function uses DMA to exchange data between the SPI master and an SPI device. The prototype for this function is:
int spi_dma_xchange( int fd, uint32_t device, void *wbuf, void *rbuf, int len );
The arguments are:
The function returns the number of bytes of data that it successfully exchanged. If an error occurred, the function returns -1 and sets errno:
An SPI driver typically considers it to be an error if the number of bytes returned by this function isn't the same as the number of bytes it asked the function to exchange.
The application is responsible for allocating and managing the DMA buffer. The application can call spi_getdrvinfo() to determine if the driver supports DMA, and whether or not the DMA buffer requires alignment. |