Through the first article, we already know that the whole SPI drive architecture can be divided into three parts: Protocol driver, common interface layer and controller driver. Among them, the controller driver is responsible for the lowest data receiving and dispatching work, in order to complete the data receiving and dispatching, the controller driver needs to complete the following functions:
1. Apply for the necessary hardware resources, such as interrupt, DMA channel, DMA memory buffer and so on;
2. Configure the working mode and parameters of SPI Controller, so that it can and the corresponding equipment for the correct data exchange work;
3. Provide interface to the common interface layer, so that the upper layer of the protocol driver can be driven by the Universal interface Layer Access controller;
4. With the common interface layer, complete the queue and processing of the data message queue until the message queue is empty;
/*****************************************************************************************************/
Statement: This Bo content by Http://blog.csdn.net/droidphone Original, reproduced please indicate the source, thank you.
/*****************************************************************************************************/
defining a controller device
The SPI controller follows the Linux device model framework, so an SPI controller corresponds to a device structure in the code, and for embedded systems, we usually treat the SPI controller as a platform device, so, for us, Just define a platform_device structure for the SPI controller in the board level code. Here's a sample of Samsung's SOC chip: s3c6410, to 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 (a),
},
};
Thus, in this platform_device, we define the register address, DMA channel resource, and IRQ number required by the controller, and the name of the device is defined as: S3C64XX-SPI, which is used for subsequent and corresponding controller drivers to match. In the machine initialization code, we need to register this platform device that represents the SPI controller, and also set the platform-related parameters via 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 Equipment
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 function is to specify the GPIO configuration that the controller uses, the number of slices of pins and the clock configuration. This information is used in the subsequent controller driver.
registering the platform_driver of the SPI Controller
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 comes 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 the S3c64xx_spi_init (), registered a platform driver, the driver's name is also: S3c64xx-spi, naturally, the platform bus will be it and the previous section defined platform _device match, and the triggering probe callback is invoked (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 appears that the Platform_device structure, which represents the SPI controller, is defined in the first section, but for the SPI generic interface layer, the spi_master structure is the representation of the controller, the description of the spi_master structure, See the second article: Linux SPI Bus and device-driven architecture bis: SPI common interface layer. We know that after the device and the driver match, the driver's probe callback function is invoked, and the probe callback function is exactly the right time to initialize the driver and 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
= Spi_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; . * * To the Common interface layer Register Spi_master structure/if (Spi_register_master (master)) {Dev_err (&pdev->
;d EV, "Cannot register SPI master\n");
ret =-ebusy;
Goto ERR3; }
......
}
The above function, in addition to complete 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 pass the Spi_register_ The master function completes the registration of the controller. We can also see from the code that several important callback functions in the Spi_master structure have been assigned, and these callback functions are invoked at the right time by the common interface layer to complete the data exchange between the controller and the device.
callback function to implement 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 common interface layer, the common interface layer will call these callback functions at the right time, here I just introduce the function of each callback function, For specific implementation examples, please read the examples of each platform in the code tree (code located at:/drivers/spi/). Int (*setup) (struct Spi_device *spi) invokes the Api:spi_setup () provided by the generic interface layer when the protocol driver wishes to modify the controller's working mode or parameters. The API function finally calls the setup callback function to complete the setup work. Int (*transfer) (struct spi_device *spi, struct spi_message)
At present, we can not implement the callback function, the initialization is directly set to NULL can be, the current universal interface layer has implemented Message Queuing, register spi_master, the common interface layer will provide a common function to achieve good. Now only some old drivers are still using this callback method, the new driver should stop using the callback function, but should use the queued Transfer_one_message callback. It should be noted that we can only choose one of the ways, set the Transfer_one_message callback, we can not set the transfer callback, and vice versa. void (*cleanup) (struct spi_device *spi)
When an SPI is freed from a device (Spi_device structure), the callback function is invoked to free the hardware resources that the 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 drive an opportunity for the controller before and after initiating a data transfer process, requesting or releasing some of the necessary hardware resources, such as DMA resources and memory resources, and so on. Int (*prepare_message) (struct spi_master *master, struct spi_message) Int (*unprepare_message) (struct spi_master *master, struct spi_message)
These two callback functions are also used to drive an opportunity for the controller before and after initiating a data transfer process, to perform the necessary preprocessing or reprocessing of the message, such as from the device where the message needs to be exchanged, setting the correct working clock, word length, and working mode of the controller. Int (*transfer_one_message) (struct spi_master *master, struct spi_message) when a common interface layer discovers that there is a message in the queue of master that needs to be transmitted, Call the callback function, so the function is a work function that really completes a message transfer, and when the transfer completes, the Spi_finalize_current_message function should be called to notify the common interface layer to initiate the transfer of the next message in the queue.