Through the introduction of the previous article, we know that the SPI Universal interface layer is used to connect the specific SPI device protocol driver and SPI Controller driver, the general interface layer in addition to the protocol driver and controller driver to provide a series of standard interface APIs, but also for these interface API defines the corresponding data structure, These data structures are part of the data abstraction of SPI devices, SPI protocol drivers, and SPI controllers, in part to data structures defined to assist in data transfer. In addition, the common interface layer is responsible for the initialization of the SPI system associated with the Linux device model. In this chapter we have a thorough understanding of the entire common interface layer through the discussion of these data structures and APIs.
/*****************************************************************************************************/
Statement: The content of this blog by Http://blog.csdn.net/droidphone Original, reproduced please indicate the source, thank you!
/*****************************************************************************************************/
The code for the SPI Universal Interface layer is concentrated in:/drivers/spi/spi.c.
Initialization of the SPI device model
Typically, depending on how the Linux device model is organized, various devices are hung on the appropriate bus, and device drivers and devices are matched to each other through the bus, enabling the device to find the correct driver for control and actuation. At the same time, a device of similar nature can be classified as a device of a class, which has some common device properties, which is called Class on the device model. SPI devices are no exception, and they follow the rules of the Linux device model:
struct Bus_type spi_bus_type = { . Name = "SPI", . Dev_attrs = Spi_dev_attrs, . Match = Spi_ Match_device, . uevent = spi_uevent, . PM = &spi_pm,}; static struct Class Spi_master_class = { . Name = "Spi_master", . Owner = this_module, . dev_ Release = spi_master_release,};static int __init spi_init (void) { int status; BUF = Kmalloc (Spi_bufsiz, gfp_kernel); ...... Status = Bus_register (&spi_bus_type); ...... Status = Class_register (&spi_master_class); ...... return 0; ......} Postcore_initcall (Spi_init);
As can be seen, during the initialization phase, the Spi_init function registers a bus type named SPI with the system, and also registers a device class named Spi_master for the SPI Controller. In this way, the following two file nodes will appear in SYSFS later:
- Sys/bus/spi
- Sys/class/spi_master
The match field of the Spi_bus_type structure representing the SPI bus points to the Spi_match_device function, which is used to match the device and driver on the SPI bus, and the specific code is not posted here, so you can view the kernel's code tree yourself.
Spi_master structure
The SPI Controller is responsible for exchanging data between the master and SPI devices according to the configured physical signal format, and how the SPI controller data is transmitted without regard to the contents of the data. The SPI universal interface layer uses the Spi_master structure to represent an SPI controller, and we look at the meaning of its main fields:
Field name |
Description |
struct Device Dev |
Device structure for SPI Controller |
struct List_head list |
The system may have more than one controller, which is connected to a global list variable using the link table |
S16 Bus_num |
The controller corresponds to the SPI bus number, starting from 0, usually set by the board-level code |
U16 Num_chipselect |
The number of chip-selection signals connected to the SPI controller |
U16 Mode_bits |
The mode of operation, which is interpreted by the driver to explain the meaning |
U32 min_speed_hz |
Minimum operating clock |
U32 max_speed_hz |
Maximum working clock |
U16 Flags |
Flag bits used to set certain restrictions |
Int (*setup) (struct Spi_device *spi) |
callback function for setting the operating parameters of an SPI device on the controller |
Int (*transfer) (...). ) |
callback function for adding the MESG structure containing the data information to the controller's message list |
void (*cleanup) (struct Spi_device *spi) |
callback function, which is called when Spi_master is freed. |
struct Kthread_worker Kworker |
Work queue thread for managing data transfer Message Queuing |
struct Kthread_work pump_messages |
The work queue that implements the data transmission queue concretely |
struct List_head queue |
Message Queuing for the controller, all messages waiting to be transmitted are queued under the linked list |
struct Spi_message *cur_msg |
Message queues that are currently being processed |
Int (*prepare_transfer_hardware) (...) |
callback function, which is called before the official launch of the transfer, for preparing the hardware resources |
Int (*transfer_one_message) (...) |
An atomic transfer callback function for a single message that each message in the queue invokes once to complete the transfer work |
Int (*unprepare_transfer_hardware) (...) |
Cleanup callback function |
int *cs_gpios |
Gpio used in the chip selection signal |
|
|
The spi_master structure is typically defined by the controller driver and is then registered to the system through the following common interface layer APIs:
- int Spi_register_master (struct spi_master *master);
Spi_device structure
The SPI universal interface layer uses the Spi_device structure to represent an SPI device, and its various fields have the following meanings:
struct Device Dev |
The device structure representing the SPI devices |
struct Spi_master *master |
The controller that is used to point to the SPI device |
U32 max_speed_hz |
Maximum operating clock frequency for this device |
U8 Chip_select |
Index of the selected PIN number in the controller |
U16 Mode |
The operating mode of the device, including the clock format, the effective electricity equality of the chip selection signal, etc. |
U8 Bits_per_word |
Number of Bits required per unit data for the device |
int IRQ |
IRQ number used by the device |
Char Modalias[spi_name_size] |
The device's name, used for pairing the SPI bus and the driver |
int Cs_gpio |
The GPIO number of the chip selection signal is usually not set by ourselves, and the interface layer will find and assign values in the Spi_master structure based on the Chip_select field above |
To complete adding and registering an SPI device to the system, we also need another data structure:
struct Spi_board_info { char modalias[spi_name_size]; const void *platform_data; void *controller_data; int IRQ; U32 max_speed_hz; U16 Bus_num; U16 Chip_select; U16 mode;};
Spi_board_info structure most fields correspond to the spi_device structure, the Bus_num field is used to specify the controller number to which it belongs, and through the spi_board_info structure, we can add the SPI device to the system in two ways. The first approach is that after the SPI controller driver has been loaded, we use the following API provided by the common interface layer to complete:
- struct Spi_device *spi_new_device (struct spi_master *master, struct spi_board_info *chip);
The second approach is to define a spi_board_info array in the initialization code of the Board, and then register the Spi_board_info with the following API:
- int Spi_register_board_info (struct spi_board_info const *info, unsigned n);
The above API will hang each spi_board_info on the global list variable board_list, and traverse the controller that is already registered in the system, match the corresponding controller and get their spi_master structure pointer, and finally pass the Spi_new_ The device function adds SPI devices. Because Spi_register_board_info can be called in the initialization code of the Board, it is possible that the controller driver has not yet been loaded and the corresponding Spi_master pointer cannot be obtained at the moment, but do not worry that the controller driver will be called when it is loaded Spi_register The _master function registers the spi_master structure, and the Spi_register_master function loops through Spi_board_info on the global list board_list, and then Spi_new_ The device function adds SPI devices.
Spi_driver structure
According to the Linux device model, there must be driver with device, the previous section describes the Spi_device structure embedded in the device structure field dev, similarly, the spi_driver structure that represents the driver is also embedded Device_ Driver structure:
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); int (*suspend) (struct Spi_device *spi, pm_message_t mesg); int (*resume) (struct spi_device *spi); struct device_driver driver;};
The Id_table field is used to specify the device name that the driver can drive, and the bus matching function compares the name specified in the id_table with the Modalias field in the Spi_device structure, which matches the success of the match and then departs Spi_ Driver's probe callback function is called to complete the initialization of the driver. The common interface layer provides the following APIs to complete Spi_driver registration:
int spi_register_driver (struct spi_driver *sdrv) { Sdrv->driver.bus = &spi_bus_type; if (sdrv->probe) sdrv->driver.probe = Spi_drv_probe; if (sdrv->remove) sdrv->driver.remove = Spi_drv_remove; if (sdrv->shutdown) sdrv->driver.shutdown = Spi_drv_shutdown; Return Driver_register (&sdrv->driver);}
It is important to note that the Spi_driver structure here represents the specific SPI protocol driver.
Spi_message and Spi_transfer Structures
To complete the data transfer work with the SPI device, we also need two additional data structures: Spi_message and Spi_transfer. The spi_message contains a sequence of spi_transfer structures, and once the controller receives a spi_message, the spi_transfer should be sent sequentially and cannot be interrupted by other spi_message, so we think the SPI _message is an atomic operation of the SPI data exchange. Let's look at the definitions of these two data structures:
struct Spi_message { struct list_head transfers; struct Spi_device *spi; unsigned is_dma_mapped:1; /* Completion is reported through a callback */ void (*complete) (void *context); void *context; unsigned frame_length; unsigned actual_length; int status; struct List_head queue; void *state;};
The Chain table field queue is used to hang the structure on the queue representing the spi_master structure of the controller, and the controller can be queued at the same time by joining multiple spi_message. Another linked table field, transfers, is used to link the spi_tranfer structure that is attached to this message. The complete callback function is called when all Spi_transfer under the message are transferred, so that the protocol driver processes the received data and prepares the next batch of data to be sent. Let's take a look at the Spi_transfer structure:
struct Spi_transfer { const void *tx_buf; void *rx_buf; unsigned len; dma_addr_t TX_DMA; dma_addr_t RX_DMA; unsigned cs_change:1; U8 tx_nbits; U8 rx_nbits; U8 Bits_per_word; U16 Delay_usecs; U32 speed_hz; struct list_head transfer_list;};
First, the Transfer_list Chain table field is used to hang the transfer in a spi_message structure, TX_BUF and RX_BUF provide a data buffer address in non-DMA mode, Len is the length of data to be transferred, TX_DMA and Rx_ DMA gives the buffer address in DMA mode. Principle, Spi_transfer is the smallest unit of transmission, the reason for the introduction of spi_message for packaging, I think the reason is: sometimes want to the SPI device multiple discontinuous address (or register) write once, if there is no spi_ The message is packaged in such multiple Spi_transfer, because the actual data transfer work is done in another kernel thread (task queue), and the consequences of non-packaging are more process switching, reduced efficiency, increased latency, This is especially true for small-scale data transfers with multiple disjoint addresses.
The universal interface layer provides us with a range of API functions for operating and maintaining Spi_message and Spi_transfer, which is also listed here.
Used to initialize the SPI_MESSAGE structure:
- void Spi_message_init (struct spi_message *m);
Add a Spi_transfer to a spi_message (note, just join, not start the transfer process), and remove a spi_transfer:
- void Spi_message_add_tail (struct spi_transfer *t, struct spi_message *m);
- void Spi_transfer_del (struct spi_transfer *t);
The combination of the above two APIs initializes a spi_message and adds several Spi_transfer structures:
- void Spi_message_init_with_transfers (struct spi_message *m, struct spi_transfer *xfers, unsigned int num_xfers);
Assign a spi_message with a number of Spi_transfer institutions:
- struct Spi_message *spi_message_alloc (unsigned ntrans, gfp_t flags);
Initiate a spi_message transfer operation:
- Asynchronous version int Spi_async (struct spi_device *spi, struct spi_message *message);
- Synchronous version int Spi_sync (struct spi_device *spi, struct spi_message *message);
Using these API functions, the SPI device's protocol driver can complete the data exchange work with an SPI device, and also can see that because of the isolation of the common interface layer, the controller driver is transparent to the protocol driver, that is to say, The protocol driver only cares about the data that needs to be processed and exchanged, without having to worry about how the controller transmits the data. Spi_master,spi_message,spi_transfer the relationships of these data structures can be used to describe:
To summarize, the process by which the protocol-driven data is sent is roughly the same:
- Define a spi_message structure;
- Initialize the spi_message with the Spi_message_init function;
- Defines one or more spi_transfer structures, initializes and prepares buffers for data and assigns values to spi_transfer corresponding fields (TX_BUF,RX_BUF, etc.);
- These spi_transfer are hung under the spi_message structure through the Spi_message_init function;
- If you use synchronous mode, call Spi_sync (), or call Spi_async () If you use asynchronous mode;
In addition, the common interface layer provides a separate API for some simple data transfer to complete the above combination process:
- int spi_write (struct spi_device *spi, const void *buf, size_t len); Send data----synchronous mode.
- int Spi_read (struct spi_device *spi, void *buf, size_t len); Receive data----synchronous mode.
- int Spi_sync_transfer (struct spi_device *spi, struct spi_transfer *xfers, unsigned int num_xfers); ----synchronous mode, directly transmits several spi_transfer, receives and sends.
- int Spi_write_then_read (struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx); ----Write first and then read.
- ssize_t spi_w8r8 (struct spi_device *spi, U8 cmd); ----Write 8 bits, and then read 8 bits.
- ssize_t spi_w8r16 (struct spi_device *spi, U8 cmd); ----Write 8 bits, and then read 16 bits.
Linux SPI bus and device driver Architecture II: SPI Universal Interface Layer