Linux SPI Bus-SPI Universal Interface Layer

Posted by beefy23 on Sun, 02 Jan 2022 13:46:29 +0100

1. Introduction

As you can see from previous blogs, the SPI Universal Interface Layer is a middle layer, which provides a series of standard interface API s and standard data structures for protocol and controller drivers. So the SPI Universal Interface Layer is a core layer of the SPI bus.

The SPI Common Interface Layer code is focused on: /drivers/spi/spi.c.

2. SPI Universal Interface Layer Initialization

This section registers a bus type named SPI with the system, as well as a SPI controller named spi_master's device class.

struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_groups	= spi_dev_groups,
	.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)
{
	status = bus_register(&spi_bus_type);   // Generate sys/bus/spi
     ······
	status = class_register(&spi_master_class);   //Generate sys/class/spi_master
	return 0;
}
postcore_initcall(spi_init);

3. SPI Common Interface Layer provides external data structures and interfaces

3.1 SPI Controller

The SPI controller is responsible for exchanging data between the master and the SPI slave devices according to the set physical signal format. The SPI controller pays attention to how the data is transferred, not the content of the data. The SPI universal interface layer uses spi_ The master structure represents a SPI controller.

struct spi_master {
	struct device	dev;    //device structure corresponding to spi controller
	struct list_head list;  //The system may have multiple controllers linked to a global list variable
	s16 bus_num;            //The spi bus number corresponding to this controller, starting at 0, is usually set by board level code
	u16 num_chipselect;     //Number of chip selection signals connected to the spi controller
	u16 dma_alignment;
	u16 mode_bits;          //Work mode, driven to explain its meaning
	u32 min_speed_hz;       //Minimum working hours
	u32 max_speed_hz;       //Maximum working hours
	u16 flags;              //Flag bits for setting certain restrictions
	int (*setup)(struct spi_device *spi);    //Callback function to set the operating parameters of a spi slave device on this controller
    //Callback function that adds a mesg structure containing data information to the message chain table of the controller
	int (*transfer)(struct spi_device *spi, struct spi_message *mesg);
	void (*cleanup)(struct spi_device *spi);  //Callback function when spi_ When master is released, the function is called
	struct kthread_worker kworker;      //Work queue threads for managing data transfer message queues
	struct kthread_work pump_messages;  //Work queue threads that implement data transfer queues
	struct list_head queue;       //Message queues for this controller, under which all message queues waiting to be transmitted hang
	struct spi_message *cur_msg;  //Message queue currently being processed
	int (*prepare_transfer_hardware)(struct spi_master *master);  //Callback function, which is called before a formal transfer is initiated, to prepare hardware resources
   //Atomic transfer callback function for a single message, which is called once for each message in the queue to complete the transfer
	int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg);
	int (*unprepare_transfer_hardware)(struct spi_master *master);  //Clean Callback Function
	int *cs_gpios;   //gpio used for chip selection signal
}

Spi_ The master structure is typically populated by a controller driver and registered with the system through the following common interface layer API s:

int spi_register_master(struct spi_master *master);

3.2 SPI slave device

Spi_for SPI Universal Interface Layer The device structure represents a SPI slave device.

struct spi_device {
	struct device dev;            //The device structure representing the spi device
	struct spi_master *master;    //Point to the controller used by the spi device
	u32 max_speed_hz;     //Maximum operating clock frequency of the device
	u8 chip_select;       //Pick Pin Number Index in Controller
	u16 mode;             //Pick Pin Number Index in Controller
	u8 bits_per_word;     //The number of bits required per unit of data for the device
	int irq;              //irq number used by the device
	char modalias[SPI_NAME_SIZE];    //The name of the device used to pair the spi bus with the driver
	int cs_gpio;//The gpio number of the slice selection signal, usually not set by ourselves, is based on the chip_above Selectect field in spi_ Find and assign values in the master structure
}

Adding and registering an SPI slave device to the system requires 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 and spi_device structure, bus_ The num field is used to specify the controller number to which it belongs, via spi_board_info architecture, we can add SPI devices to the system in two ways. The first is to use the following API s provided by the Common Interface Layer after the SPI controller driver has been loaded:

