Through the first article, we already know that the whole SPI drive architecture can be divided into three parts: Protocol driver, general interface layer and controller driver. The controller driver is responsible for the data sending and receiving work at the lowest level, in order to complete the data sending and receiving work, the controller driver needs to complete the following functions:
1. Request the necessary hardware resources, such as interrupts, DMA channels, DMA memory buffers, etc.;
2. Configure the operating mode and parameters of the SPI controller so that the correct data exchange can be done with the corresponding equipment;
3. Provide the interface to the general interface layer, so that the upper layer protocol driver can access the controller driver through the Universal interface layer;
4. In conjunction with the common interface layer, complete the queue and processing of data Message Queuing until the message queue becomes empty;
/*****************************************************************************************************/
Statement: The content of this blog by Http://blog.csdn.net/droidphone Original, reproduced please indicate the source, thank you!
/*****************************************************************************************************/
Defining controller Devices
The SPI controller follows the Linux device model framework, so that an SPI controller corresponds to one device structure in the code, and for embedded systems we usually treat the SPI controller as a platform device, so, for us, Simply define a platform_device structure for the SPI controller in the board-level code. Here's an example of Samsung's SOC chip: s3c6410, and see how to define this platform_device. The following code is from:/ARCH/ARM/PLAT-SAMSUNG/DEVS.C:
static struct resource s3c64xx_spi0_resource[] = {[0] = Define_res_mem (S3c_pa_spi0, sz_256), [1] = DEFINE_RES_DMA (dmach_ SPI0_TX), [2] = DEFINE_RES_DMA (DMACH_SPI0_RX), [3] = DEFINE_RES_IRQ (irq_spi0),};struct platform_device S3c64xx_device_ Spi0 = {. Name= "S3c6410-spi",. id= 0,.num_resources= array_size (S3c64xx_spi0_resource),. resource= s3c64xx_spi0_ Resource,.dev = {. dma_mask= &samsung_device_dma_mask,.coherent_dma_mask= Dma_bit_mask (32),},};
Thus, in this platform_device, we define the register address, DMA channel resource, and IRQ number required for the controller, and the name of the device is defined as: S3C64XX-SPI, which is used to match subsequent and corresponding controller drivers. In machine initialization code, we need to register this platform device that represents the SPI controller, and in addition, the platform-related parameters are set by the S3c64xx_spi0_set_platdata function for subsequent controller-driven use:
static struct Platform_device *crag6410_devices[] __initdata = { ... &s3c64xx_device_spi0, ...}; static void __init Xxxx_machine_init (void) { s3c64xx_spi0_set_platdata (NULL, 0, 2); Register platform Device platform_add_devices (crag6410_devices, Array_size (crag6410_devices));}
The S3c64xx_spi0_set_platdata function is defined as follows:
void __init s3c64xx_spi0_set_platdata (int (*cfg_gpio) (void), int src_clk_nr,int num_cs) {struct s3c64xx_spi_info pd; ... pd.num_cs = NUM_CS;PD.SRC_CLK_NR = Src_clk_nr;pd.cfg_gpio = (cfg_gpio)? Cfg_gpio:s3c64xx_spi0_cfg_gpio; ... s3c_set_platdata (&PD, sizeof (PD), &s3c64xx_device_spi0);}
The above functions mainly specify the GPIO configuration used by the controller, the number of pin pins and the clock configuration. This information is to be used in the controller driver behind.
Register the SPI Controller Platform_driver
In the previous section, we registered the SPI controller as a platform_device, correspondingly, the corresponding driver should be a platform driver: platform_driver, they match each other through platform bus. The following code is from:/drivers/spi/spi-s3c64xx.c
static struct Platform_driver S3c64xx_spi_driver = { . Driver = { . Name = "S3c64xx-spi", . Owner = This_ MODULE, . PM = &s3c64xx_spi_pm, . of_match_table = Of_match_ptr (S3c64xx_spi_dt_match), }, . remove = S3c64xx_spi_remove, . id_table = S3c64xx_spi_driver_ids,}; Module_alias ("Platform:s3c64xx-spi"); static int __init s3c64xx_spi_init (void) { return Platform_driver_probe ( &s3c64xx_spi_driver, s3c64xx_spi_probe);} Subsys_initcall (S3c64xx_spi_init);
Obviously, the system initialization phase (Subsys_initcall phase), through S3c64xx_spi_init (), registered a platform driver, the name of the driver is exactly the same: S3c64xx-spi, naturally, the platform bus will put it and the previous section defined platform _device matches, and the trigger probe callback is called (that is, the S3c64xx_spi_probe function). Of course, the match here is done through the id_table field:
static struct platform_device_id s3c64xx_spi_driver_ids[] = { { . Name = "S3c2443-spi", . Driver_data = (kernel_ulong_t) &s3c2443_spi_port_config, }, { . Name = "S3c6410-spi", . Driver_data = (kernel_ulong_t) &s3c6410_spi_port_config, }, ... { },};
Register Spi_master
In the Linux device model, it is the platform_device structure defined in the first section that represents the SPI controller, but for the SPI general interface layer, the Spi_master structure representing the controller is the description of the spi_master structure, See the second article: Linux SPI Bus and device driver Architecture II: SPI Universal interface layer. We know that the driver's probe callback function is called when the device and driver match, and the probe callback is the right time to initialize the driver and the device, in this case the corresponding probe callback is: S3c64xx_spi_probe:
static int s3c64xx_spi_probe (struct platform_device *pdev) {.../* Assign a SPI_MASTER structure */master = SP I_alloc_master (&pdev->dev, sizeof (struct s3c64xx_spi_driver_data)); ... platform_set_drvdata (Pdev, master); ... master->dev.of_node = pdev->dev.of_node; Master->bus_num = sdd->port_id; Master->setup = S3c64xx_spi_setup; Master->cleanup = S3c64xx_spi_cleanup; Master->prepare_transfer_hardware = S3c64xx_spi_prepare_transfer; Master->transfer_one_message = S3c64xx_spi_transfer_one_message; Master->unprepare_transfer_hardware = S3c64xx_spi_unprepare_transfer; Master->num_chipselect = sci->num_cs; Master->dma_alignment = 8; Master->bits_per_word_mask = Spi_bpw_mask (32) | Spi_bpw_mask (16) | Spi_bpw_mask (8); /* The Spi->mode bits understood by this driveR: */master->mode_bits = Spi_cpol | Spi_cpha | Spi_cs_high; MASTER->AUTO_RUNTIME_PM = true; .../* Register the SPI_MASTER structure with the Universal interface layer */if (Spi_register_master (master)) {Dev_err (&pdev->de V, "Cannot register SPI master\n"); ret =-ebusy; Goto ERR3; } ......}
The above function, in addition to completing the necessary hardware resource initialization work, the most important task is to assign a spi_master structure through the Spi_alloc_master function, initialize the structure, and finally through the Spi_register_ The master function completes the registration work for the controller. As we can see from the code, several important callback functions in the Spi_master structure have been assigned, and these callback functions are called by the common interface layer at the right time to complete the data exchange between the controller and the device.
Implementing a callback function for the spi_master structure
In fact, the main work of the SPI Controller driver is to implement several callback functions in the spi_master structure, the other work logic is done by the general interface layer to help us, the general interface layer will call these callback functions at the appropriate time, here I just introduce the function of each callback function, For specific implementation examples, please read the example of each platform in the code tree (the code is at:/drivers/spi/).
Int (*setup) (struct Spi_device *spi) when the protocol driver wants to modify the controller's operating mode or parameters, it invokes the Api:spi_setup () provided by the Universal interface layer, which finally calls the setup callback function to complete the setup work. Int (*transfer) (struct spi_device *spi, struct spi_message *mesg)
At present, we can not implement the callback function ourselves, the initialization is directly set to NULL, the current general interface layer has implemented Message Queuing, when registering Spi_master, the General interface layer will provide the implementation of a good general function. Now only some old drivers are still using the callback, and the new driver should stop using the callback function, but should use the queued Transfer_one_message callback. It is important to note that we can only choose one of these methods, set the Transfer_one_message callback, we cannot set the transfer callback, and vice versa.
void (*cleanup) (struct Spi_device *spi)
When an SPI is freed from the device (Spi_device structure), the callback function is called to free the hardware resources that the slave device occupies.
Int (*prepare_transfer_hardware) (struct spi_master *master) int (*unprepare_transfer_hardware) (struct Spi_master * Master
These two callback functions are used to give the controller a chance to request or release some necessary hardware resources, such as DMA resources and memory resources, before and after initiating a data transfer process.
Int (*prepare_message) (struct spi_master *master, struct spi_message *message) int (*unprepare_message) (struct SPI_ Master *master, struct spi_message *message)
These two callback functions are also used before and after initiating a data transfer process, to give the controller a chance to perform the necessary preprocessing or post-processing of the message, for example, according to a message needs to exchange data from the device, set the correct working clock of the controller, Word length and operating mode.
Int (*transfer_one_message) (struct spi_master *master, struct spi_message *mesg) This callback function is called when the common interface layer discovers that a message in the queue of Master is required to be transmitted. So the function is to actually complete a message delivery function, when the transfer work is complete, you should call the Spi_finalize_current_message function to notify the Universal interface layer, initiating the delivery of the next message in the queue.
Linux SPI bus and device driver Architecture III: SPI Controller driver