From: http://www.cnblogs.com/liugf05/archive/2012/12/03/2800457.html
There are two major modules below:
One is SPI bus-driven analysis (the specific implementation process is studied)
The other is the writing of the SPI bus driver (no need to study the specific implementation process)
SPI bus driver analysis
1 SPI Overview
SPI is short for serial peripheral interface. as its name implies, it is a serial peripheral device interface, which is first defined by Motorola on its mc68hcxx series processor. The SPI interface is mainly used between EEPROM, Flash, real-time clock, AD converter, digital signal processor, and digital signal decoder. SPI is a high-speed, full-duplex, synchronous communication bus, and occupies only four lines on the chip pins, saving the chip pins, at the same time, it saves space for PCB layout and provides convenience.
The communication principle of SPI is very simple. It works in the master-slave mode. In this mode, there is usually one master device and one or more slave devices, and four wires are required. In fact, three connections are allowed. It is also common to all SPI-based devices, including SDI (data input), SDO (data output), sclk (clock), and CS (chip selection ).
Mosi (SDO): The data output from the primary device.
Miso (SDI): data input from the master device and output from the device data.
Sclk: clock signal generated by the main device.
CS: enables signal from the device and is controlled by the main device.
Among them, CS is to control whether the chip is selected, that is to say, only when the chip selection signal is a pre-defined enable signal (high potential or low potential), the operation of this chip is effective, this allows connecting multiple SPI devices on the same bus. Note that in a specific application, when a SPI bus is connected to multiple devices, the Cs of the SPI itself may be replaced by other gpio ports, that is, the CS foot of each device is connected to different gpio on the processor end. Different gpio ports are operated to control the specific SPI device to be operated to reduce interference between each SPI device.
SPI is a serial communication protocol, that is, data is transmitted from MSB or LSB. This is why the sck clock line exists and the sck provides the clock pulse, miso and MoSi complete data transmission based on this pulse. SPI supports 4-32bits serial data transmission and MSB and LSB. You need to reset the size of the SPI master when the size of the device changes during each data transmission.
2 Overall Linux SPI driver architecture
In the 2.6 Linux kernel, the SPI driver architecture can be divided into three layers: the SPI core layer, the SPI controller driver layer, and the SPI device driver layer.
In Linux, the SPI driver code is located in the drivers/SPI directory.
2.1 SPI core layer
The SPI core layer is the core part of Linux SPI. It provides APIs for defining core data structures, registering SPI controller drivers and device drivers, and managing cancellation. It is an independent layer of the hardware platform. It shields the differences between physical bus controllers and defines unified access policies and interfaces. It provides unified interfaces, this allows the SPI device driver to send and receive data through the bus controller.
In Linux, the SPI core layer code is located in Driver/SPI. C. Since this layer is a platform-independent layer, this article will not describe it any more. If you are interested, please refer to the relevant materials.
2.2 SPI controller driver layer
SPI controller driver layer. Each processor platform has its own controller driver, which belongs to the platform porting layer. It is responsible for implementing the corresponding read/write methods for each SPI bus in the system. Physically, each SPI controller can connect several SPI slave devices.
When the system is started, the SPI controller driver is first loaded. A controller driver is used to support reading and writing a specific SPI bus. A controller driver can be described using the data structure struct spi_master.
In the include/liunx/SPI. h file, the data structure struct spi_master is defined as follows:
- Struct spi_master {
- Struct device dev;
- S16 bus_num;
- 2010num_chipselect;
- INT (* setup) (struct spi_device * SPI );
- INT (* Transfer) (struct spi_device * SPI, struct spi_message * mesg );
- Void (* cleanup) (struct spi_device * SPI );
- };
Bus_num is the SPI bus number corresponding to the Controller.
Number of slices supported by the num_chipselect controller, that is, the number of SPI devices supported
The setup function is the initialization function for setting the SPI bus mode and clock, and sets the SPI working clock and data transmission mode for the device. It is called in the spi_add_device function.
The transfer function is a function that implements the SPI bus read/write method. Achieve two-way data transmission and may sleep
CleanupCalled upon Cancellation
2.3 SPI device driver layer
The driver layer of the SPI device is the user interface layer, which provides interfaces for users to access specific devices through the SPI bus.
The driver layer of the SPI device can be described by two modules, struct spi_driver and struct spi_device.
The related data structure is as follows:
- Struct spi_driver {
- 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 driver serves the device. When the spi_driver is registered, It scans the device on the SPI bus to bind the driver to the device. The probe function is used to call the driver when matching the device. From the above structure comment, we can know that the SPI communication is through the message queue mechanism, rather than through the conversation with the slave device like I2C.
- Struct spi_device {
- Struct device dev;
- Struct spi_master * master;
- U32 max_speed_hz;
- U8 chip_select;
- U8 mode;
- U8 bits_per_word;
- Int IRQ;
- Void * controller_state;
- Void * controller_data;
- Char modalias [32];
- };
. Modalias = "m25p10 ",
. Mode = spi_mode_0, // cpol = 0, cpha = 0 select the specific data transmission mode.
. Max_speed_hz = 10000000, // maximum SPI clock frequency
/* Connected to SPI-0 as 1st slave */
. Bus_num = 0, // The device is connected to SPI controller 0
. Chip_select = 0, // The part selection line number. In the s5pc100 controller driver, it is not used as the basis for the part selection, but the method in controller_data below is selected.
. Controller_data = & smdk_spi0_csi [0],
Generally, spi_device corresponds to a specific slave on the SPI bus. In addition, spi_device encapsulates a spi_master struct. The spi_device struct contains private specific slave device features, including its maximum frequency, selected slice, and input/output modes.
3 omap3630 SPI Controller
On the omap3630, SPI is a Master/Slave Synchronous Serial Bus. There are four independent SPI modules (spi1, spi2, SPI3, and spi4 ), the difference between each module is that spi1 supports up to four SPI devices, spi2 and SPI3 support two SPI devices, and spi4 supports only one SPI device.
The SPI controller has the following features:
1. Programmable serial clock, including frequency, phase, polarity.
2. Supports 4-32-Bit Data Transmission
3. Support 4-channel or single-channel slave mode
4. Supports the main multi-channel mode
4.1 full/half duplex
4.2 only send/only receive/send and receive modes supported
4.3 flexible I/O port control
4.4 each channel supports DMA read/write
5. Support the interrupt time of multiple interrupt sources
6. Support for wake-up power management
7. built-in 64-byte FIFO
4. The following operations of spi_device are completed in the platform board file! The spi_device Board information is described by the struct structure: struct detail {charmodalias [spi_name_size]; const void * platform_data; void * controller_data; intirq; plates; u16bus_num; interval; u8mode ;};
This structure records the serial number, chip selection signal, data bit rate, and SPI transmission mode of the host controller used by the SPI peripherals.
The build procedure is as follows:
1.
Static struct spi_board_info initi_spi_devs [] _ initdata = {
{
. Modalias = "m25p10a ",
. Mode = spi_mode_0,
. Max_speed_hz = 1000000,
. Bus_num = 0,
. Chip_select = 0,
. Controller_data = & smdk_spi0_csi [smdk_mmcspi_cs],
},
};
2.
This info will be initialized when the init function is called:
Spi_register_board_info (cloud_spi_devs, array_size (cloud_spi_devs ));
Spi_register_board_info(Cloud_spi_devs, array_size (cloud_spi_devs); // register spi_board_info. This code registers spi_board_info to the linked list board_list. Spi_device encapsulates a spi_master struct. In fact, the registration of spi_master will call scan_boardinfo to scan board_list and find the SPI device attached to it after spi_register_board_info, then create and register the spi_device.
At this point, spi_device is built and registered !!!!!!!!!!!!!
5. Build and register spi_driver
Driver has several important structures: spi_driver, spi_transfer, and spi_message.
Driver has several important functions: spi_message_init, spi_message_add_tail, and spi_sync.
// Build spi_driver
Static struct spi_driver m25p80_driver = {
. Driver = {
. Name = "m25p80 ",
. Bus = & spi_bus_type,
. Owner = this_module,
},
. Probe = m25p_probe,
. Remove =__ devexit_p (m25p_remove ),
};
// Spidriver Registration
Spi_register_driver (& m25p80_driver );
When a matching spi_device exists, m25p_probe is called.
Probe is completeConstruction of spi_transfer and spi_message;
Spi_message_init, spi_message_add_tail, spi_sync,Spi_write_then_readFunction call
For example:
- */
- Static int m25p10a_read (struct m25p10a * flash, loff_t from,
- Size_t Len, char * BUF)
- {
- Int r_count = 0, I;
- Struct spi_transfer st [2];
- Struct spi_message MSG;
- Spi_message_init (& MSG );
- Memset (St, 0, sizeof (ST ));
- Flash-> cmd [0] = pai_read_bytes;
- Flash-> cmd [1] = from> 16;
- Flash-> cmd [2] = from> 8;
- Flash-> cmd [3] = from;
- St [0]. tx_buf = flash-> cmd;
- St [0]. Len = ipv_sz;
- Spi_message_add_tail (& St [0], & MSG );
- St [1]. rx_buf = Buf;
- St [1]. Len = Len;
- Spi_message_add_tail (& St [1], & MSG );
- Mutex_lock (& flash-> lock );
- /* Wait until finished previous write command .*/
- If (wait_till_ready (flash )){
- Mutex_unlock (& flash-> lock );
- Return-1;
- }
- Spi_sync (flash-> SPI, & MSG );
- R_count = msg. actual_length-ipv_sz;
- Printk ("in (% s): Read % d bytes \ n", _ FUNC __, r_count );
- For (I = 0; I <r_count; I ++ ){
- Printk ("0x % 02x \ n", Buf [I]);
- }
- Mutex_unlock (& flash-> lock );
- Return 0;
- }
- Static int m25p10a_write (struct m25p10a * flash, loff_t,
- Size_t Len, const char * BUF)
- {
- Int w_count = 0, I, page_offset;
- Struct spi_transfer st [2];
-
- Struct spi_message MSG;
- Write_enable (flash); // write enable
Spi_message_init (& MSG );
- Memset (St, 0, sizeof (ST ));
- Flash-> cmd [0] = pai_page_program;
- Flash-> cmd [1] = to> 16;
- Flash-> cmd [2] = to> 8;
- Flash-> cmd [3] =;
- St [0]. tx_buf = flash-> cmd;
- St [0]. Len = ipv_sz;
- // Fill in spi_transfer and put transfer behind the queue
- Spi_message_add_tail (& St [0], & MSG );
- St [1]. tx_buf = Buf;
- St [1]. Len = Len;
- Spi_message_add_tail (& St [1], & MSG );
-
- Spi_sync (flash->SPI, & MSG );Send by calling spi_masterSpi_message
- Return 0;
- }
- Static int m25p10a_probe (struct spi_device * SPI)
- {
- Int ret = 0;
- Struct m25p10a * flash;
- Char Buf [256];
- Flash = kzarloc (sizeof (struct m25p10a), gfp_kernel );
- Flash-> SPI = SPI;
- /* Save flash as driver's private data */
- Spi_set_drvdata (SPI, flash );
- Memset (BUF, 0x7,256 );
- M25p10a_write (flash, 0, 20, Buf); // write 20 7 addresses
- Memset (BUF, 0,256 );
- M25p10a_read (flash, 0, 25, Buf); // read 25 records from 0 addresses
-
- Return 0;
- }
So far, the SPI driver and application have been completed.