struct spi_device *spi_new_device(struct spi_master *master, struct spi_board_info *chip);

The second way is to define a spi_in the board's initialization code Board_ Info array and register spi_through the following API s Board_ Info:

int spi_register_board_info(struct spi_board_info const *info, unsigned n);

* This API will put every spi_board_info hangs in global list variable board_list, and traverse the controllers already registered in the system, match the corresponding controllers, and get their spi_master structure pointer, which will eventually pass through spi_ New_ The device function adds a SPI device. Because spi_register_board_info can be called in the board's initialization code, maybe the controller driver has not been loaded at this time, and the corresponding spi_cannot be obtained at this time Master pointer, but don't worry, spi_will be called when the controller driver is loaded Register_ Master function to register spi_master structure, while spi_ Register_ The master function, in turn, traverses the global list board_ Spi_on list Board_ Info, then spi_ New_ The device function adds a SPI device.

3.3 SPI Driver from Device

Spi_for SPI Universal Interface Layer The driver structure represents a SPI slave device driver (or "SPI protocol driver").

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;
};

* id_ The table field is used to specify the device name that the driver can drive, and the bus matching function takes id_ Name and spi_specified in table The modalias field in the device structure is compared, and the match is successful, then spi_is triggered Driver's probe callback function is called to complete the initialization of the driver.

Common Interface Layer provides the following API s to complete spi_ Registration of driver:

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);
}

3.4 Data transfer between controller and slave device

spi_message contains a spi_transfer structure sequence, once the controller receives a spi_message, where spi_transfer should be sent in order and not by other spi_message interrupted, so we think spi_message is an atomic operation of SPI data exchange.

struct spi_message {
/* The list field transfers is used to link spi_suspended under this message Tranfer structure */    
        struct list_head        transfers;
        struct spi_device       *spi;
        unsigned                is_dma_mapped:1;
/* complete The callback function will display all spi_under this message Transfer is called when the transfer is complete to notify the protocol driver to process the received data and prepare the next batch of data to be sent */
        void                    (*complete)(void *context);
        void                    *context;
        unsigned                frame_length;
        unsigned                actual_length;
        int                     status;
/* The chain list field queue is used to hang this structure on spi_representing the controller On the queue field of the master structure, multiple spi_s can be added to the controller at the same time Message queuing */        
        struct list_head        queue;
        void                    *state;
};

struct spi_transfer {
        /* tx_buf And rx_buf provides data buffer address in non-dma mode */
        const void      *tx_buf;
        void            *rx_buf;
        unsigned        len;        //Length of data to be transmitted
        /* tx_dma And rx_dma provides buffer address in dma mode */
        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;
        /* transfer_list The list field is used to hang the transfer in a spi_message structure */
        struct list_head transfer_list;
};

The Common Interface Layer provides us with a series of spi_s for operation and maintenance Message and spi_ API function of transfer:

/* Initialize spi_message structure */
void spi_message_init(struct spi_message *m);

/* Put a spi_transfer joins/removes to a spi_ In message (note, just join, no transfer process started) */
void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m);
void spi_transfer_del(struct spi_transfer *t);

/* A combination of the above two API s to initialize a spi_message and add several spi_transfer structure */
void spi_message_init_with_transfers(struct spi_message *m, struct spi_transfer *xfers, unsigned int num_xfers);

/* Assign a self-contained number of spi_ Spi_of transfer structure Message */
struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags);

/* Initiate a spi_ Delivery of message, asynchronous version */
int spi_async(struct spi_device *spi, struct spi_message *message);
/* Initiate a spi_ Delivery of message, synchronization version */    
int spi_sync(struct spi_device *spi, struct spi_message *message);

With these API function interfaces, the protocol driver of a SPI device can complete the data exchange with a SPI slave device, because of the isolation of the common interface layer, the controller driver is transparent to the protocol driver, that is, the protocol driver only cares about the data that needs to be processed and exchanged. It doesn't matter how the controller transmits this data.

3.5 Summary

Summarize that the protocol-driven process for sending data is roughly the same:

Define a spi_message Structure;
use spi_message_init Function Initialization spi_message;
Define one or more spi_transfer Structure, initializes and prepares buffers for the data and assigns them to spi_transfer Corresponding fields ( tx_buf,rx_buf Etc.);
adopt spi_message_init Functions take these spi_transfer Hang spi_message Structurally;
If synchronization is used, call spi_sync(),If asynchronous, call spi_async();

In addition, the Common Interface Layer provides separate API s for some simple data transfers to complete the above combined processes:

/* Send data synchronously */
int spi_write(struct spi_device *spi, const void *buf, size_t len);

/* Receive data synchronously */
int spi_read(struct spi_device *spi, void *buf, size_t len);   

/* Synchronization, direct transfer of several spi_transfer, receive and send. */
int spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, unsigned int num_xfers);

/* Write before read */
int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx);

/* Write 8 bits, then read 8 bits */
ssize_t spi_w8r8(struct spi_device *spi, u8 cmd);

/* Write 8 bits and read 16 bits */
ssize_t spi_w8r16(struct spi_device *spi, u8 cmd);

4. Queuing SPI data transfer

Queuing means putting a message waiting for transmission in a waiting queue to initiate a transmission operation. In fact, putting the corresponding message in a waiting queue in order, the system will continuously detect whether there are messages waiting for transmission in the queue and, if there are, continuously schedule the data transfer kernel threads. Remove messages from the queue one by one and process them until the queue becomes empty.

Initialization of 4.1 queues and worker threads

Initialization of queued related fields and worker threads is done during the SPI controller registration process, spi_register_master.

int spi_register_master(struct spi_master *master)
{
    /* If we're using a queued driver, start the queue */
    /* If spi_master sets the transfer callback function field to indicate that the controller driver is not ready to use the queuing framework provided by the common interface layer */
	if (master->transfer)
		dev_info(dev, "master is unqueued, this is deprecated\n");
	else {
     /* Otherwise, spi_ Master_ Initialize_ The queue function will be called---> */
		status = spi_master_initialize_queue(master);
		if (status) {
			device_del(&master->dev);
			goto done;
		}
	}
}

static int spi_master_initialize_queue(struct spi_master *master)
{
	int ret;
   /* Set the master->transfer callback field to the default implementation function: spi_queued_transfer */
	master->transfer = spi_queued_transfer;
	if (!master->transfer_one_message)
   /* If the controller driver does not implement transfer_one_message callback with default spi_ Transfer_ One_ Assignment by message function */
		master->transfer_one_message = spi_transfer_one_message;

	/* Initialize and start queue Initialize queues and create worker threads---> */
	ret = spi_init_queue(master);
	master->queued = true;
   /* Start Work Thread---> */
	ret = spi_start_queue(master);

	return 0;
}

static int spi_init_queue(struct spi_master *master)
{
	struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };

	INIT_LIST_HEAD(&master->queue);
	spin_lock_init(&master->queue_lock);

	init_kthread_worker(&master->kworker);
	master->kworker_task = kthread_run(kthread_worker_fn,
					   &master->kworker,
					   dev_name(&master->dev));
	init_kthread_work(&master->pump_messages, spi_pump_messages);

	if (master->rt) {
		dev_info(&master->dev,
			"will run message pump with realtime priority\n");
		sched_setscheduler(master->kworker_task, SCHED_FIFO, &param);
	}

	return 0;
}

int kthread_worker_fn(void *worker_ptr)
{
	struct kthread_worker *worker = worker_ptr;
	struct kthread_work *work;

	worker->task = current;
	work = NULL;
   /* Determine the current worker's work_ Is the list empty, if not, then take it out and set it to worker->current_ Work, the current work */
	if (!list_empty(&worker->work_list)) {
		work = list_first_entry(&worker->work_list,
					struct kthread_work, node);
		list_del_init(&work->node);
	}
	worker->current_work = work;

	if (work) {
		__set_current_state(TASK_RUNNING);
		work->func(work);   //Execute the extracted work->func
	} else if (!freezing(current))
 /* If the worker's work_ If there is no task on the list, schedule(), the kthread_is called Worker_ FN execution thread goes to sleep */
		schedule();          
}

static int spi_start_queue(struct spi_master *master)
{
   ······
   /* Wake up master->kworker thread, that is, execute spi_pump_messages function */
	queue_kthread_work(&master->kworker, &master->pump_messages);
	return 0;
}

4.2 Working Mechanism of Queuing

When the protocol driver passes spi_ When async initiates a message request, the queuing and worker threads are activated, triggering some column operations, and finally completing the message transfer operation.

int spi_async(struct spi_device *spi, struct spi_message *message)
{
	struct spi_master *master = spi->master;
	int ret;

	if (master->bus_lock_flag)
		ret = -EBUSY;
	else
		ret = __spi_async(spi, message);

	return ret;
}

static int __spi_async(struct spi_device *spi, struct spi_message *message)
{
	struct spi_master *master = spi->master;

   /* In spi_ Master_ Initialize_ The transfer callback in queue () has been set as the default implementation function: spi_queued_transfer*/
	return master->transfer(spi, message);
 } 
 
static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{
	struct spi_master *master = spi->master;

	list_add_tail(&msg->queue, &master->queue);   /* Will spi_ Put message in spi_master's queue list */
	if (!master->busy)
           /* Wake up master->kworker thread, that is, execute spi_pump_messages function */
		queue_kthread_work(&master->kworker, &master->pump_messages);

	return 0;
}

static void spi_pump_messages(struct kthread_work *work)
{
	struct spi_master *master = container_of(work, struct spi_master, pump_messages);
	int ret;

   /* Remove the first spi_in the master->queue queue Message */ 
	master->cur_msg = list_first_entry(&master->queue, struct spi_message, queue);
	list_del_init(&master->cur_msg->queue);
	
   /* Call controller-driven prepare_transfer_hardware callback to allow the controller driver to prepare the necessary hardware resources */ 
	if (!was_busy && master->prepare_transfer_hardware) {
		ret = master->prepare_transfer_hardware(master);
		if (ret) {
			dev_err(&master->dev, "failed to prepare transfer hardware\n");

			return;
		}
	}

   /* Call controller-driven prepare_message handles messages as necessary */
	if (master->prepare_message) {
		ret = master->prepare_message(master, master->cur_msg);
		if (ret) {
			dev_err(&master->dev, "failed to prepare message: %d\n", ret);
			master->cur_msg->status = ret;
			spi_finalize_current_message(master);
			return;
		}
		master->cur_msg_prepared = true;
	}

   /* Call Controller Driven transfer_ One_ The message callback function completes the transfer of the message */
	ret = master->transfer_one_message(master, master->cur_msg);
}   

If you don't want to transfer by yourself One_ If message, you can use the default function in spi_master_initialize_queue() determines if transfer_is provided in the controller driver One_ Message, if not provided, the default function interface spi_transfer_one_message() is assigned to transfer_one_message.

static int spi_transfer_one_message(struct spi_master *master, struct spi_message *msg)
{
	struct spi_transfer *xfer;
	bool keep_cs = false;
	int ret = 0;
	int ms = 1;

	spi_set_cs(msg->spi, true);

	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
		trace_spi_transfer_start(msg, xfer);
		INIT_COMPLETION(master->xfer_completion);
            
           /* Callback function transfer_in controller driver One */ 
		ret = master->transfer_one(master, msg->spi, xfer);
		if (ret > 0) {
			ret = 0;
			ms = xfer->len * 8 * 1000 / xfer->speed_hz;
			ms += ms + 100; /* some tolerance */
			ms = wait_for_completion_timeout(&master->xfer_completion, msecs_to_jiffies(ms));
		}

		if (ms == 0) {
			dev_err(&msg->spi->dev, "SPI transfer timed out\n");
			msg->status = -ETIMEDOUT;
		}
		trace_spi_transfer_stop(msg, xfer);
		msg->actual_length += xfer->len;
	}
   /* Notify the Common Interface Layer to continue processing the next message in the queue */  
	spi_finalize_current_message(master);

	return ret;
}

In summary, in Controller Driver, spi_transfer_one_message and transfer_ The one callback function implements one of these.

Topics: Linux Driver